diff --git a/Cargo.toml b/Cargo.toml index 39a2e757b7ec7..158f78bf39133 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,4 +91,5 @@ is-it-maintained-issue-resolution = { repository = "paritytech/polkadot" } is-it-maintained-open-issues = { repository = "paritytech/polkadot" } [profile.release] -panic = "abort" +# Substrate runtime requires unwinding. +panic = "unwind" diff --git a/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm b/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm index 8913735a62db1..7d546485a1c9a 100644 Binary files a/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm and b/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm differ diff --git a/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm b/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm index f7b82c5117428..4dad2b4000977 100755 Binary files a/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm and b/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm differ 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 af9ab7dc2745d..8ce040fb8a26a 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 62100fe11a4fd..a0ab536128cb9 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/substrate/cli/src/panic_hook.rs b/substrate/cli/src/panic_hook.rs index 1364cafce46f3..c7cea5c8537b0 100644 --- a/substrate/cli/src/panic_hook.rs +++ b/substrate/cli/src/panic_hook.rs @@ -64,5 +64,6 @@ fn panic_hook(info: &PanicInfo) { ); let _ = writeln!(stderr, "{}", ABOUT_PANIC); + ::std::process::exit(1); } diff --git a/substrate/client/src/block_builder.rs b/substrate/client/src/block_builder.rs index bb50df28fe1df..bc5c29a37f86d 100644 --- a/substrate/client/src/block_builder.rs +++ b/substrate/client/src/block_builder.rs @@ -22,6 +22,7 @@ use state_machine::{self, native_when_possible}; use runtime_primitives::traits::{Header as HeaderT, Hash, Block as BlockT, One, HashFor}; use runtime_primitives::generic::BlockId; use {backend, error, Client, CallExecutor}; +use runtime_primitives::{ApplyResult, ApplyOutcome}; /// Utility for building new (valid) blocks from a stream of extrinsics. pub struct BlockBuilder where @@ -68,6 +69,7 @@ impl BlockBuilder where ); executor.call_at_state(&state, &mut changes, "initialise_block", &header.encode(), native_when_possible())?; + changes.commit_prospective(); Ok(BlockBuilder { header, @@ -83,9 +85,22 @@ impl BlockBuilder where /// the error. Otherwise, it will return a mutable reference to self (in order to chain). pub fn push(&mut self, xt: ::Extrinsic) -> error::Result<()> { match self.executor.call_at_state(&self.state, &mut self.changes, "apply_extrinsic", &xt.encode(), native_when_possible()) { - Ok(_) => { - self.extrinsics.push(xt); - Ok(()) + Ok((result, _)) => { + match ApplyResult::decode(&mut result.as_slice()) { + Some(Ok(ApplyOutcome::Success)) | Some(Ok(ApplyOutcome::Fail)) => { + self.extrinsics.push(xt); + self.changes.commit_prospective(); + Ok(()) + } + Some(Err(e)) => { + self.changes.discard_prospective(); + Err(error::ErrorKind::ApplyExtinsicFailed(e).into()) + } + None => { + self.changes.discard_prospective(); + Err(error::ErrorKind::CallResultDecode("apply_extrinsic").into()) + } + } } Err(e) => { self.changes.discard_prospective(); diff --git a/substrate/client/src/client.rs b/substrate/client/src/client.rs index ef755b13ae697..c4b6ff15b5792 100644 --- a/substrate/client/src/client.rs +++ b/substrate/client/src/client.rs @@ -592,4 +592,31 @@ mod tests { assert_eq!(client.using_environment(|| test_runtime::system::balance_of(Keyring::Alice.to_raw_public().into())).unwrap(), 958); assert_eq!(client.using_environment(|| test_runtime::system::balance_of(Keyring::Ferdie.to_raw_public().into())).unwrap(), 42); } + + #[test] + fn block_builder_does_not_include_invalid() { + let client = test_client::new(); + + let mut builder = client.new_block().unwrap(); + + builder.push(sign_tx(Transfer { + from: Keyring::Alice.to_raw_public().into(), + to: Keyring::Ferdie.to_raw_public().into(), + amount: 42, + nonce: 0, + })).unwrap(); + + assert!(builder.push(sign_tx(Transfer { + from: Keyring::Eve.to_raw_public().into(), + to: Keyring::Alice.to_raw_public().into(), + amount: 42, + nonce: 0, + })).is_err()); + + client.justify_and_import(BlockOrigin::Own, builder.bake().unwrap()).unwrap(); + + assert_eq!(client.info().unwrap().chain.best_number, 1); + assert!(client.state_at(&BlockId::Number(1)).unwrap() != client.state_at(&BlockId::Number(0)).unwrap()); + assert_eq!(client.body(&BlockId::Number(1)).unwrap().unwrap().len(), 1) + } } diff --git a/substrate/client/src/error.rs b/substrate/client/src/error.rs index 5d991b00a11f0..26964334f3d87 100644 --- a/substrate/client/src/error.rs +++ b/substrate/client/src/error.rs @@ -19,6 +19,7 @@ use std; use state_machine; use primitives::hexdisplay::HexDisplay; +use runtime_primitives::ApplyError; error_chain! { errors { @@ -34,6 +35,12 @@ error_chain! { display("UnknownBlock: {}", &*h), } + /// Applying extrinsic error. + ApplyExtinsicFailed(e: ApplyError) { + description("Extrinsic error"), + display("Extrinsic error: {:?}", e), + } + /// Execution error. Execution(e: Box) { description("execution error"), @@ -111,6 +118,12 @@ error_chain! { description("remote fetch failed"), display("Remote data fetch has been failed"), } + + /// Error decoding call result. + CallResultDecode(method: &'static str) { + description("Error decoding call result") + display("Error decoding call result of {}", method) + } } } @@ -139,4 +152,4 @@ impl Error { } } -impl state_machine::Error for Error {} \ No newline at end of file +impl state_machine::Error for Error {} diff --git a/substrate/executor/src/native_executor.rs b/substrate/executor/src/native_executor.rs index 13d19b5447d96..5101398b0eb7e 100644 --- a/substrate/executor/src/native_executor.rs +++ b/substrate/executor/src/native_executor.rs @@ -80,7 +80,11 @@ fn fetch_cached_runtime_version<'a, E: Externalities>( fn safe_call(f: F) -> Result where F: ::std::panic::UnwindSafe + FnOnce() -> U { - ::std::panic::catch_unwind(f).map_err(|_| ErrorKind::Runtime.into()) + // Substrate uses custom panic hook that terminates process on panic. Disable it for the native call. + let hook = ::std::panic::take_hook(); + let result = ::std::panic::catch_unwind(f).map_err(|_| ErrorKind::Runtime.into()); + ::std::panic::set_hook(hook); + result } /// Set up the externalities and safe calling environment to execute calls to a native runtime. diff --git a/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm b/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm index 85ddc5e7b6a2b..ee39736edf763 100644 Binary files a/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm and b/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.compact.wasm differ diff --git a/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.wasm b/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.wasm index f9cad0284aa9e..a48cfe38df266 100755 Binary files a/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.wasm and b/substrate/executor/wasm/target/wasm32-unknown-unknown/release/runtime_test.wasm differ diff --git a/substrate/runtime/executive/src/lib.rs b/substrate/runtime/executive/src/lib.rs index 3d30618a4a765..61f52640418c6 100644 --- a/substrate/runtime/executive/src/lib.rs +++ b/substrate/runtime/executive/src/lib.rs @@ -355,4 +355,15 @@ mod tests { }); }); } + + #[test] + fn bad_extrinsic_not_inserted() { + let mut t = new_test_ext(); + let xt = primitives::testing::TestXt((1, 42, Call::transfer(33.into(), 69))); + with_externalities(&mut t, || { + Executive::initialise_block(&Header::new(1, H256::default(), H256::default(), [69u8; 32].into(), Digest::default())); + assert!(Executive::apply_extrinsic(xt).is_err()); + assert_eq!(>::extrinsic_index(), 0); + }); + } } diff --git a/substrate/state-machine/src/lib.rs b/substrate/state-machine/src/lib.rs index 7a69dc2c21b6f..82a8d0eb50d8c 100644 --- a/substrate/state-machine/src/lib.rs +++ b/substrate/state-machine/src/lib.rs @@ -342,11 +342,9 @@ pub fn execute_using_consensus_failure_handler< match result { Ok(x) => { - overlay.commit_prospective(); Ok(x) } Err(e) => { - overlay.discard_prospective(); Err(Box::new(e)) } } diff --git a/substrate/test-runtime/src/system.rs b/substrate/test-runtime/src/system.rs index df582a46241b2..107bab6f33eff 100644 --- a/substrate/test-runtime/src/system.rs +++ b/substrate/test-runtime/src/system.rs @@ -21,6 +21,7 @@ use rstd::prelude::*; use runtime_io::{storage_root, enumerated_trie_root}; use runtime_support::storage::{self, StorageValue, StorageMap}; use runtime_primitives::traits::{Hash as HashT, BlakeTwo256}; +use runtime_primitives::{ApplyError, ApplyOutcome, ApplyResult}; use codec::{KeyedVec, Encode}; use super::{AccountId, BlockNumber, Extrinsic, H256 as Hash, Block, Header}; @@ -72,7 +73,7 @@ pub fn execute_block(block: Block) { assert!(header.extrinsics_root == txs_root, "Transaction trie root must be valid."); // execute transactions - block.extrinsics.iter().for_each(execute_transaction_backend); + block.extrinsics.iter().for_each(|e| { execute_transaction_backend(e).map_err(|_| ()).expect("Extrinsic error"); }); // check storage root. let storage_root = storage_root().into(); @@ -82,11 +83,11 @@ pub fn execute_block(block: Block) { /// Execute a transaction outside of the block execution function. /// This doesn't attempt to validate anything regarding the block. -pub fn execute_transaction(utx: Extrinsic) { +pub fn execute_transaction(utx: Extrinsic) -> ApplyResult { let extrinsic_index = ExtrinsicIndex::get(); ExtrinsicData::insert(extrinsic_index, utx.encode()); ExtrinsicIndex::put(extrinsic_index + 1); - execute_transaction_backend(&utx); + execute_transaction_backend(&utx) } /// Finalise the block. @@ -109,13 +110,13 @@ pub fn finalise_block() -> Header { } } -fn execute_transaction_backend(utx: &Extrinsic) { +fn execute_transaction_backend(utx: &Extrinsic) -> ApplyResult { use runtime_primitives::traits::BlindCheckable; // check signature let utx = match utx.clone().check() { Ok(tx) => tx, - Err(_) => panic!("All transactions should be properly signed"), + Err(_) => return Err(ApplyError::BadSignature), }; let tx: ::Transfer = utx.transfer; @@ -123,7 +124,9 @@ fn execute_transaction_backend(utx: &Extrinsic) { // check nonce let nonce_key = tx.from.to_keyed_vec(NONCE_OF); let expected_nonce: u64 = storage::get_or(&nonce_key, 0); - assert!(tx.nonce == expected_nonce, "All transactions should have the correct nonce"); + if !(tx.nonce == expected_nonce) { + return Err(ApplyError::Stale) + } // increment nonce in storage storage::put(&nonce_key, &(expected_nonce + 1)); @@ -133,11 +136,14 @@ fn execute_transaction_backend(utx: &Extrinsic) { let from_balance: u64 = storage::get_or(&from_balance_key, 0); // enact transfer - assert!(tx.amount <= from_balance, "All transactions should transfer at most the sender balance"); + if !(tx.amount <= from_balance) { + return Err(ApplyError::CantPay) + } let to_balance_key = tx.to.to_keyed_vec(BALANCE_OF); let to_balance: u64 = storage::get_or(&to_balance_key, 0); storage::put(&from_balance_key, &(from_balance - tx.amount)); storage::put(&to_balance_key, &(to_balance + tx.amount)); + Ok(ApplyOutcome::Success) } #[cfg(feature = "std")] 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 640183b15fb72..de3f922c2ea81 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 7241cad551c0d..d1f2b6fbbf4af 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