diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 4f4a414d7a222ede157c6175b686da8538b74730..dd81690e5f2d40dc6ef90328c8a1ea8a5a8e2540 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -333,6 +333,18 @@ dependencies = [ "tiny-keccak 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ethbloom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fixed-hash 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ethcore-bigint" version = "0.2.1" @@ -460,6 +472,28 @@ dependencies = [ "uint 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ethereum-types" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ethbloom 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fixed-hash 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "uint 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ethereum-types-serialize" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ethkey" version = "0.3.0" @@ -1091,6 +1125,7 @@ dependencies = [ "polkadot-collator 0.1.0", "polkadot-primitives 0.1.0", "polkadot-statement-table 0.1.0", + "polkadot-transaction-pool 0.1.0", "substrate-bft 0.1.0", "substrate-codec 0.1.0", "substrate-primitives 0.1.0", @@ -1152,6 +1187,20 @@ dependencies = [ "substrate-primitives 0.1.0", ] +[[package]] +name = "polkadot-transaction-pool" +version = "0.1.0" +dependencies = [ + "ed25519 0.1.0", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "polkadot-api 0.1.0", + "polkadot-primitives 0.1.0", + "substrate-codec 0.1.0", + "substrate-primitives 0.1.0", + "transaction-pool 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "polkadot-validator" version = "0.1.0" @@ -1439,6 +1488,11 @@ name = "smallvec" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "smallvec" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "smallvec" version = "0.6.0" @@ -1825,6 +1879,17 @@ name = "traitobject" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "transaction-pool" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "triehash" version = "0.1.0" @@ -2044,6 +2109,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" "checksum eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)" = "<none>" "checksum ethbloom 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5f7fb5d27fb017f21c15d1e0b953831b58581c9942a5e5614fd2b6603697b7" +"checksum ethbloom 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f240172b976e2421fa5485e45cd45287bbdb56d742aa3a1d77005c49071a8518" "checksum ethcore-bigint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcb5af77e74a8f70e9c3337e069c37bc82178ef1b459c02091f73c4ad5281eb5" "checksum ethcore-bytes 0.1.0 (git+https://github.com/paritytech/parity.git)" = "<none>" "checksum ethcore-bytes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3977c772cd6c5c22e1c7cfa208e4c3b746bd6c3a6c8eeec0999a6b2103015ad5" @@ -2053,6 +2119,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum ethcore-network 1.9.0 (git+https://github.com/paritytech/parity.git)" = "<none>" "checksum ethcrypto 0.1.0 (git+https://github.com/paritytech/parity.git)" = "<none>" "checksum ethereum-types 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2adaa5b8ceafcce0bc3a68ef116ca5702958cc97d70a6eb008aeddb569b092b3" +"checksum ethereum-types 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5cff74129deda8a155b729cad1a22dc3cdd08115abd1165079c519d0cab6917a" +"checksum ethereum-types-serialize 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ac59a21a9ce98e188f3dace9eb67a6c4a3c67ec7fbc7218cb827852679dc002" "checksum ethkey 0.3.0 (git+https://github.com/paritytech/parity.git)" = "<none>" "checksum fixed-hash 0.1.3 (git+https://github.com/rphmeier/primitives.git?branch=compile-for-wasm)" = "<none>" "checksum fixed-hash 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21c520ebc46522d519aec9cba2b7115d49cea707d771b772c46bec61aa0daeb8" @@ -2150,6 +2218,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" "checksum slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdeff4cd9ecff59ec7e3744cbca73dfe5ac35c2aedb2cfba8a1c715a18912e9d" "checksum smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8cbcd6df1e117c2210e13ab5109635ad68a929fcbb8964dc965b76cb5ee013" +"checksum smallvec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ee4f357e8cd37bf8822e1b964e96fd39e2cb5a0424f8aaa284ccaccc2162411c" "checksum smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44db0ecb22921ef790d17ae13a3f6d15784183ff5f2a01aa32098c7498d2b4b9" "checksum snappy 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "<none>" "checksum snappy-sys 0.1.0 (git+https://github.com/paritytech/rust-snappy)" = "<none>" @@ -2170,6 +2239,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" "checksum tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6131e780037787ff1b3f8aad9da83bca02438b72277850dd6ad0d455e0e20efc" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" +"checksum transaction-pool 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23303835df389f9c34ad45cacf392304193f974faaf48c30a4ece2b03da0ed57" "checksum triehash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9291c7f0fae44858b5e087dd462afb382354120003778f1695b44aab98c7abd7" "checksum twox-hash 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "475352206e7a290c5fccc27624a163e8d0d115f7bb60ca18a64fc9ce056d7435" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml index e56f0ddcd135f37dd49cd65d25b641fd2e0df077..635370e2dfcb8be558134b90d6243fa85ea81c4b 100644 --- a/substrate/Cargo.toml +++ b/substrate/Cargo.toml @@ -21,6 +21,7 @@ members = [ "polkadot/primitives", "polkadot/runtime", "polkadot/statement-table", + "polkadot/transaction-pool", "polkadot/validator", "substrate/bft", "substrate/client", diff --git a/substrate/demo/runtime/src/lib.rs b/substrate/demo/runtime/src/lib.rs index f42d16016a4d07cb04662c0e2c0a0e5412fbcf04..110061ee7c4c5080be992ce93cbbd528ef112c30 100644 --- a/substrate/demo/runtime/src/lib.rs +++ b/substrate/demo/runtime/src/lib.rs @@ -18,7 +18,7 @@ #![cfg_attr(not(feature = "std"), no_std)] -extern crate substrate_runtime_std as rstd; +#[macro_use] extern crate substrate_runtime_std as rstd; #[macro_use] extern crate substrate_runtime_io as runtime_io; extern crate substrate_runtime_support as runtime_support; #[cfg(all(feature = "std", test))] extern crate substrate_keyring as keyring; diff --git a/substrate/demo/runtime/wasm/Cargo.lock b/substrate/demo/runtime/wasm/Cargo.lock index 245ae29a7ac6aaed2cb1573d7dc53f66082cdd35..a415dd58eb92f6e8aed7d52d1a9544bdf4bd9e4a 100644 --- a/substrate/demo/runtime/wasm/Cargo.lock +++ b/substrate/demo/runtime/wasm/Cargo.lock @@ -104,6 +104,7 @@ name = "demo-runtime" version = "0.1.0" dependencies = [ "demo-primitives 0.1.0", + "integer-sqrt 0.1.0 (git+https://github.com/paritytech/integer-sqrt-rs.git)", "substrate-codec 0.1.0", "substrate-primitives 0.1.0", "substrate-runtime-io 0.1.0", @@ -243,6 +244,11 @@ dependencies = [ "proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "integer-sqrt" +version = "0.1.0" +source = "git+https://github.com/paritytech/integer-sqrt-rs.git#f4cf61482096dc98c1273f46a10849d182b4c23c" + [[package]] name = "isatty" version = "0.1.6" @@ -830,6 +836,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461" "checksum hex-literal 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd546ef520ab3745f1aae5f2cdc6de9e6498e94d1ab138b9eb3ddfbf335847fb" "checksum hex-literal-impl 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2ea76da4c7f1a54d01d54985566d3fdd960b2bbd7b970da024821c883c2d9631" +"checksum integer-sqrt 0.1.0 (git+https://github.com/paritytech/integer-sqrt-rs.git)" = "<none>" "checksum isatty 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f2a233726c7bb76995cec749d59582e5664823b7245d4970354408f1d79a7a2" "checksum keccak-hash 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f300c1f149cd9ca5214eed24f6e713a597517420fb8b15499824aa916259ec1" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" diff --git a/substrate/demo/runtime/wasm/Cargo.toml b/substrate/demo/runtime/wasm/Cargo.toml index 04d8999e275d7c12a814aaf09f790c5cfe97a5b5..436c482015cba32e5d7c1d0303e7a47412b5dae7 100644 --- a/substrate/demo/runtime/wasm/Cargo.toml +++ b/substrate/demo/runtime/wasm/Cargo.toml @@ -13,7 +13,7 @@ substrate-runtime-io = { path = "../../../substrate/runtime-io", default-feature substrate-runtime-support = { path = "../../../substrate/runtime-support", default-features = false } substrate-primitives = { path = "../../../substrate/primitives", default-features = false } demo-primitives = { path = "../../primitives", default-features = false } -integer-sqrt = "0.1.0" +integer-sqrt = { git = "https://github.com/paritytech/integer-sqrt-rs.git", branch = "master" } [features] default = [] diff --git a/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm b/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm index 437bbeb5de2b9a6c42b58d75b9b4b6041d749fdd..f542540c93e1ab432c2fed89067e577220d80c48 100644 Binary files a/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm and b/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm differ diff --git a/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm b/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm index 98838fcf5013dd87ef37bfad8d0df2ff81071c9f..8ecf2b7224ed72d40b1bee2ca4d924177a099644 100644 Binary files a/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm and b/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm differ diff --git a/substrate/polkadot/api/src/lib.rs b/substrate/polkadot/api/src/lib.rs index 0ffb55233acfed6b6ffcf51fd2519ca650081218..2eeb0cd06d0d3f365c546dd392e53ba54117dbdc 100644 --- a/substrate/polkadot/api/src/lib.rs +++ b/substrate/polkadot/api/src/lib.rs @@ -36,7 +36,7 @@ use polkadot_runtime::runtime; use polkadot_executor::Executor as LocalDispatch; use substrate_executor::{NativeExecutionDispatch, NativeExecutor}; use state_machine::OverlayedChanges; -use primitives::{AccountId, SessionKey, Timestamp}; +use primitives::{AccountId, SessionKey, Timestamp, TxOrder}; use primitives::block::{Id as BlockId, Block, Header, Body}; use primitives::transaction::UncheckedTransaction; use primitives::parachain::DutyRoster; @@ -85,6 +85,7 @@ impl From<client::error::Error> for Error { } } +/// A builder for blocks. pub trait BlockBuilder: Sized { /// Push a non-inherent transaction. fn push_transaction(&mut self, transaction: UncheckedTransaction) -> Result<()>; @@ -93,40 +94,64 @@ pub trait BlockBuilder: Sized { fn bake(self) -> Block; } +/// A checked block identifier. +pub trait CheckedBlockId: Clone { + /// Yield the underlying block ID. + fn block_id(&self) -> &BlockId; +} + /// Trait encapsulating the Polkadot API. /// /// All calls should fail when the exact runtime is unknown. pub trait PolkadotApi { + /// A checked block ID. Used to avoid redundancy of code check. + type CheckedBlockId: CheckedBlockId; + /// The type used to build blocks. type BlockBuilder: BlockBuilder; + /// Check whether requests at the given block ID can be served. + /// + /// It should not be possible to instantiate this type without going + /// through this function. + fn check_id(&self, id: BlockId) -> Result<Self::CheckedBlockId>; + /// Get session keys at a given block. - fn session_keys(&self, at: &BlockId) -> Result<Vec<SessionKey>>; + fn session_keys(&self, at: &Self::CheckedBlockId) -> Result<Vec<SessionKey>>; /// Get validators at a given block. - fn validators(&self, at: &BlockId) -> Result<Vec<AccountId>>; + fn validators(&self, at: &Self::CheckedBlockId) -> Result<Vec<AccountId>>; /// Get the authority duty roster at a block. - fn duty_roster(&self, at: &BlockId) -> Result<DutyRoster>; + fn duty_roster(&self, at: &Self::CheckedBlockId) -> Result<DutyRoster>; /// Get the timestamp registered at a block. - fn timestamp(&self, at: &BlockId) -> Result<Timestamp>; + fn timestamp(&self, at: &Self::CheckedBlockId) -> Result<Timestamp>; + + /// Get the nonce of an account at a block. + fn nonce(&self, at: &Self::CheckedBlockId, account: AccountId) -> Result<TxOrder>; + /// Evaluate a block and see if it gives an error. - fn evaluate_block(&self, at: &BlockId, block: Block) -> Result<()>; + fn evaluate_block(&self, at: &Self::CheckedBlockId, block: Block) -> Result<()>; /// Create a block builder on top of the parent block. - fn build_block(&self, parent: &BlockId, timestamp: u64) -> Result<Self::BlockBuilder>; + fn build_block(&self, parent: &Self::CheckedBlockId, timestamp: u64) -> Result<Self::BlockBuilder>; +} + +/// A checked block ID used for the substrate-client implementation of CheckedBlockId; +#[derive(Debug, Clone, Copy)] +pub struct CheckedId(BlockId); + +impl CheckedBlockId for CheckedId { + fn block_id(&self) -> &BlockId { + &self.0 + } } // set up the necessary scaffolding to execute the runtime. macro_rules! with_runtime { ($client: ident, $at: expr, $exec: expr) => {{ - // bail if the code is not the same as the natively linked. - if $client.code_at($at)? != LocalDispatch::native_equivalent() { - bail!(ErrorKind::UnknownRuntime); - } - - $client.state_at($at).map_err(Error::from).and_then(|state| { + $client.state_at($at.block_id()).map_err(Error::from).and_then(|state| { let mut changes = Default::default(); let mut ext = state_machine::Ext { overlay: &mut changes, @@ -141,33 +166,44 @@ macro_rules! with_runtime { impl<B: Backend> PolkadotApi for Client<B, NativeExecutor<LocalDispatch>> where ::client::error::Error: From<<<B as Backend>::State as state_machine::backend::Backend>::Error> { + type CheckedBlockId = CheckedId; type BlockBuilder = ClientBlockBuilder<B::State>; - fn session_keys(&self, at: &BlockId) -> Result<Vec<SessionKey>> { + fn check_id(&self, id: BlockId) -> Result<CheckedId> { + // bail if the code is not the same as the natively linked. + if self.code_at(&id)? != LocalDispatch::native_equivalent() { + bail!(ErrorKind::UnknownRuntime); + } + + Ok(CheckedId(id)) + } + + fn session_keys(&self, at: &CheckedId) -> Result<Vec<SessionKey>> { with_runtime!(self, at, ::runtime::consensus::authorities) } - fn validators(&self, at: &BlockId) -> Result<Vec<AccountId>> { + fn validators(&self, at: &CheckedId) -> Result<Vec<AccountId>> { with_runtime!(self, at, ::runtime::session::validators) } - fn duty_roster(&self, at: &BlockId) -> Result<DutyRoster> { + fn duty_roster(&self, at: &CheckedId) -> Result<DutyRoster> { with_runtime!(self, at, ::runtime::parachains::calculate_duty_roster) } - fn timestamp(&self, at: &BlockId) -> Result<Timestamp> { + fn timestamp(&self, at: &CheckedId) -> Result<Timestamp> { with_runtime!(self, at, ::runtime::timestamp::get) } - fn evaluate_block(&self, at: &BlockId, block: Block) -> Result<()> { + fn evaluate_block(&self, at: &CheckedId, block: Block) -> Result<()> { with_runtime!(self, at, || ::runtime::system::internal::execute_block(block)) } - fn build_block(&self, parent: &BlockId, timestamp: Timestamp) -> Result<Self::BlockBuilder> { - if self.code_at(parent)? != LocalDispatch::native_equivalent() { - bail!(ErrorKind::UnknownRuntime); - } + fn nonce(&self, at: &Self::CheckedBlockId, account: AccountId) -> Result<TxOrder> { + with_runtime!(self, at, || ::runtime::system::nonce(account)) + } + fn build_block(&self, parent: &CheckedId, timestamp: Timestamp) -> Result<Self::BlockBuilder> { + let parent = parent.block_id(); let header = Header { parent_hash: self.block_hash_from_id(parent)?.ok_or(ErrorKind::UnknownBlock(*parent))?, number: self.block_number_from_id(parent)?.ok_or(ErrorKind::UnknownBlock(*parent))? + 1, @@ -316,23 +352,24 @@ mod tests { #[test] fn gets_session_and_validator_keys() { let client = client(); - assert_eq!(client.session_keys(&BlockId::Number(0)).unwrap(), validators()); - assert_eq!(client.validators(&BlockId::Number(0)).unwrap(), validators()); + let id = client.check_id(BlockId::Number(0)).unwrap(); + assert_eq!(client.session_keys(&id).unwrap(), validators()); + assert_eq!(client.validators(&id).unwrap(), validators()); } #[test] fn build_block() { let client = client(); - let block_builder = client.build_block(&BlockId::Number(0), 1_000_000).unwrap(); + let id = client.check_id(BlockId::Number(0)).unwrap(); + let block_builder = client.build_block(&id, 1_000_000).unwrap(); let block = block_builder.bake(); assert_eq!(block.header.number, 1); } #[test] - fn cannot_build_block_on_unknown_parent() { - let client = client(); - assert!(client.build_block(&BlockId::Number(100), 1_000_000).is_err()); + fn fails_to_check_id_for_unknown_block() { + assert!(client().check_id(BlockId::Number(100)).is_err()); } } diff --git a/substrate/polkadot/consensus/Cargo.toml b/substrate/polkadot/consensus/Cargo.toml index 298d6478700eebae3808823df46b0559719d49bc..60c8009b7c9d5652afe89b0dfbe49341b0fe9746 100644 --- a/substrate/polkadot/consensus/Cargo.toml +++ b/substrate/polkadot/consensus/Cargo.toml @@ -13,6 +13,7 @@ polkadot-api = { path = "../api" } polkadot-collator = { path = "../collator" } polkadot-primitives = { path = "../primitives" } polkadot-statement-table = { path = "../statement-table" } +polkadot-transaction-pool = { path = "../transaction-pool" } substrate-bft = { path = "../../substrate/bft" } substrate-codec = { path = "../../substrate/codec" } substrate-primitives = { path = "../../substrate/primitives" } diff --git a/substrate/polkadot/consensus/src/error.rs b/substrate/polkadot/consensus/src/error.rs index 648072ef0b7b38b98e0768004446ecde5920302c..4d1387d17e1d4e0a14e84c30a5df0fe10ded7355 100644 --- a/substrate/polkadot/consensus/src/error.rs +++ b/substrate/polkadot/consensus/src/error.rs @@ -41,6 +41,13 @@ error_chain! { description("Proposal had wrong parent hash."), display("Proposal had wrong parent hash. Expected {:?}, got {:?}", expected, got), } + ProposalTooLarge(size: usize) { + description("Proposal exceeded the maximum size."), + display( + "Proposal exceeded the maximum size of {} by {} bytes.", + ::MAX_TRANSACTIONS_SIZE, ::MAX_TRANSACTIONS_SIZE.saturating_sub(*size) + ), + } } } diff --git a/substrate/polkadot/consensus/src/lib.rs b/substrate/polkadot/consensus/src/lib.rs index ef00318209757d96bc67193337952f6f7f541e4b..7321948dd773432f2fe09d24c1f9577d5d685290 100644 --- a/substrate/polkadot/consensus/src/lib.rs +++ b/substrate/polkadot/consensus/src/lib.rs @@ -37,6 +37,7 @@ extern crate polkadot_api; extern crate polkadot_collator as collator; extern crate polkadot_statement_table as table; extern crate polkadot_primitives; +extern crate polkadot_transaction_pool as transaction_pool; extern crate substrate_bft as bft; extern crate substrate_codec as codec; extern crate substrate_primitives as primitives; @@ -56,6 +57,7 @@ use polkadot_primitives::block::Block as PolkadotBlock; use polkadot_primitives::parachain::{Id as ParaId, DutyRoster, BlockData, Extrinsic, CandidateReceipt}; use primitives::block::{Block as SubstrateBlock, Header as SubstrateHeader, HeaderHash, Id as BlockId}; use primitives::AuthorityId; +use transaction_pool::TransactionPool; use futures::prelude::*; use futures::future; @@ -65,6 +67,9 @@ pub use self::error::{ErrorKind, Error}; mod error; +// block size limit. +const MAX_TRANSACTIONS_SIZE: usize = 4 * 1024 * 1024; + /// A handle to a statement table router. pub trait TableRouter { /// Errors when fetching data from the network. @@ -455,6 +460,8 @@ fn make_group_info(roster: DutyRoster, authorities: &[AuthorityId]) -> Result<Ha pub struct ProposerFactory<C, N> { /// The client instance. pub client: Arc<C>, + /// The transaction pool. + pub transaction_pool: Arc<Mutex<TransactionPool>>, /// The backing network handle. pub network: N, } @@ -465,7 +472,9 @@ impl<C: PolkadotApi, N: Network> bft::ProposerFactory for ProposerFactory<C, N> fn init(&self, parent_header: &SubstrateHeader, authorities: &[AuthorityId], sign_with: Arc<ed25519::Pair>) -> Result<Self::Proposer, Error> { let parent_hash = parent_header.hash(); - let duty_roster = self.client.duty_roster(&BlockId::Hash(parent_hash))?; + + let checked_id = self.client.check_id(BlockId::Hash(parent_hash))?; + let duty_roster = self.client.duty_roster(&checked_id)?; let group_info = make_group_info(duty_roster, authorities)?; let table = Arc::new(SharedTable::new(group_info, sign_with, parent_hash)); @@ -474,9 +483,11 @@ impl<C: PolkadotApi, N: Network> bft::ProposerFactory for ProposerFactory<C, N> // TODO [PoC-2]: kick off collation process. Ok(Proposer { parent_hash, + parent_id: checked_id, _table: table, _router: router, client: self.client.clone(), + transaction_pool: self.transaction_pool.clone(), }) } } @@ -490,9 +501,11 @@ fn current_timestamp() -> Timestamp { } /// The Polkadot proposer logic. -pub struct Proposer<C, R> { +pub struct Proposer<C: PolkadotApi, R> { parent_hash: HeaderHash, + parent_id: C::CheckedBlockId, client: Arc<C>, + transaction_pool: Arc<Mutex<TransactionPool>>, _table: Arc<SharedTable>, _router: R, } @@ -503,14 +516,45 @@ impl<C: PolkadotApi, R: TableRouter> bft::Proposer for Proposer<C, R> { type Evaluate = Result<bool, Error>; fn propose(&self) -> Result<SubstrateBlock, Error> { + use transaction_pool::Ready; + // TODO: handle case when current timestamp behind that in state. - let polkadot_block = self.client.build_block( - &BlockId::Hash(self.parent_hash), + let mut block_builder = self.client.build_block( + &self.parent_id, current_timestamp() - )?.bake(); + )?; + + let readiness_evaluator = Ready::create(self.parent_id.clone(), &*self.client); + + { + let mut pool = self.transaction_pool.lock(); + let mut unqueue_invalid = Vec::new(); + let mut pending_size = 0; + for pending in pool.pending(readiness_evaluator.clone()) { + // skip and cull transactions which are too large. + if pending.encoded_size() > MAX_TRANSACTIONS_SIZE { + unqueue_invalid.push(pending.hash().clone()); + continue + } - // TODO: integrate transaction queue and `push_transaction`s. + if pending_size + pending.encoded_size() >= MAX_TRANSACTIONS_SIZE { break } + match block_builder.push_transaction(pending.as_transaction().clone()) { + Ok(()) => { + pending_size += pending.encoded_size(); + } + Err(_) => { + unqueue_invalid.push(pending.hash().clone()); + } + } + } + + for tx_hash in unqueue_invalid { + pool.remove(&tx_hash, false); + } + } + + let polkadot_block = block_builder.bake(); let substrate_block = Slicable::decode(&mut polkadot_block.encode().as_slice()) .expect("polkadot blocks defined to serialize to substrate blocks correctly; qed"); @@ -519,7 +563,7 @@ impl<C: PolkadotApi, R: TableRouter> bft::Proposer for Proposer<C, R> { // TODO: certain kinds of errors here should lead to a misbehavior report. fn evaluate(&self, proposal: &SubstrateBlock) -> Result<bool, Error> { - evaluate_proposal(proposal, &*self.client, current_timestamp(), &self.parent_hash) + evaluate_proposal(proposal, &*self.client, current_timestamp(), &self.parent_hash, &self.parent_id) } } @@ -528,6 +572,7 @@ fn evaluate_proposal<C: PolkadotApi>( client: &C, now: Timestamp, parent_hash: &HeaderHash, + parent_id: &C::CheckedBlockId, ) -> Result<bool, Error> { const MAX_TIMESTAMP_DRIFT: Timestamp = 4; @@ -535,6 +580,14 @@ fn evaluate_proposal<C: PolkadotApi>( let proposal = PolkadotBlock::decode(&mut &encoded[..]) .ok_or_else(|| ErrorKind::ProposalNotForPolkadot)?; + let transactions_size = proposal.body.transactions.iter().fold(0, |a, tx| { + a + Slicable::encode(tx).len() + }); + + if transactions_size > MAX_TRANSACTIONS_SIZE { + bail!(ErrorKind::ProposalTooLarge(transactions_size)) + } + if proposal.header.parent_hash != *parent_hash { bail!(ErrorKind::WrongParentHash(*parent_hash, proposal.header.parent_hash)); } @@ -551,6 +604,6 @@ fn evaluate_proposal<C: PolkadotApi>( } // execute the block. - client.evaluate_block(&BlockId::Hash(*parent_hash), proposal)?; + client.evaluate_block(parent_id, proposal)?; Ok(true) } diff --git a/substrate/polkadot/primitives/src/transaction.rs b/substrate/polkadot/primitives/src/transaction.rs index d0b5ab9557f4f7101b7bb39b9a469299e8bf9412..3d4095b86c8d7661f84985958504a957a5134a31 100644 --- a/substrate/polkadot/primitives/src/transaction.rs +++ b/substrate/polkadot/primitives/src/transaction.rs @@ -237,7 +237,10 @@ impl Function { /// /// Transactions containing inherent functions should not be signed. pub fn is_inherent(&self) -> bool { - self.inherent_index().is_some() + match *self { + Function::Inherent(_) => true, + _ => false, + } } /// If this function is inherent, returns the index it should occupy @@ -370,6 +373,11 @@ impl UncheckedTransaction { } } + /// Whether this transaction invokes an inherent function. + pub fn is_inherent(&self) -> bool { + self.transaction.function.is_inherent() + } + /// Create a new inherent-style transaction from the given function. pub fn inherent(function: InherentFunction) -> Self { UncheckedTransaction { diff --git a/substrate/polkadot/runtime/src/api.rs b/substrate/polkadot/runtime/src/api.rs index b8371a5da8531a2207f6e746b4c5efd094eb84e6..7ce51381e9d78f56d7d1169ddf57b1eafc6159af 100644 --- a/substrate/polkadot/runtime/src/api.rs +++ b/substrate/polkadot/runtime/src/api.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see <http://www.gnu.org/licenses/>. -use runtime::{system, parachains, consensus, session, timestamp}; +use runtime::{system, parachains, consensus, session}; impl_stubs!( execute_block => |block| system::internal::execute_block(block), @@ -24,5 +24,6 @@ impl_stubs!( validators => |()| session::validators(), authorities => |()| consensus::authorities(), duty_roster => |()| parachains::calculate_duty_roster(), - get_timestamp => |()| timestamp::get() + timestamp => |()| ::runtime::timestamp::get(), + nonce => |account_id| system::nonce(account_id) ); diff --git a/substrate/polkadot/runtime/src/lib.rs b/substrate/polkadot/runtime/src/lib.rs index 4059a16551632ca04d7f498a1a7051612ee972d2..16379cac8e41188e7d0cb1ab49d05fc1ea9e8552 100644 --- a/substrate/polkadot/runtime/src/lib.rs +++ b/substrate/polkadot/runtime/src/lib.rs @@ -31,9 +31,9 @@ extern crate polkadot_primitives; #[cfg(test)] #[macro_use] extern crate hex_literal; +pub mod api; pub mod environment; pub mod runtime; -pub mod api; #[cfg(feature = "std")] pub mod genesismap; diff --git a/substrate/polkadot/runtime/src/runtime/system.rs b/substrate/polkadot/runtime/src/runtime/system.rs index b9d28cf18e5ff13fdfa3d16ad6d9d76561b31ce7..aa6cfc45ce7120ac6389137eef15df5edf3932fd 100644 --- a/substrate/polkadot/runtime/src/runtime/system.rs +++ b/substrate/polkadot/runtime/src/runtime/system.rs @@ -17,19 +17,26 @@ //! System manager: Handles all of the top-level stuff; executing block/transaction, setting code //! and depositing logs. -use rstd::prelude::*; use rstd::mem; -use runtime_io::{print, storage_root, enumerated_trie_root}; +use rstd::prelude::*; + use codec::{KeyedVec, Slicable}; -use runtime_support::{Hashable, storage}; use environment::with_env; -use polkadot_primitives::{AccountId, Hash, TxOrder, BlockNumber, Block, Header, - UncheckedTransaction, Function, InherentFunction, Log}; +use polkadot_primitives::{ + AccountId, Hash, TxOrder, BlockNumber, Block, Header, + UncheckedTransaction, Function, InherentFunction, Log +}; + +use runtime_io::{print, storage_root, enumerated_trie_root}; +use runtime_support::{Hashable, storage}; use runtime::{staking, session}; -const NONCE_OF: &[u8] = b"sys:non:"; -const BLOCK_HASH_AT: &[u8] = b"sys:old:"; -const TEMP_TRANSACTION_NUMBER: &[u8] = b"temp:txcount:"; +/// Prefixes account ID and stores u64 nonce. +pub const NONCE_OF: &[u8] = b"sys:non:"; +/// Prefixes block number and stores hash of that block. +pub const BLOCK_HASH_AT: &[u8] = b"sys:old:"; +/// Stores the temporary current transaction number. +pub const TEMP_TRANSACTION_NUMBER: &[u8] = b"temp:txcount"; /// The current block number being processed. Set by `execute_block`. pub fn block_number() -> BlockNumber { @@ -53,8 +60,6 @@ pub mod privileged { pub mod internal { use super::*; - struct CheckedTransaction(UncheckedTransaction); - /// Deposits a log and ensures it matches the blocks log data. pub fn deposit_log(log: Log) { with_env(|e| e.digest.logs.push(log)); @@ -141,6 +146,12 @@ pub mod internal { } } +/// Get an account's current nonce. +pub fn nonce(account: AccountId) -> TxOrder { + let nonce_key = account.to_keyed_vec(NONCE_OF); + storage::get_or(&nonce_key, 0) +} + /// Dispatch a function. fn dispatch_function(function: &Function, transactor: &AccountId) { match *function { diff --git a/substrate/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm b/substrate/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm index 89ed90c99d157f4a0c948badd83877df0da103b8..1a7785d62623f53de0c64cb75a2aff30a273585f 100644 Binary files a/substrate/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm and b/substrate/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm differ diff --git a/substrate/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm b/substrate/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm index 3ca31b5a116ebe29af9c12b951b1df74e97bbd28..7528a02d42f7c13ae4826476215bacb482f7c9c3 100644 Binary files a/substrate/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm and b/substrate/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm differ diff --git a/substrate/polkadot/transaction-pool/Cargo.toml b/substrate/polkadot/transaction-pool/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..51271feece3b0105c7f5a59025ef2485b5a83774 --- /dev/null +++ b/substrate/polkadot/transaction-pool/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "polkadot-transaction-pool" +version = "0.1.0" +authors = ["Parity Technologies <admin@parity.io>"] + +[dependencies] +transaction-pool = "1.9.0" +error-chain = "0.11" +polkadot-api = { path = "../api" } +polkadot-primitives = { path = "../primitives" } +substrate-primitives = { path = "../../substrate/primitives" } +substrate-codec = { path = "../../substrate/codec" } +ed25519 = { path = "../../substrate/ed25519" } +ethereum-types = "0.2" diff --git a/substrate/polkadot/transaction-pool/src/lib.rs b/substrate/polkadot/transaction-pool/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..4ab327bd18ade62401f35fbd5a895fb0b0247f47 --- /dev/null +++ b/substrate/polkadot/transaction-pool/src/lib.rs @@ -0,0 +1,298 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see <http://www.gnu.org/licenses/>. + +extern crate transaction_pool; +extern crate polkadot_api; +extern crate polkadot_primitives as primitives; +extern crate substrate_primitives as substrate_primitives; +extern crate substrate_codec as codec; +extern crate ed25519; +extern crate ethereum_types; + +#[macro_use] +extern crate error_chain; + +use std::collections::HashMap; +use std::cmp::Ordering; +use std::sync::Arc; + +use polkadot_api::PolkadotApi; +use primitives::AccountId; +use primitives::transaction::UncheckedTransaction; +use transaction_pool::{Pool, Readiness}; +use transaction_pool::scoring::{Change, Choice}; + +// TODO: make queue generic over hash and sender so we don't need ethereum-types +pub use ethereum_types::{Address as TruncatedAccountId, H256 as TransactionHash}; +pub use transaction_pool::{Options, Status, LightStatus, NoopListener, VerifiedTransaction as VerifiedTransactionOps}; + +/// Truncate an account ID to 160 bits. +pub fn truncate_id(id: &AccountId) -> TruncatedAccountId { + TruncatedAccountId::from_slice(&id[..20]) +} + +/// Iterator over pending transactions. +pub type PendingIterator<'a, C> = + transaction_pool::PendingIterator<'a, VerifiedTransaction, Ready<'a, C>, Scoring, NoopListener>; + +error_chain! { + errors { + /// Attempted to queue an inherent transaction. + IsInherent(tx: UncheckedTransaction) { + description("Inherent transactions cannot be queued."), + display("Inehrent transactions cannot be queued."), + } + /// Attempted to queue a transaction with bad signature. + BadSignature(tx: UncheckedTransaction) { + description("Transaction had bad signature."), + display("Transaction had bad signature."), + } + /// Import error. + Import(err: Box<::std::error::Error + Send>) { + description("Error importing transaction"), + display("Error importing transaction: {}", err.description()), + } + } +} + +/// A verified transaction which should be includable and non-inherent. +#[derive(Debug, Clone)] +pub struct VerifiedTransaction { + inner: UncheckedTransaction, + hash: TransactionHash, + address: TruncatedAccountId, + insertion_id: u64, + encoded_size: usize, +} + +impl VerifiedTransaction { + /// Attempt to verify a transaction. + fn create(tx: UncheckedTransaction, insertion_id: u64) -> Result<Self> { + if tx.is_inherent() { + bail!(ErrorKind::IsInherent(tx)) + } + + let message = codec::Slicable::encode(&tx); + if ed25519::verify(&*tx.signature, &message, &tx.transaction.signed[..]) { + // TODO: make transaction-pool use generic types. + let hash = substrate_primitives::hashing::blake2_256(&message); + let address = truncate_id(&tx.transaction.signed); + Ok(VerifiedTransaction { + inner: tx, + hash: hash.into(), + encoded_size: message.len(), + address, + insertion_id, + }) + } else { + Err(ErrorKind::BadSignature(tx).into()) + } + } + + /// Access the underlying transaction. + pub fn as_transaction(&self) -> &UncheckedTransaction { + self.as_ref() + } + + /// Consume the verified transaciton, yielding the unchecked counterpart. + pub fn into_inner(self) -> UncheckedTransaction { + self.inner + } + + /// Get the 256-bit hash of this transaction. + pub fn hash(&self) -> &TransactionHash { + &self.hash + } + + /// Get the truncated account ID of the sender of this transaction. + pub fn sender(&self) -> &TruncatedAccountId { + &self.address + } + + /// Get encoded size of the transaction. + pub fn encoded_size(&self) -> usize { + self.encoded_size + } +} + +impl AsRef<UncheckedTransaction> for VerifiedTransaction { + fn as_ref(&self) -> &UncheckedTransaction { + &self.inner + } +} + +impl transaction_pool::VerifiedTransaction for VerifiedTransaction { + fn hash(&self) -> &TransactionHash { + &self.hash + } + + fn sender(&self) -> &TruncatedAccountId { + &self.address + } + + fn mem_usage(&self) -> usize { + 1 // TODO + } + + fn insertion_id(&self) -> u64 { + self.insertion_id + } +} + +/// Scoring implementation for polkadot transactions. +pub struct Scoring; + +impl transaction_pool::Scoring<VerifiedTransaction> for Scoring { + type Score = u64; + + fn compare(&self, old: &VerifiedTransaction, other: &VerifiedTransaction) -> Ordering { + old.inner.transaction.nonce.cmp(&other.inner.transaction.nonce) + } + + fn choose(&self, _old: &VerifiedTransaction, _new: &VerifiedTransaction) -> Choice { + Choice::InsertNew + } + + fn update_scores( + &self, + txs: &[Arc<VerifiedTransaction>], + scores: &mut [Self::Score], + _change: Change + ) { + for i in 0..txs.len() { + // all the same score since there are no fees. + // TODO: prioritize things like misbehavior or fishermen reports + scores[i] = 1; + } + } + fn should_replace(&self, _old: &VerifiedTransaction, _new: &VerifiedTransaction) -> bool { + false // no fees to determine which is better. + } +} + +/// Readiness evaluator for polkadot transactions. +pub struct Ready<'a, T: 'a + PolkadotApi> { + at_block: T::CheckedBlockId, + api_handle: &'a T, + known_nonces: HashMap<AccountId, ::primitives::TxOrder>, +} + +impl<'a, T: 'a + PolkadotApi> Clone for Ready<'a, T> { + fn clone(&self) -> Self { + Ready { + at_block: self.at_block.clone(), + api_handle: self.api_handle, + known_nonces: self.known_nonces.clone(), + } + } +} + +impl<'a, T: 'a + PolkadotApi> Ready<'a, T> { + /// Create a new readiness evaluator at the given block. Requires that + /// the ID has already been checked for local corresponding and available state. + pub fn create(at: T::CheckedBlockId, client: &'a T) -> Self { + Ready { + at_block: at, + api_handle: client, + known_nonces: HashMap::new(), + } + } +} + +impl<'a, T: 'a + PolkadotApi> transaction_pool::Ready<VerifiedTransaction> for Ready<'a, T> { + fn is_ready(&mut self, tx: &VerifiedTransaction) -> Readiness { + let sender = tx.inner.transaction.signed; + + // TODO: find a way to handle nonce error properly -- will need changes to + // transaction-pool trait. + let (api_handle, at_block) = (&self.api_handle, &self.at_block); + let next_nonce = self.known_nonces.entry(sender) + .or_insert_with(|| api_handle.nonce(at_block, sender).ok().unwrap_or_else(u64::max_value)); + + *next_nonce += 1; + + match tx.inner.transaction.nonce.cmp(&next_nonce) { + Ordering::Greater => Readiness::Future, + Ordering::Equal => Readiness::Ready, + Ordering::Less => Readiness::Stalled, + } + } +} + +/// The polkadot transaction pool. +/// +/// Wraps a `transaction-pool::Pool`. +pub struct TransactionPool { + inner: transaction_pool::Pool<VerifiedTransaction, Scoring>, + insertion_index: u64, // TODO: use AtomicU64 when it stabilizes +} + +impl TransactionPool { + /// Create a new transaction pool. + pub fn new(options: Options) -> Self { + TransactionPool { + inner: Pool::new(NoopListener, Scoring, options), + insertion_index: 0, + } + } + + /// Verify and import a transaction into the pool. + pub fn import(&mut self, tx: UncheckedTransaction) -> Result<Arc<VerifiedTransaction>> { + let insertion_index = self.insertion_index; + self.insertion_index += 1; + + let verified = VerifiedTransaction::create(tx, insertion_index)?; + + // TODO: just use a foreign link when the error type is made public. + self.inner.import(verified) + .map_err(|e| ErrorKind::Import(Box::new(e))) + .map_err(Into::into) + } + + /// Clear the pool. + pub fn clear(&mut self) { + self.inner.clear(); + } + + /// Remove from the pool. + pub fn remove(&mut self, hash: &TransactionHash, is_valid: bool) -> Option<Arc<VerifiedTransaction>> { + self.inner.remove(hash, is_valid) + } + + /// Cull transactions from the queue. + pub fn cull<T: PolkadotApi>(&mut self, senders: Option<&[TruncatedAccountId]>, ready: Ready<T>) -> usize { + self.inner.cull(senders, ready) + } + + /// Get an iterator of pending transactions. + pub fn pending<'a, T: 'a + PolkadotApi>(&'a self, ready: Ready<'a, T>) -> PendingIterator<'a, T> { + self.inner.pending(ready) + } + + /// Get the full status of the queue (including readiness) + pub fn status<T: PolkadotApi>(&self, ready: Ready<T>) -> Status { + self.inner.status(ready) + } + + /// Returns light status of the pool. + pub fn light_status(&self) -> LightStatus { + self.inner.light_status() + } +} + +#[cfg(test)] +mod tests { +} diff --git a/substrate/substrate/codec/src/slicable.rs b/substrate/substrate/codec/src/slicable.rs index 74b165ec4ccee6761fb1a690634cdfe515e221dc..0304b51003765d70956b17b323b61d692e086b78 100644 --- a/substrate/substrate/codec/src/slicable.rs +++ b/substrate/substrate/codec/src/slicable.rs @@ -118,7 +118,7 @@ impl Slicable for Vec<u64> { u32::decode(input).and_then(move |len| { let len = len as usize; let mut vec = Vec::with_capacity(len); - for i in 0..len { + for _ in 0..len { vec.push(u64::decode(input)?); } Some(vec) diff --git a/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm b/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm index c9ad192e0171feeb0fcf555593cc787f68dcd8b2..fc34a3fd55082e7011646e99b1fc54c7d4fda632 100644 Binary files a/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm and b/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm differ diff --git a/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm b/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm index f9ce2b147d7e4ee8a5df653cadaabf98235f751a..c27b24b0c21ae7094dd821cf5309d28a5a547c52 100644 Binary files a/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm and b/substrate/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm differ