From 1f183d688a8621ec638c851e710fc9ae99928835 Mon Sep 17 00:00:00 2001
From: Gav <gavin@parity.io>
Date: Mon, 8 Jan 2018 17:13:44 +0100
Subject: [PATCH] Introduce basic skeleton for Polkador runtime.

---
 substrate/executor/src/wasm_executor.rs |  28 ++-
 substrate/runtime/polkadot/src/lib.rs   | 222 ++++++++++++++++++++++--
 substrate/runtime/support/src/lib.rs    |  87 ++++------
 substrate/runtime/test/src/lib.rs       |  53 +++++-
 4 files changed, 308 insertions(+), 82 deletions(-)

diff --git a/substrate/executor/src/wasm_executor.rs b/substrate/executor/src/wasm_executor.rs
index f52b2cbf715..4c3ed5b7916 100644
--- a/substrate/executor/src/wasm_executor.rs
+++ b/substrate/executor/src/wasm_executor.rs
@@ -76,7 +76,7 @@ impl WritePrimitive<u32> for MemoryInstance {
 }
 
 impl_function_executor!(this: FunctionExecutor<'e, E>,
-	ext_print(utf8_data: *const u8, utf8_len: i32) => {
+	ext_print(utf8_data: *const u8, utf8_len: u32) => {
 		if let Ok(utf8) = this.memory.get(utf8_data, utf8_len as usize) {
 			if let Ok(message) = String::from_utf8(utf8) {
 				println!("Runtime: {}", message);
@@ -96,7 +96,7 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
 		println!("memmove {} from {}, {} bytes", dest, src, count);
 		dest
 	},
-	ext_memset(dest: *mut u8, val: i32, count: usize) -> *mut u8 => {
+	ext_memset(dest: *mut u8, val: u32, count: usize) -> *mut u8 => {
 		let _ = this.memory.clear(dest as usize, val as u8, count as usize);
 		println!("memset {} with {}, {} bytes", dest, val, count);
 		dest
@@ -110,12 +110,12 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
 		this.heap.deallocate(addr);
 		println!("free {}", addr)
 	},
-	ext_set_storage(key_data: *const u8, key_len: i32, value_data: *const u8, value_len: i32) => {
+	ext_set_storage(key_data: *const u8, key_len: u32, value_data: *const u8, value_len: u32) => {
 		if let (Ok(key), Ok(value)) = (this.memory.get(key_data, key_len as usize), this.memory.get(value_data, value_len as usize)) {
 			this.ext.set_storage(key, value);
 		}
 	},
-	ext_get_allocated_storage(key_data: *const u8, key_len: i32, written_out: *mut i32) -> *mut u8 => {
+	ext_get_allocated_storage(key_data: *const u8, key_len: u32, written_out: *mut u32) -> *mut u8 => {
 		let (offset, written) = if let Ok(key) = this.memory.get(key_data, key_len as usize) {
 			if let Ok(value) = this.ext.storage(&key) {
 				let offset = this.heap.allocate(value.len() as u32) as u32;
@@ -126,6 +126,18 @@ impl_function_executor!(this: FunctionExecutor<'e, E>,
 
 		this.memory.write_primitive(written_out, written);
 		offset as u32
+	},
+	ext_get_storage_into(key_data: *const u8, key_len: u32, value_data: *mut u8, value_len: u32) -> u32 => {
+		if let Ok(key) = this.memory.get(key_data, key_len as usize) {
+			if let Ok(value) = this.ext.storage(&key) {
+				let written = ::std::cmp::min(value_len as usize, value.len());
+				let _ = this.memory.set(value_data, &value[0..written]);
+				written as u32
+			} else { 0 }
+		} else { 0 }
+	},
+	ext_deposit_log(_log_data: *const u8, _log_len: u32) {
+		unimplemented!()
 	}
 	=> <'e, E: Externalities + 'e>
 );
@@ -163,8 +175,8 @@ impl CodeExecutor for WasmExecutor {
 		let returned = program
 				.params_with_external("env", &mut fec)
 				.map(|p| p
-					.add_argument(I32(offset as i32))
-					.add_argument(I32(size as i32)))
+					.add_argument(I32(offset as u32))
+					.add_argument(I32(size as u32)))
 			.and_then(|p| module.execute_export(method, p))
 			.map_err(|_| -> Error { ErrorKind::Runtime.into() })?;
 
@@ -221,8 +233,8 @@ mod tests {
 			let returned = program
 					.params_with_external("env", &mut fec)
 					.map(|p| p
-						.add_argument(I32(offset as i32))
-						.add_argument(I32(size as i32)))
+						.add_argument(I32(offset as u32))
+						.add_argument(I32(size as u32)))
 				.and_then(|p| module.execute_export("test_data_in", p))
 				.map_err(|_| -> Error { ErrorKind::Runtime.into() }).expect("function should be callable");
 
diff --git a/substrate/runtime/polkadot/src/lib.rs b/substrate/runtime/polkadot/src/lib.rs
index ec3fabb89cd..da82db8fa2c 100644
--- a/substrate/runtime/polkadot/src/lib.rs
+++ b/substrate/runtime/polkadot/src/lib.rs
@@ -8,29 +8,215 @@ use alloc::vec::Vec;
 
 #[macro_use]
 extern crate runtime_support;
-use runtime_support::{set_storage, code, set_code, storage, validators, set_validators, print};
+use runtime_support::{set_storage, storage, storage_into, print, Value20};
 
-impl_stub!(test_data_in);
-fn test_data_in(input: Vec<u8>) -> Vec<u8> {
-	print(b"set_storage" as &[u8]);
-	set_storage(b"input", &input);
+/// The hash of an ECDSA pub key which is used to identify an external transactor.
+type AccountID = [u8; 32];
+/// The ECDSA pub key of an authority. This is what the external environment/consensus algorithm
+/// refers to as a "authority".
+type SessionKey = [u8; 65];
+type Balance = u64;
+type ChainID = u64;
+type Hash = [u8; 32];
+type BlockNumber = u64;
+/// A proportion (rational number).
+struct Proportion { nom: u64, denom: u64, };
+type Timestamp = u64;
+type TxOrder = u64;
+/// Statistics concerning consensus.
+// TODO.
+struct Statistics;
+/// A report of bad behaviour.
+// TODO.
+struct Complaint;
 
-	print(b"code" as &[u8]);
-	set_storage(b"code", &code());
+/// The state of a parachain.
+/*struct ParachainState {
+	head_data: Vec<u8>,
+	balance: Balance,
+	user_balances: HashMap<AccountID, Balance>,
+	balance_downloads: HashMap<AccountID, ( Balance, Vec<u8> ),
+	egress_roots: Vec<Hash>
+}*/
+//struct CandidateReceipt;
 
-	print(b"set_code" as &[u8]);
-	set_code(&input);
+// TODO: include RLP implementation
+// TODO: add keccak256 (or some better hashing scheme) & ECDSA-recover (or some better sig scheme)
 
-	print(b"storage" as &[u8]);
-	let copy = storage(b"input");
+impl_stub!(execute_block);
+fn execute_block(_input: Vec<u8>) -> Vec<u8> {
+	// TODO: decode block and ensure valid
+	// TODO: iterate through transactions amd decode/dispatch them
+	// TODO: progress to next session if it's time
+	// TODO: progress to next era if it's time
+	Vec::new()
+}
+
+impl_stub!(execute_transaction);
+fn execute_transaction(tx: Vec<u8>) -> Vec<u8> {
+	environment::execute_transaction(&tx)
+}
+
+/// The current relay chain identifier.
+fn chain_id() -> ChainID { unimplemented!() }	// TODO: retrieve from external
+
+mod environment {
+	/// The current block number being processed. Set by `execute_block`.
+	pub fn block_number() -> BlockNumber { unimplemented!() }
+
+	/// Get the block hash of a given block.
+	pub fn block_hash(_number: BlockNumber) -> Hash { unimplemented!() }
+
+	/// ?
+	fn set_digest(_preserialised_rlp_digest: &[u8]) { unimplemented!() }
+
+	/// Get the current user's ID
+	pub fn current_user() -> AccountID { unimplemented!() }
+
+	/// Execute a given transaction.
+	pub fn execute_transaction(_tx: &[u8]) -> Vec<u8> {
+		// TODO: decode data and ensure valid
+		// TODO: ensure signature valid and recover id
+		// TODO: ensure target_function valid
+		// TODO: decode parameters
+		// TODO: make call
+		// TODO: encode any return
+		Vec::new()
+	}
+
+	/// Set the new code.
+	pub fn set_code(new: &[u8]) {
+		set_storage(b"\0code", new)
+	}
+
+	/// ?
+	fn set_active_parachains(_data: &[u8]) { unimplemented!() }
+}
+
+mod consensus {
+	fn value_vec(mut value: usize, initial: Vec<u8>) -> Vec<u8> {
+		let mut acc = initial;
+		while value > 0 {
+			acc.push(value as u8);
+			value /= 256;
+		}
+		acc
+	}
+
+	fn set_authority(index: usize, authority: AccountID) {
+		set_storage(&value_vec(index, b"\0authority".to_vec()), &authority[..]);
+	}
+
+	fn authority(index: usize) -> AccountID {
+		storage_into::<Value20>(&value_vec(index, b"\0authority".to_vec()))
+	}
+
+	fn set_authority_count(count: usize) {
+		(count..authority_count()).for_each(|i| set_authority(i, &[]));
+		set_storage(b"\0authority_count", &value_vec(count, Vec::new()));
+	}
+
+	fn authority_count() -> usize {
+		storage(b"\0authority_count").into_iter().rev().fold(0, |acc, i| (acc << 8) + (i as usize))
+	}
+
+	/// Get the current set of authorities. These are the session keys.
+	pub fn authorities() -> Vec<AccountID> {
+		(0..authority_count()).into_iter().map(authority).map.collect()
+	}
 
-	print(b"validators" as &[u8]);
-	let mut v = validators();
-	v.push(copy);
+	/// Set the current set of authorities' session keys.
+	///
+	/// Called by `next_session` only.
+	fn set_authorities(authorities: &[AccountID]) {
+		set_authority_count(authorities.len());
+		authorities.iter().enumerate().for_each(|(v, i)| set_authority(v, i));
+	}
 
-	print(b"set_validators" as &[u8]);
-	set_validators(&v.iter().map(Vec::as_slice).collect::<Vec<_>>());
+	/// Get the current set of validators. These are the long-term identifiers for the validators
+	/// and will be mapped to a session key with the most recent `set_next_session_key`.
+	pub fn validators() -> Vec<AccountID> {
+		unimplemented!()
+	}
 
-	print(b"finished!" as &[u8]);
-	b"all ok!".to_vec()
+	/// Set the current set of validators.
+	///
+	/// Called by staking::next_era() only.
+	pub fn set_validators(_new: &[AccountID]) {
+		unimplemented!()
+	}
+
+	/// Flush out any statistics.
+	pub fn flush_statistics() -> Statistics { unimplemented!() }
+
+	/// Sets the session key of `_validator` to `_session`. This doesn't take effect until the next
+	/// session.
+	pub fn set_session_key(_validator: AccountID, _session: AccountID) {
+		unimplemented!()
+	}
+
+	/// Move onto next session: register the new authority set.
+	pub fn next_session() {
+		// TODO: Call set_authorities().
+		unimplemented!()
+	}
+}
+
+mod staking {
+	/// The length of a staking era in blocks.
+	fn era_length() -> BlockNumber { unimplemented!() }
+
+	/// The era has changed - enact new staking set.
+	///
+	/// NOTE: This is always a session change.
+	fn next_era() { unimplemented!() }
+
+	/// The balance of a given account.
+	fn balance(_who: AccountID) -> Balance { unimplemented!() }
+
+	/// User-level function to move funds onto a parachain. Calls `parachains::credit_parachain`.
+	fn move_to_parachain(chain_id: ChainID, value: Balance) { unimplemented!() }
+
+	/// System-level function to be called only by Parachains object when funds have left that
+	/// object and are to be credited here.
+	fn credit_staker(value: Balance) { unimplemented!() }
+
+	/// Declare the desire to stake under the requirement that under flawless operation, each era
+	/// should return `minimum_era_return` on the amount staked.
+	///
+	/// Effects will be felt at the beginning of the next era.
+	fn stake(minimum_era_return: Proportion) { unimplemented!() }
+
+	/// Retract the desire to stake.
+	///
+	/// Effects will be felt at the beginning of the next era.
+	fn unstake() { unimplemented!() }
+
+	/// Report invalid behaviour by a staking participant.
+	fn complain(complaint: Complaint) { unimplemented!() }
+}
+
+/*
+mod parachains {
+	fn chain_ids(self) -> [ ChainID ];
+	fn validation_function(self, chain_id: ChainID) -> Fn(consolidated_ingress: [ ( ChainID, bytes ) ], balance_downloads: [ ( AccountID, Balance ) ], block_data: bytes, previous_head_data: bytes) -> (head_data: bytes, egress_queues: [ [ bytes ] ], balance_uploads: [ ( AccountID, Balance ) ]);
+	fn validate_and_calculate_fees_function(self, chain_id: ChainID) -> Fn(egress_queues: [ [ bytes ] ], balance_uploads: [ ( AccountID, Balance ) ]) -> Balance;
+	fn balance(self, chain_id: ChainID, id: AccountID) -> Balance;
+	fn verify_and_consolidate_queues(self, unprocessed_ingress: [ [ [ bytes ] ] ]) -> [ (chain_id: ChainID, message: bytes) ];
+	fn chain_state(self, chain_id: ChainID) -> ParachainState;
+	fn move_to_staking(mut self, chain_id: ChainID, value: Balance);
+	fn credit_parachain(mut self, chain_id: ChainID, value: Balance);
+	fn download(mut self, chain_id: ChainID, value: Balance, instruction: bytes);
+	fn update_heads(mut self, candidate_receipts: &[ ( ChainID, CandidateReceipt ) ]);
+}
+
+mod authentication {
+	fn validate_signature(self, tx: Transaction) -> ( AccountID, TxOrder );
+	fn nonce(self, id: AccountID) -> TxOrder;
+	fn authenticate(mut self, tx: Transaction) -> AccountID;
+}
+*/
+mod timestamp {
+	fn timestamp() -> Timestamp { unimplemented!() }
+	fn set_timestamp(Timestamp) { unimplemented!() }
 }
diff --git a/substrate/runtime/support/src/lib.rs b/substrate/runtime/support/src/lib.rs
index 472497d2845..4430f7249fa 100644
--- a/substrate/runtime/support/src/lib.rs
+++ b/substrate/runtime/support/src/lib.rs
@@ -17,70 +17,57 @@ pub fn panic_fmt() -> ! {
 }
 
 extern "C" {
-	fn ext_print(utf8_data: *const u8, utf8_len: i32);
+	fn ext_print(utf8_data: *const u8, utf8_len: u32);
 	fn ext_print_num(value: u64);
-	fn ext_set_storage(key_data: *const u8, key_len: i32, value_data: *const u8, value_len: i32);
-	fn ext_get_allocated_storage(key_data: *const u8, key_len: i32, written_out: *mut i32) -> *mut u8;
+	fn ext_set_storage(key_data: *const u8, key_len: u32, value_data: *const u8, value_len: u32);
+	fn ext_get_allocated_storage(key_data: *const u8, key_len: u32, written_out: *mut u32) -> *mut u8;
+	fn ext_get_storage_into(key_data: *const u8, key_len: u32, value_data: *mut u8, value_len: u32) -> u32;
+	fn ext_deposit_log(log_data: *const u8, log_len: u32);
 }
 
 pub fn storage(key: &[u8]) -> Vec<u8> {
-	let mut length: i32 = 0;
+	let mut length: u32 = 0;
 	unsafe {
-		let ptr = ext_get_allocated_storage(&key[0], key.len() as i32, &mut length);
+		let ptr = ext_get_allocated_storage(&key[0], key.len() as u32, &mut length);
 		Vec::from_raw_parts(ptr, length as usize, length as usize)
 	}
 }
 
-pub fn set_storage(key: &[u8], value: &[u8]) {
-	unsafe {
-		ext_set_storage(
-			&key[0] as *const u8, key.len() as i32,
-			&value[0] as *const u8, value.len() as i32
-		);
-	}
-}
-
-pub fn code() -> Vec<u8> {
-	storage(b"\0code")
+pub trait IsValue {
+	const value: usize;
 }
 
-pub fn set_code(new: &[u8]) {
-	set_storage(b"\0code", new)
-}
+pub struct Value20; impl IsValue for Value20 { const value = 20usize; }
+pub struct Value32; impl IsValue for Value32 { const value = 32usize; }
+pub struct Value64; impl IsValue for Value64 { const value = 64usize; }
+pub struct Value65; impl IsValue for Value65 { const value = 65usize; }
 
-fn value_vec(mut value: usize, initial: Vec<u8>) -> Vec<u8> {
-	let mut acc = initial;
-	while value > 0 {
-		acc.push(value as u8);
-		value /= 256;
+pub fn storage_into<T: IsValue>(key: &[u8]) -> Option<[u8; T::value]> {
+	let mut result = [0u8; T::value];
+	let written = unsafe {
+		ext_get_storage_into(&key[0], key.len() as u32, &result[0], result.len())
+	};
+	match written {
+		T::value => Some(result),
+		_ => None,
 	}
-	acc
-}
-
-pub fn set_validator(index: usize, validator: &[u8]) {
-	set_storage(&value_vec(index, b"\0validator".to_vec()), validator);
-}
-
-pub fn validator(index: usize) -> Vec<u8> {
-	storage(&value_vec(index, b"\0validator".to_vec()))
 }
 
-pub fn set_validator_count(count: usize) {
-	(count..validator_count()).for_each(|i| set_validator(i, &[]));
-	set_storage(b"\0validator_count", &value_vec(count, Vec::new()));
-}
-
-pub fn validator_count() -> usize {
-	storage(b"\0validator_count").into_iter().rev().fold(0, |acc, i| (acc << 8) + (i as usize))
-}
-
-pub fn validators() -> Vec<Vec<u8>> {
-	(0..validator_count()).into_iter().map(validator).collect()
+pub fn set_storage(key: &[u8], value: &[u8]) {
+	unsafe {
+		ext_set_storage(
+			&key[0] as *const u8, key.len() as u32,
+			&value[0] as *const u8, value.len() as u32
+		);
+	}
 }
 
-pub fn set_validators(validators: &[&[u8]]) {
-	set_validator_count(validators.len());
-	validators.iter().enumerate().for_each(|(v, i)| set_validator(v, i));
+pub fn deposit_log(log: &[u8]) {
+	unsafe {
+		ext_deposit_log(
+			&log[0] as *const u8, log.len() as u32,
+		)
+	}
 }
 
 pub trait Printable {
@@ -90,7 +77,7 @@ pub trait Printable {
 impl<'a> Printable for &'a [u8] {
 	fn print(self) {
 		unsafe {
-			ext_print(&self[0] as *const u8, self.len() as i32);
+			ext_print(&self[0] as *const u8, self.len() as u32);
 		}
 	}
 }
@@ -109,12 +96,10 @@ pub fn print<T: Printable + Sized>(value: T) {
 macro_rules! impl_stub {
 	($name:ident) => {
 		pub mod _internal {
-			extern crate alloc;
-			
 			#[no_mangle]
 			pub fn $name(input_data: *mut u8, input_len: usize) -> u64 {
 				let input = unsafe {
-					::alloc::vec::Vec::from_raw_parts(input_data, input_len, input_len)
+					super::alloc::vec::Vec::from_raw_parts(input_data, input_len, input_len)
 				};
 
 				let output = super::$name(input);
diff --git a/substrate/runtime/test/src/lib.rs b/substrate/runtime/test/src/lib.rs
index ec3fabb89cd..550e06c05dd 100644
--- a/substrate/runtime/test/src/lib.rs
+++ b/substrate/runtime/test/src/lib.rs
@@ -8,7 +8,50 @@ use alloc::vec::Vec;
 
 #[macro_use]
 extern crate runtime_support;
-use runtime_support::{set_storage, code, set_code, storage, validators, set_validators, print};
+use runtime_support::{set_storage, storage, print};
+
+pub fn code() -> Vec<u8> {
+	storage(b"\0code")
+}
+
+pub fn set_code(new: &[u8]) {
+	set_storage(b"\0code", new)
+}
+
+fn value_vec(mut value: usize, initial: Vec<u8>) -> Vec<u8> {
+	let mut acc = initial;
+	while value > 0 {
+		acc.push(value as u8);
+		value /= 256;
+	}
+	acc
+}
+
+pub fn set_authority(index: usize, authority: &[u8]) {
+	set_storage(&value_vec(index, b"\0authority".to_vec()), authority);
+}
+
+pub fn authority(index: usize) -> Vec<u8> {
+	storage(&value_vec(index, b"\0authority".to_vec()))
+}
+
+pub fn set_authority_count(count: usize) {
+	(count..authority_count()).for_each(|i| set_authority(i, &[]));
+	set_storage(b"\0authority_count", &value_vec(count, Vec::new()));
+}
+
+pub fn authority_count() -> usize {
+	storage(b"\0authority_count").into_iter().rev().fold(0, |acc, i| (acc << 8) + (i as usize))
+}
+
+pub fn authorities() -> Vec<Vec<u8>> {
+	(0..authority_count()).into_iter().map(authority).collect()
+}
+
+pub fn set_authorities(authorities: &[&[u8]]) {
+	set_authority_count(authorities.len());
+	authorities.iter().enumerate().for_each(|(v, i)| set_authority(v, i));
+}
 
 impl_stub!(test_data_in);
 fn test_data_in(input: Vec<u8>) -> Vec<u8> {
@@ -24,12 +67,12 @@ fn test_data_in(input: Vec<u8>) -> Vec<u8> {
 	print(b"storage" as &[u8]);
 	let copy = storage(b"input");
 
-	print(b"validators" as &[u8]);
-	let mut v = validators();
+	print(b"authorities" as &[u8]);
+	let mut v = authorities();
 	v.push(copy);
 
-	print(b"set_validators" as &[u8]);
-	set_validators(&v.iter().map(Vec::as_slice).collect::<Vec<_>>());
+	print(b"set_authorities" as &[u8]);
+	set_authorities(&v.iter().map(Vec::as_slice).collect::<Vec<_>>());
 
 	print(b"finished!" as &[u8]);
 	b"all ok!".to_vec()
-- 
GitLab