From 4839294c863a6a136b370619774449ea71d678ec Mon Sep 17 00:00:00 2001 From: Sergey Pepyakin Date: Thu, 5 Jul 2018 10:09:01 +0300 Subject: [PATCH] Recursive test (#9042) --- Cargo.lock | 6 +-- ethcore/res/wasm-tests | 2 +- ethcore/wasm/Cargo.toml | 2 +- ethcore/wasm/src/tests.rs | 90 ++++++++++++++++++++++++++++----------- 4 files changed, 70 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 09cbc2775..855cc5e62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3763,12 +3763,12 @@ dependencies = [ "parity-wasm 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", "pwasm-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "vm 0.1.0", - "wasmi 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmi 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmi" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4191,7 +4191,7 @@ dependencies = [ "checksum vergen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c3365f36c57e5df714a34be40902b27a992eeddb9996eca52d0584611cf885d" "checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum wasmi 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "076dfb6fe482466f13c191c1ae658692665886776073867881e4ae52bcbc8b4a" +"checksum wasmi 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b4a6d379e9332b1b1f52c5a87f2481c85c7c931d8ec411963dfb8f26b1ec1e3" "checksum webpki 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e1622384bcb5458c6a3e3fa572f53ea8fef1cc85e535a2983dea87e9154fac2" "checksum webpki-roots 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "155d4060e5befdf3a6076bd28c22513473d9900b763c9e4521acc6f78a75415c" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" diff --git a/ethcore/res/wasm-tests b/ethcore/res/wasm-tests index fb111c82d..474110de5 160000 --- a/ethcore/res/wasm-tests +++ b/ethcore/res/wasm-tests @@ -1 +1 @@ -Subproject commit fb111c82deff8759f54a5038d07cecc77cb5a663 +Subproject commit 474110de59a0f632b20615256c913b144c49354c diff --git a/ethcore/wasm/Cargo.toml b/ethcore/wasm/Cargo.toml index 40225ed4b..5ca2f3122 100644 --- a/ethcore/wasm/Cargo.toml +++ b/ethcore/wasm/Cargo.toml @@ -12,4 +12,4 @@ libc = "0.2" pwasm-utils = "0.2.2" vm = { path = "../vm" } ethcore-logger = { path = "../../logger" } -wasmi = "0.2.1" +wasmi = "0.3.0" diff --git a/ethcore/wasm/src/tests.rs b/ethcore/wasm/src/tests.rs index b32ca75ae..726b9ebab 100644 --- a/ethcore/wasm/src/tests.rs +++ b/ethcore/wasm/src/tests.rs @@ -86,7 +86,7 @@ fn empty() { test_finalize(interpreter.exec(params, &mut ext)).unwrap() }; - assert_eq!(gas_left, U256::from(98462)); + assert_eq!(gas_left, U256::from(96_926)); } // This test checks if the contract deserializes payload header properly. @@ -138,7 +138,7 @@ fn logger() { U256::from(1_000_000_000), "Logger sets 0x04 key to the trasferred value" ); - assert_eq!(gas_left, U256::from(17_578)); + assert_eq!(gas_left, U256::from(16_181)); } // This test checks if the contract can allocate memory and pass pointer to the result stream properly. @@ -173,7 +173,7 @@ fn identity() { sender, "Idenity test contract does not return the sender passed" ); - assert_eq!(gas_left, U256::from(98_408)); + assert_eq!(gas_left, U256::from(96_883)); } // Dispersion test sends byte array and expect the contract to 'disperse' the original elements with @@ -207,7 +207,7 @@ fn dispersion() { result, vec![0u8, 0, 125, 11, 197, 7, 255, 8, 19, 0] ); - assert_eq!(gas_left, U256::from(94_013)); + assert_eq!(gas_left, U256::from(92_371)); } #[test] @@ -235,7 +235,7 @@ fn suicide_not() { result, vec![0u8] ); - assert_eq!(gas_left, U256::from(94_984)); + assert_eq!(gas_left, U256::from(93_378)); } #[test] @@ -267,7 +267,7 @@ fn suicide() { }; assert!(ext.suicides.contains(&refund)); - assert_eq!(gas_left, U256::from(94_925)); + assert_eq!(gas_left, U256::from(93_348)); } #[test] @@ -297,7 +297,7 @@ fn create() { assert!(ext.calls.contains( &FakeCall { call_type: FakeCallType::Create, - gas: U256::from(60_914), + gas: U256::from(59_269), sender_address: None, receive_address: None, value: Some(1_000_000_000.into()), @@ -305,7 +305,7 @@ fn create() { code_address: None, } )); - assert_eq!(gas_left, U256::from(60_900)); + assert_eq!(gas_left, U256::from(59_212)); } #[test] @@ -349,7 +349,7 @@ fn call_msg() { } )); - assert_eq!(gas_left, U256::from(93_511)); + assert_eq!(gas_left, U256::from(91_672)); } #[test] @@ -394,7 +394,7 @@ fn call_code() { // siphash result let res = LittleEndian::read_u32(&result[..]); assert_eq!(res, 4198595614); - assert_eq!(gas_left, U256::from(92_381)); + assert_eq!(gas_left, U256::from(90_038)); } #[test] @@ -442,7 +442,7 @@ fn call_static() { let res = LittleEndian::read_u32(&result[..]); assert_eq!(res, 317632590); - assert_eq!(gas_left, U256::from(92_381)); + assert_eq!(gas_left, U256::from(90_043)); } // Realloc test @@ -465,7 +465,7 @@ fn realloc() { } }; assert_eq!(result, vec![0u8; 2]); - assert_eq!(gas_left, U256::from(94_372)); + assert_eq!(gas_left, U256::from(92_842)); } #[test] @@ -486,8 +486,8 @@ fn alloc() { GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()), } }; - assert_eq!(result, vec![5u8; 1024*450]); - assert_eq!(gas_left, U256::from(6_506_844)); + assert_eq!(result, vec![5u8; 1024*400]); + assert_eq!(gas_left, U256::from(6_893_883)); } // Tests that contract's ability to read from a storage @@ -515,7 +515,7 @@ fn storage_read() { }; assert_eq!(Address::from(&result[12..32]), address); - assert_eq!(gas_left, U256::from(98_298)); + assert_eq!(gas_left, U256::from(96_833)); } // Tests keccak calculation @@ -541,7 +541,7 @@ fn keccak() { }; assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87")); - assert_eq!(gas_left, U256::from(84_240)); + assert_eq!(gas_left, U256::from(84_134)); } // math_* tests check the ability of wasm contract to perform big integer operations @@ -570,7 +570,7 @@ fn math_add() { U256::from_dec_str("1888888888888888888888888888887").unwrap(), (&result[..]).into() ); - assert_eq!(gas_left, U256::from(93_814)); + assert_eq!(gas_left, U256::from(92_086)); } // multiplication @@ -592,7 +592,7 @@ fn math_mul() { U256::from_dec_str("888888888888888888888888888887111111111111111111111111111112").unwrap(), (&result[..]).into() ); - assert_eq!(gas_left, U256::from(93_300)); + assert_eq!(gas_left, U256::from(91_414)); } // subtraction @@ -614,7 +614,7 @@ fn math_sub() { U256::from_dec_str("111111111111111111111111111111").unwrap(), (&result[..]).into() ); - assert_eq!(gas_left, U256::from(93_826)); + assert_eq!(gas_left, U256::from(92_086)); } // subtraction with overflow @@ -656,7 +656,7 @@ fn math_div() { U256::from_dec_str("1125000").unwrap(), (&result[..]).into() ); - assert_eq!(gas_left, U256::from(90_603)); + assert_eq!(gas_left, U256::from(87_376)); } #[test] @@ -684,7 +684,7 @@ fn storage_metering() { }; // 0 -> not 0 - assert_eq!(gas_left, U256::from(74_338)); + assert_eq!(gas_left, U256::from(72_399)); // #2 @@ -703,7 +703,7 @@ fn storage_metering() { }; // not 0 -> not 0 - assert_eq!(gas_left, U256::from(89_338)); + assert_eq!(gas_left, U256::from(87_399)); } // This test checks the ability of wasm contract to invoke @@ -791,7 +791,7 @@ fn externs() { "Gas limit requested and returned does not match" ); - assert_eq!(gas_left, U256::from(92_110)); + assert_eq!(gas_left, U256::from(90_435)); } #[test] @@ -817,7 +817,7 @@ fn embedded_keccak() { }; assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87")); - assert_eq!(gas_left, U256::from(84_240)); + assert_eq!(gas_left, U256::from(84_134)); } /// This test checks the correctness of log extern @@ -852,5 +852,45 @@ fn events() { assert_eq!(&log_entry.data, b"gnihtemos"); assert_eq!(&result, b"gnihtemos"); - assert_eq!(gas_left, U256::from(81_292)); + assert_eq!(gas_left, U256::from(81_351)); +} + +#[test] +fn recursive() { + ::ethcore_logger::init_log(); + let code = load_sample!("recursive.wasm"); + + let mut params = ActionParams::default(); + params.gas = U256::from(100_000_000); + params.code = Some(Arc::new(code)); + params.data = Some({ + // `recursive` expects only one 32-bit word in LE that + // represents an iteration count. + // + // We pick a relative big number to definitely hit stack overflow. + use byteorder::WriteBytesExt; + let mut data = vec![]; + data.write_u32::(100000).unwrap(); + data + }); + + let mut ext = FakeExt::new().with_wasm(); + + let mut interpreter = wasm_interpreter(); + let result = interpreter.exec(params, &mut ext); + + // We expect that stack overflow will occur and it should be generated by + // deterministic stack metering. Exceeding deterministic stack height limit + // always ends with a trap generated by `unreachable` instruction. + match result { + Err(trap) => { + let err_description = trap.to_string(); + assert!( + err_description.contains("Unreachable"), + "err_description: {} should contain 'Unreachable'", + err_description + ); + }, + _ => panic!("this test should trap"), + } }