From 88d66681f62d45af86e1a9f92850943ecc6402a7 Mon Sep 17 00:00:00 2001 From: Gav Date: Tue, 9 Jan 2018 15:05:41 +0100 Subject: [PATCH] More fleshing out on runtime. --- substrate/wasm-runtime/polkadot/src/lib.rs | 93 ++++++++++-------- substrate/wasm-runtime/support/src/lib.rs | 11 ++- .../lib-runtime_polkadot | 2 +- .../lib-runtime_polkadot.json | 2 +- .../lib-runtime_support-5482fb51bf4d410e | 2 +- .../lib-runtime_support-5482fb51bf4d410e.json | 2 +- .../lib-runtime_test | 2 +- .../lib-runtime_test.json | 2 +- .../libruntime_support-5482fb51bf4d410e.rlib | Bin 12778 -> 13160 bytes .../release/libpwasm_alloc.d | 2 +- .../release/libruntime_support.d | 2 +- .../release/libruntime_support.rlib | Bin 12778 -> 13160 bytes .../release/runtime_polkadot.d | 2 +- .../release/runtime_test.d | 2 +- 14 files changed, 68 insertions(+), 56 deletions(-) diff --git a/substrate/wasm-runtime/polkadot/src/lib.rs b/substrate/wasm-runtime/polkadot/src/lib.rs index 24529d4380..fb8e5b86f8 100644 --- a/substrate/wasm-runtime/polkadot/src/lib.rs +++ b/substrate/wasm-runtime/polkadot/src/lib.rs @@ -3,7 +3,8 @@ #[macro_use] extern crate runtime_support; -use runtime_support::{set_storage, storage, storage_into, Vec}; +use runtime_support::{set_storage, storage, storage_into, Vec, size_of}; +use runtime_support::{Rc, RefCell, transmute, Box}; /// The hash of an ECDSA pub key which is used to identify an external transactor. pub type AccountID = [u8; 32]; @@ -19,20 +20,36 @@ pub type TxOrder = u64; /// The functions that a transaction can call (and be dispatched to). pub enum Function { - StakingStake(), - StakingUnstake(), - ConsensusSetSessionKey(SessionKey), + StakingStake, + StakingUnstake, + ConsensusSetSessionKey, } impl Function { /// Dispatch the function. - pub fn dispatch(self) -> Vec { unimplemented!() } + pub fn dispatch(&self, transactor: &AccountID, params: &[u8]) { + match *self { + Function::StakingStake => { + staking::stake(transactor); + } + Function::StakingUnstake => { + staking::unstake(transactor); + } + Function::ConsensusSetSessionKey => { + let mut session = AccountID::default(); + session.copy_from_slice(¶ms[0..size_of::()]); + consensus::set_session_key(transactor, session); + } + } + } } +#[derive(Clone)] pub struct Digest { pub logs: Vec>, } +#[derive(Clone)] pub struct Header { pub parent_hash: Hash, pub number: BlockNumber, @@ -42,7 +59,7 @@ pub struct Header { } pub struct Transaction { - pub senders: Vec, + pub signed: AccountID, pub function: Function, pub input_data: Vec, pub nonce: TxOrder, @@ -71,42 +88,28 @@ impl Block { } } -/* -use std::sync::{rc, RefCell, Once, ONCE_INIT}; -use std::mem; - #[derive(Default)] struct Environment { - header: Option
, - current_user: Option, + block_number: BlockNumber, } -#[derive(Clone)] -struct EnvironmentHolder { - inner: Rc>, -} - -fn get_environment() -> EnvironmentHolder { +fn env() -> Rc> { // Initialize it to a null value - static mut SINGLETON: *const EnvironmentHolder = 0 as *const EnvironmentHolder; - static ONCE: Once = ONCE_INIT; + static mut SINGLETON: *const Rc> = 0 as *const Rc>; unsafe { - ONCE.call_once(|| { + if SINGLETON == 0 as *const Rc> { // Make it - let singleton = EnvironmentHolder { - inner: Rc::new(RefCell::new(Default::default())), - }; + let singleton: Rc> = Rc::new(RefCell::new(Default::default())); // Put it in the heap so it can outlive this call - SINGLETON = mem::transmute(Box::new(singleton)); - }); + SINGLETON = transmute(Box::new(singleton)); + } // Now we give out a copy of the data that is safe to use concurrently. (*SINGLETON).clone() } } -*/ // TODO: include RLP implementation // TODO: add keccak256 (or some better hashing scheme) & ECDSA-recover (or some better sig scheme) @@ -133,20 +136,26 @@ mod environment { use super::*; /// The current block number being processed. Set by `execute_block`. - pub fn block_number() -> BlockNumber { unimplemented!() } + pub fn block_number() -> BlockNumber { let e = env(); let eb = e.borrow(); eb.block_number } /// Get the block hash of a given block. pub fn block_hash(_number: BlockNumber) -> Hash { unimplemented!() } - /// Get the current user's ID - pub fn current_user() -> AccountID { unimplemented!() } - pub fn execute_block(_block: &Block) -> Vec { - // TODO: populate environment from header. + // populate environment from header. + { + let e = env(); + e.borrow_mut().block_number = _block.header.number; + } + staking::pre_transactions(); + // TODO: go through each transaction and use execute_transaction to execute. + staking::post_transactions(); + // TODO: ensure digest in header is what we expect from transactions. + Vec::new() } @@ -156,9 +165,9 @@ mod environment { // TODO: ensure signature valid and recover id (use authentication::authenticate) // TODO: ensure target_function valid // TODO: decode parameters - // TODO: set `current_user` to the id - // TODO: make call - // TODO: reset `current_user` + + _tx.function.dispatch(&_tx.signed, &_tx.input_data); + // TODO: encode any return Vec::new() } @@ -235,9 +244,9 @@ mod consensus { 10 } - /// Sets the session key of `_validator` to `_session`. This doesn't take effect until the next + /// Sets the session key of `_transactor` to `_session`. This doesn't take effect until the next /// session. - pub fn set_session_key(_validator: AccountID, _session: AccountID) { + pub fn set_session_key(_transactor: &AccountID, _session: AccountID) { unimplemented!() } @@ -274,17 +283,17 @@ mod staking { fn balance(_who: AccountID) -> Balance { unimplemented!() } /// Transfer some unlocked staking balance to another staker. - fn transfer_stake(_who: AccountID, _dest: AccountID, _value: Balance) { unimplemented!() } + pub fn transfer_stake(_transactor: AccountID, _dest: AccountID, _value: Balance) { unimplemented!() } - /// Declare the desire to stake. + /// Declare the desire to stake for the transactor. /// /// Effects will be felt at the beginning of the next era. - fn stake() { unimplemented!() } + pub fn stake(_transactor: &AccountID) { unimplemented!() } - /// Retract the desire to stake. + /// Retract the desire to stake for the transactor. /// /// Effects will be felt at the beginning of the next era. - fn unstake() { unimplemented!() } + pub fn unstake(_transactor: &AccountID) { unimplemented!() } /// Hook to be called prior to transaction processing. pub fn pre_transactions() { diff --git a/substrate/wasm-runtime/support/src/lib.rs b/substrate/wasm-runtime/support/src/lib.rs index aaab93e960..3acad5237e 100644 --- a/substrate/wasm-runtime/support/src/lib.rs +++ b/substrate/wasm-runtime/support/src/lib.rs @@ -7,7 +7,10 @@ //#[macro_use] extern crate alloc; pub use alloc::vec::Vec; -use core::mem; +pub use alloc::boxed::Box; +pub use alloc::rc::Rc; +pub use core::mem::{transmute, size_of, uninitialized}; +pub use core::cell::{RefCell, Ref, RefMut}; extern crate pwasm_libc; extern crate pwasm_alloc; @@ -37,11 +40,11 @@ pub fn storage(key: &[u8]) -> Vec { pub fn storage_into(key: &[u8]) -> Option { let mut result: T; - let size = mem::size_of::(); + let size = size_of::(); let written; unsafe { - result = mem::uninitialized(); - let result_as_byte_blob = mem::transmute::<*mut T, *mut u8>(&mut result); + result = uninitialized(); + let result_as_byte_blob = transmute::<*mut T, *mut u8>(&mut result); written = ext_get_storage_into(&key[0], key.len() as u32, result_as_byte_blob, size as u32) as usize; } // Only return a fully written value. diff --git a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-polkadot-1e4c8740d04ba868/lib-runtime_polkadot b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-polkadot-1e4c8740d04ba868/lib-runtime_polkadot index 3e7282f285..77c1ca3667 100644 --- a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-polkadot-1e4c8740d04ba868/lib-runtime_polkadot +++ b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-polkadot-1e4c8740d04ba868/lib-runtime_polkadot @@ -1 +1 @@ -d4940d6f62cf958e \ No newline at end of file +6eee55b59b574864 \ No newline at end of file diff --git a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-polkadot-1e4c8740d04ba868/lib-runtime_polkadot.json b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-polkadot-1e4c8740d04ba868/lib-runtime_polkadot.json index ae6a4a3c0f..39174c4da4 100644 --- a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-polkadot-1e4c8740d04ba868/lib-runtime_polkadot.json +++ b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-polkadot-1e4c8740d04ba868/lib-runtime_polkadot.json @@ -1 +1 @@ -{"rustc":8294656847287967537,"features":"[\"default\", \"without-std\"]","target":15371597068611496627,"profile":42358739494345872,"deps":[["runtime-support v0.1.0 (file:///Users/gav/Core/polkadot/wasm-runtime/support)",2223771509741189442]],"local":[{"MtimeBased":[[1515501953,507863132],"/Users/gav/Core/polkadot/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-polkadot-1e4c8740d04ba868/dep-lib-runtime_polkadot"]}],"rustflags":[]} \ No newline at end of file +{"rustc":8294656847287967537,"features":"[\"default\", \"without-std\"]","target":15371597068611496627,"profile":42358739494345872,"deps":[["runtime-support v0.1.0 (file:///Users/gav/Core/polkadot/wasm-runtime/support)",18014962227880213226]],"local":[{"MtimeBased":[[1515506687,785085370],"/Users/gav/Core/polkadot/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-polkadot-1e4c8740d04ba868/dep-lib-runtime_polkadot"]}],"rustflags":[]} \ No newline at end of file diff --git a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-support-5482fb51bf4d410e/lib-runtime_support-5482fb51bf4d410e b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-support-5482fb51bf4d410e/lib-runtime_support-5482fb51bf4d410e index c062c60974..7d69f92972 100644 --- a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-support-5482fb51bf4d410e/lib-runtime_support-5482fb51bf4d410e +++ b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-support-5482fb51bf4d410e/lib-runtime_support-5482fb51bf4d410e @@ -1 +1 @@ -42f9c1f3676cdc1e \ No newline at end of file +ea3ae1eab20002fa \ No newline at end of file diff --git a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-support-5482fb51bf4d410e/lib-runtime_support-5482fb51bf4d410e.json b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-support-5482fb51bf4d410e/lib-runtime_support-5482fb51bf4d410e.json index 497c7e5b56..1e4859a996 100644 --- a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-support-5482fb51bf4d410e/lib-runtime_support-5482fb51bf4d410e.json +++ b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-support-5482fb51bf4d410e/lib-runtime_support-5482fb51bf4d410e.json @@ -1 +1 @@ -{"rustc":8294656847287967537,"features":"[]","target":14982045766639954252,"profile":42358739494345872,"deps":[["pwasm-alloc v0.1.0 (file:///Users/gav/Core/polkadot/wasm-runtime/pwasm-alloc)",1843871105590971886],["pwasm-libc v0.1.0 (file:///Users/gav/Core/polkadot/wasm-runtime/pwasm-libc)",6197225601014249845]],"local":[{"MtimeBased":[[1515500954,752149165],"/Users/gav/Core/polkadot/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-support-5482fb51bf4d410e/dep-lib-runtime_support-5482fb51bf4d410e"]}],"rustflags":[]} \ No newline at end of file +{"rustc":8294656847287967537,"features":"[]","target":14982045766639954252,"profile":42358739494345872,"deps":[["pwasm-alloc v0.1.0 (file:///Users/gav/Core/polkadot/wasm-runtime/pwasm-alloc)",1843871105590971886],["pwasm-libc v0.1.0 (file:///Users/gav/Core/polkadot/wasm-runtime/pwasm-libc)",6197225601014249845]],"local":[{"MtimeBased":[[1515504344,57881737],"/Users/gav/Core/polkadot/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-support-5482fb51bf4d410e/dep-lib-runtime_support-5482fb51bf4d410e"]}],"rustflags":[]} \ No newline at end of file diff --git a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-test-0ee9f37942e84b82/lib-runtime_test b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-test-0ee9f37942e84b82/lib-runtime_test index dc062b33e3..fb66643a92 100644 --- a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-test-0ee9f37942e84b82/lib-runtime_test +++ b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-test-0ee9f37942e84b82/lib-runtime_test @@ -1 +1 @@ -9cf830998a9aef5e \ No newline at end of file +0caae204cc6f3f45 \ No newline at end of file diff --git a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-test-0ee9f37942e84b82/lib-runtime_test.json b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-test-0ee9f37942e84b82/lib-runtime_test.json index 6040d1fe18..1003d6c5db 100644 --- a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-test-0ee9f37942e84b82/lib-runtime_test.json +++ b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-test-0ee9f37942e84b82/lib-runtime_test.json @@ -1 +1 @@ -{"rustc":8294656847287967537,"features":"[]","target":11385551307513482501,"profile":42358739494345872,"deps":[["runtime-support v0.1.0 (file:///Users/gav/Core/polkadot/wasm-runtime/support)",2223771509741189442]],"local":[{"MtimeBased":[[1515500955,389693545],"/Users/gav/Core/polkadot/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-test-0ee9f37942e84b82/dep-lib-runtime_test"]}],"rustflags":[]} \ No newline at end of file +{"rustc":8294656847287967537,"features":"[]","target":11385551307513482501,"profile":42358739494345872,"deps":[["runtime-support v0.1.0 (file:///Users/gav/Core/polkadot/wasm-runtime/support)",18014962227880213226]],"local":[{"MtimeBased":[[1515504344,719487568],"/Users/gav/Core/polkadot/wasm-runtime/target/wasm32-unknown-unknown/release/.fingerprint/runtime-test-0ee9f37942e84b82/dep-lib-runtime_test"]}],"rustflags":[]} \ No newline at end of file diff --git a/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/deps/libruntime_support-5482fb51bf4d410e.rlib b/substrate/wasm-runtime/target/wasm32-unknown-unknown/release/deps/libruntime_support-5482fb51bf4d410e.rlib index 2e0626d0708f1edb9ac3677db1439b816a1e3eb1..c74a5505236b2abd831d543c288f99ad02138b74 100644 GIT binary patch delta 6273 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 delta 5976 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 delta 5976 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