diff --git a/.gitignore b/.gitignore index efe1d5d61f48e..be532c5d8007e 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,9 @@ polkadot/runtime/wasm/target/ substrate/executor/wasm/target/ substrate/test-runtime/wasm/target/ +substrate/pwasm-alloc/target/ +substrate/pwasm-libc/target/ +substrate/pwasm-alloc/Cargo.lock +substrate/pwasm-libc/Cargo.lock demo/runtime/wasm/target/ **/._* diff --git a/polkadot/consensus/src/lib.rs b/polkadot/consensus/src/lib.rs index 1d79f9f2077e8..cefb625afcea1 100644 --- a/polkadot/consensus/src/lib.rs +++ b/polkadot/consensus/src/lib.rs @@ -585,7 +585,15 @@ impl bft::Proposer for Proposer { } let polkadot_block = block_builder.bake(); - info!("Proposing block [number: {}; extrinsics: [{}], parent_hash: {}]", polkadot_block.header.number, polkadot_block.extrinsics.len(), polkadot_block.header.parent_hash); + info!("Proposing block [number: {}; hash: {}; parent_hash: {}; extrinsics: [{}]]", + polkadot_block.header.number, + Hash::from(polkadot_block.header.blake2_256()), + polkadot_block.header.parent_hash, + polkadot_block.extrinsics.iter() + .map(|xt| format!("{}", Hash::from(xt.blake2_256()))) + .collect::>() + .join(", ") + ); let substrate_block = Slicable::decode(&mut polkadot_block.encode().as_slice()) .expect("polkadot blocks defined to serialize to substrate blocks correctly; qed"); diff --git a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm index ed4b07987ed61..428d6a94b9873 100644 Binary files a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm and b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm differ diff --git a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm index 2dacd6f14b05f..07c467e9a5a6a 100755 Binary files a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm and b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm differ diff --git a/polkadot/service/src/lib.rs b/polkadot/service/src/lib.rs index 9c0adc23d9fe6..2c4d4ef47c13a 100644 --- a/polkadot/service/src/lib.rs +++ b/polkadot/service/src/lib.rs @@ -206,7 +206,7 @@ fn local_testnet_config() -> ChainConfig { }), staking: Some(StakingConfig { current_era: 0, - intentions: vec![], + intentions: initial_authorities.clone(), transaction_fee: 1, balances: endowed_accounts.iter().map(|&k|(k, 1u64 << 60)).collect(), validator_count: 2, diff --git a/polkadot/transaction-pool/src/lib.rs b/polkadot/transaction-pool/src/lib.rs index 56534aa6992ad..555f2a8402b23 100644 --- a/polkadot/transaction-pool/src/lib.rs +++ b/polkadot/transaction-pool/src/lib.rs @@ -292,6 +292,7 @@ impl<'a, T: 'a + PolkadotApi> Ready<'a, T> { impl<'a, T: 'a + PolkadotApi> transaction_pool::Ready for Ready<'a, T> { fn is_ready(&mut self, xt: &VerifiedTransaction) -> Readiness { let sender = xt.inner.signed; + trace!(target: "transaction-pool", "Checking readiness of {} (from {})", xt.hash, TransactionHash::from(sender)); // TODO: find a way to handle index error properly -- will need changes to // transaction-pool trait. @@ -299,6 +300,8 @@ impl<'a, T: 'a + PolkadotApi> transaction_pool::Ready for R let next_index = self.known_indices.entry(sender) .or_insert_with(|| api_handle.index(at_block, sender).ok().unwrap_or_else(u64::max_value)); + trace!(target: "transaction-pool", "Next index for sender is {}; xt index is {}", next_index, xt.inner.index); + match xt.inner.index.cmp(&next_index) { Ordering::Greater => Readiness::Future, Ordering::Equal => Readiness::Ready, diff --git a/substrate/bft/src/generic/mod.rs b/substrate/bft/src/generic/mod.rs index aa0fe2c549a3f..0d0b1058934a6 100644 --- a/substrate/bft/src/generic/mod.rs +++ b/substrate/bft/src/generic/mod.rs @@ -293,7 +293,7 @@ impl Locked { enum LocalState { Start, Proposed, - Prepared, + Prepared(bool), // whether we thought it valid. Committed, VoteAdvance, } @@ -582,6 +582,7 @@ impl Strategy { Some(_) => { // don't check validity if we are locked. // this is necessary to preserve the liveness property. + self.local_state = LocalState::Prepared(true); prepare_for = Some(digest); } None => { @@ -591,6 +592,8 @@ impl Strategy { if let Async::Ready(valid) = res { self.evaluating_proposal = None; + self.local_state = LocalState::Prepared(valid); + if valid { prepare_for = Some(digest); } @@ -606,7 +609,6 @@ impl Strategy { ).into(); self.import_and_send_message(message, context, sending); - self.local_state = LocalState::Prepared; } Ok(()) @@ -657,6 +659,12 @@ impl Strategy { // sent an AdvanceRound message yet, do so. let mut attempt_advance = self.current_accumulator.advance_votes() > self.max_faulty; + // if we evaluated the proposal and it was bad, vote to advance round. + if let LocalState::Prepared(false) = self.local_state { + attempt_advance = true; + } + + // if the timeout has fired, vote to advance round. if let Async::Ready(_) = self.round_timeout.poll()? { attempt_advance = true; } diff --git a/substrate/bft/src/generic/tests.rs b/substrate/bft/src/generic/tests.rs index 00d8ccf9a54d9..b683d751e6ed5 100644 --- a/substrate/bft/src/generic/tests.rs +++ b/substrate/bft/src/generic/tests.rs @@ -18,6 +18,7 @@ use super::*; +use std::collections::BTreeSet; use std::sync::{Arc, Mutex}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::time::Duration; @@ -117,6 +118,7 @@ struct TestContext { node_count: usize, current_round: Arc, timer: Timer, + evaluated: Mutex>, } impl Context for TestContext { @@ -137,7 +139,7 @@ impl Context for TestContext { let proposal = { let mut p = self.proposal.lock().unwrap(); let x = *p; - *p = (*p * 2) + 1; + *p += self.node_count; x }; @@ -175,6 +177,10 @@ impl Context for TestContext { } fn proposal_valid(&self, proposal: &Candidate) -> FutureResult { + if !self.evaluated.lock().unwrap().insert(proposal.0) { + panic!("Evaluated proposal {:?} twice", proposal.0); + } + Ok(proposal.0 % 3 != 0).into_future() } @@ -230,6 +236,64 @@ fn consensus_completes_with_minimum_good() { proposal: Mutex::new(i), current_round: Arc::new(AtomicUsize::new(0)), timer: timer.clone(), + evaluated: Mutex::new(BTreeSet::new()), + node_count, + }; + + agree( + ctx, + node_count, + max_faulty, + rx.map_err(|_| Error), + tx.sink_map_err(|_| Error).with(move |t| Ok((i, t))), + ) + }) + .collect::>(); + + let timeout = timeout_in(Duration::from_millis(500)).map_err(|_| Error); + let results = ::futures::future::join_all(nodes) + .map(Some) + .select(timeout.map(|_| None)) + .wait() + .map(|(i, _)| i) + .map_err(|(e, _)| e) + .expect("to complete") + .expect("to not time out"); + + for result in &results { + assert_eq!(&result.justification.digest, &results[0].justification.digest); + } +} + +#[test] +fn consensus_completes_with_minimum_good_all_initial_proposals_bad() { + let node_count = 10; + let max_faulty = 3; + + let timer = tokio_timer::wheel().tick_duration(ROUND_DURATION).build(); + + let (network, net_send, net_recv) = Network::new(node_count); + network.route_on_thread(); + + let nodes = net_send + .into_iter() + .zip(net_recv) + .take(node_count - max_faulty) + .enumerate() + .map(|(i, (tx, rx))| { + // the first 5 proposals are going to be bad. + let proposal = if i < 5 { + i * 3 // proposals considered bad in the tests if they are % 3 + } else { + (i * 3) + 1 + }; + + let ctx = TestContext { + local_id: AuthorityId(i), + proposal: Mutex::new(proposal), + current_round: Arc::new(AtomicUsize::new(0)), + timer: timer.clone(), + evaluated: Mutex::new(BTreeSet::new()), node_count, }; @@ -279,6 +343,7 @@ fn consensus_does_not_complete_without_enough_nodes() { proposal: Mutex::new(i), current_round: Arc::new(AtomicUsize::new(0)), timer: timer.clone(), + evaluated: Mutex::new(BTreeSet::new()), node_count, }; @@ -335,6 +400,7 @@ fn threshold_plus_one_locked_on_proposal_only_one_with_candidate() { proposal: Mutex::new(i), current_round: Arc::new(AtomicUsize::new(locked_round + 1)), timer: timer.clone(), + evaluated: Mutex::new(BTreeSet::new()), node_count, }; let mut agreement = agree( @@ -367,7 +433,7 @@ fn threshold_plus_one_locked_on_proposal_only_one_with_candidate() { }) .collect::>(); - let timeout = timeout_in(Duration::from_millis(500)).map_err(|_| Error); + let timeout = timeout_in(Duration::from_millis(1000)).map_err(|_| Error); let results = ::futures::future::join_all(nodes) .map(Some) .select(timeout.map(|_| None)) @@ -404,6 +470,7 @@ fn consensus_completes_even_when_nodes_start_with_a_delay() { proposal: Mutex::new(i), current_round: Arc::new(AtomicUsize::new(0)), timer: timer.clone(), + evaluated: Mutex::new(BTreeSet::new()), node_count, }; diff --git a/substrate/rpc-servers/src/lib.rs b/substrate/rpc-servers/src/lib.rs index 26156c120e189..0d0157553ec44 100644 --- a/substrate/rpc-servers/src/lib.rs +++ b/substrate/rpc-servers/src/lib.rs @@ -58,6 +58,7 @@ pub fn start_http( http::ServerBuilder::new(io) .threads(4) .rest_api(http::RestApi::Unsecure) + .cors(http::DomainsValidation::Disabled) .start_http(addr) } diff --git a/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm b/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm index 7555a364a5a92..a73b67188887f 100644 Binary files a/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm and b/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm differ diff --git a/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm b/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm index 92842089ef45f..c8186f9c08c15 100755 Binary files a/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm and b/substrate/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.wasm differ