Merge with master
This commit is contained in:
commit
01ea968d4f
73
Cargo.lock
generated
73
Cargo.lock
generated
@ -1,6 +1,15 @@
|
|||||||
[root]
|
[root]
|
||||||
name = "using_queue"
|
name = "wasm"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ethcore-logger 1.8.0",
|
||||||
|
"ethcore-util 1.8.0",
|
||||||
|
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"parity-wasm 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"vm 0.1.0",
|
||||||
|
"wasm-utils 0.1.0 (git+https://github.com/paritytech/wasm-utils)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "advapi32-sys"
|
name = "advapi32-sys"
|
||||||
@ -181,6 +190,14 @@ name = "blastfig"
|
|||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bloomable"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"ethcore-bigint 0.1.3",
|
||||||
|
"tiny-keccak 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bloomchain"
|
name = "bloomchain"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -220,6 +237,15 @@ name = "cfg-if"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chainspec"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"ethjson 0.1.0",
|
||||||
|
"serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cid"
|
name = "cid"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@ -271,6 +297,7 @@ dependencies = [
|
|||||||
name = "common-types"
|
name = "common-types"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bloomable 0.1.0",
|
||||||
"ethcore-util 1.8.0",
|
"ethcore-util 1.8.0",
|
||||||
"ethjson 0.1.0",
|
"ethjson 0.1.0",
|
||||||
"rlp 0.2.0",
|
"rlp 0.2.0",
|
||||||
@ -462,6 +489,7 @@ name = "ethcore"
|
|||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"bloomable 0.1.0",
|
||||||
"bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bloomchain 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bn 0.4.4 (git+https://github.com/paritytech/bn)",
|
"bn 0.4.4 (git+https://github.com/paritytech/bn)",
|
||||||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -502,8 +530,12 @@ dependencies = [
|
|||||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"stats 0.1.0",
|
"stats 0.1.0",
|
||||||
|
"table 0.1.0",
|
||||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"using_queue 0.1.0",
|
||||||
|
"vm 0.1.0",
|
||||||
|
"wasm 0.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -625,6 +657,7 @@ dependencies = [
|
|||||||
"smallvec 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"smallvec 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"stats 0.1.0",
|
"stats 0.1.0",
|
||||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"vm 0.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -752,11 +785,9 @@ dependencies = [
|
|||||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"sha3 0.1.0",
|
"sha3 0.1.0",
|
||||||
"table 0.1.0",
|
|
||||||
"target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tiny-keccak 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tiny-keccak 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"using_queue 0.1.0",
|
|
||||||
"vergen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"vergen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -880,6 +911,7 @@ dependencies = [
|
|||||||
"bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"common-types 0.1.0",
|
"common-types 0.1.0",
|
||||||
|
"ethcore-logger 1.8.0",
|
||||||
"ethcore-util 1.8.0",
|
"ethcore-util 1.8.0",
|
||||||
"ethjson 0.1.0",
|
"ethjson 0.1.0",
|
||||||
"evmjit 1.8.0",
|
"evmjit 1.8.0",
|
||||||
@ -888,6 +920,7 @@ dependencies = [
|
|||||||
"parity-wasm 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parity-wasm 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rlp 0.2.0",
|
"rlp 0.2.0",
|
||||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"vm 0.1.0",
|
||||||
"wasm-utils 0.1.0 (git+https://github.com/paritytech/wasm-utils)",
|
"wasm-utils 0.1.0 (git+https://github.com/paritytech/wasm-utils)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -903,6 +936,7 @@ dependencies = [
|
|||||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"vm 0.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1933,7 +1967,6 @@ dependencies = [
|
|||||||
"ethkey 0.2.0",
|
"ethkey 0.2.0",
|
||||||
"ethstore 0.1.0",
|
"ethstore 0.1.0",
|
||||||
"ethsync 1.8.0",
|
"ethsync 1.8.0",
|
||||||
"evm 0.1.0",
|
|
||||||
"fetch 0.1.0",
|
"fetch 0.1.0",
|
||||||
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"futures-cpupool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures-cpupool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1962,6 +1995,7 @@ dependencies = [
|
|||||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tokio-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tokio-timer 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"transient-hashmap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"vm 0.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2018,7 +2052,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "parity-ui-precompiled"
|
name = "parity-ui-precompiled"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
source = "git+https://github.com/paritytech/js-precompiled.git#5a357d01c459d3f371a87bfa138567b30603222c"
|
source = "git+https://github.com/paritytech/js-precompiled.git#06f77d96f1b1a771d643f07b60c802d448b6415c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@ -2567,6 +2601,14 @@ dependencies = [
|
|||||||
"synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_ignored"
|
||||||
|
version = "0.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
@ -3044,6 +3086,10 @@ dependencies = [
|
|||||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "using_queue"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf8-ranges"
|
name = "utf8-ranges"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@ -3072,6 +3118,20 @@ dependencies = [
|
|||||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vm"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"common-types 0.1.0",
|
||||||
|
"ethcore-util 1.8.0",
|
||||||
|
"ethjson 0.1.0",
|
||||||
|
"evmjit 1.8.0",
|
||||||
|
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rlp 0.2.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "void"
|
name = "void"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
@ -3080,7 +3140,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-utils"
|
name = "wasm-utils"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/paritytech/wasm-utils#fee06b6d5826c2dc1fc1aa183b0c2c75e3e140c3"
|
source = "git+https://github.com/paritytech/wasm-utils#9462bcc0680f0ec2c876abdf75bae981dd4344a5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 2.24.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.24.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -3355,6 +3415,7 @@ dependencies = [
|
|||||||
"checksum serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6a7c6b751a2e8d5df57a5ff71b5b4fc8aaee9ee28ff1341d640dd130bb5f4f7a"
|
"checksum serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6a7c6b751a2e8d5df57a5ff71b5b4fc8aaee9ee28ff1341d640dd130bb5f4f7a"
|
||||||
"checksum serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "2f6ca58905ebd3c3b285a8a6d4f3ac92b92c0d7951d5649b1bdd212549c06639"
|
"checksum serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "2f6ca58905ebd3c3b285a8a6d4f3ac92b92c0d7951d5649b1bdd212549c06639"
|
||||||
"checksum serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37aee4e0da52d801acfbc0cc219eb1eda7142112339726e427926a6f6ee65d3a"
|
"checksum serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37aee4e0da52d801acfbc0cc219eb1eda7142112339726e427926a6f6ee65d3a"
|
||||||
|
"checksum serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "190e9765dcedb56be63b6e0993a006c7e3b071a016a304736e4a315dc01fb142"
|
||||||
"checksum serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "48b04779552e92037212c3615370f6bd57a40ebba7f20e554ff9f55e41a69a7b"
|
"checksum serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "48b04779552e92037212c3615370f6bd57a40ebba7f20e554ff9f55e41a69a7b"
|
||||||
"checksum serde_urlencoded 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce0fd303af908732989354c6f02e05e2e6d597152870f2c6990efb0577137480"
|
"checksum serde_urlencoded 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce0fd303af908732989354c6f02e05e2e6d597152870f2c6990efb0577137480"
|
||||||
"checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c"
|
"checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c"
|
||||||
|
@ -110,4 +110,4 @@ lto = false
|
|||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["ethstore/cli", "ethkey/cli", "evmbin", "whisper"]
|
members = ["ethstore/cli", "ethkey/cli", "evmbin", "whisper", "chainspec"]
|
||||||
|
9
chainspec/Cargo.toml
Normal file
9
chainspec/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "chainspec"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["debris <marek.kotewicz@gmail.com>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ethjson = { path = "../json" }
|
||||||
|
serde_json = "1.0"
|
||||||
|
serde_ignored = "0.0.4"
|
48
chainspec/src/main.rs
Normal file
48
chainspec/src/main.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
extern crate serde_json;
|
||||||
|
extern crate serde_ignored;
|
||||||
|
extern crate ethjson;
|
||||||
|
|
||||||
|
use std::collections::BTreeSet;
|
||||||
|
use std::{fs, env, process};
|
||||||
|
use ethjson::spec::Spec;
|
||||||
|
|
||||||
|
fn quit(s: &str) -> ! {
|
||||||
|
println!("{}", s);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut args = env::args();
|
||||||
|
if args.len() != 2 {
|
||||||
|
quit("You need to specify chainspec.json\n\
|
||||||
|
\n\
|
||||||
|
./chainspec <chainspec.json>");
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = args.nth(1).expect("args.len() == 2; qed");
|
||||||
|
let file = match fs::File::open(&path) {
|
||||||
|
Ok(file) => file,
|
||||||
|
Err(_) => quit(&format!("{} could not be opened", path)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut unused = BTreeSet::new();
|
||||||
|
let mut deserializer = serde_json::Deserializer::from_reader(file);
|
||||||
|
|
||||||
|
let spec: Result<Spec, _> = serde_ignored::deserialize(&mut deserializer, |field| {
|
||||||
|
unused.insert(field.to_string());
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Err(err) = spec {
|
||||||
|
quit(&format!("{} {}", path, err.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !unused.is_empty() {
|
||||||
|
let err = unused.into_iter()
|
||||||
|
.map(|field| format!("{} unexpected field `{}`", path, field))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("\n");
|
||||||
|
quit(&err);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{} is valid", path);
|
||||||
|
}
|
@ -33,13 +33,14 @@
|
|||||||
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::{fmt, mem, time};
|
use std::{fmt, mem, time};
|
||||||
|
use std::sync::Arc;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use futures::{self, Future, BoxFuture};
|
use futures::{self, Future, BoxFuture};
|
||||||
use futures_cpupool::CpuPool;
|
use futures_cpupool::CpuPool;
|
||||||
use ntp;
|
use ntp;
|
||||||
use time::{Duration, Timespec};
|
use time::{Duration, Timespec};
|
||||||
use util::{Arc, RwLock};
|
use util::RwLock;
|
||||||
|
|
||||||
/// Time checker error.
|
/// Time checker error.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
@ -53,6 +53,11 @@ semver = "0.6"
|
|||||||
stats = { path = "../util/stats" }
|
stats = { path = "../util/stats" }
|
||||||
time = "0.1"
|
time = "0.1"
|
||||||
transient-hashmap = "0.4"
|
transient-hashmap = "0.4"
|
||||||
|
using_queue = { path = "../util/using_queue" }
|
||||||
|
table = { path = "../util/table" }
|
||||||
|
bloomable = { path = "../util/bloomable" }
|
||||||
|
vm = { path = "vm" }
|
||||||
|
wasm = { path = "wasm" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
native-contracts = { path = "native_contracts", features = ["test_contracts"] }
|
native-contracts = { path = "native_contracts", features = ["test_contracts"] }
|
||||||
|
@ -13,7 +13,9 @@ ethjson = { path = "../../json" }
|
|||||||
lazy_static = "0.2"
|
lazy_static = "0.2"
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
rlp = { path = "../../util/rlp" }
|
rlp = { path = "../../util/rlp" }
|
||||||
|
vm = { path = "../vm" }
|
||||||
parity-wasm = "0.12"
|
parity-wasm = "0.12"
|
||||||
|
ethcore-logger = { path = "../../logger" }
|
||||||
wasm-utils = { git = "https://github.com/paritytech/wasm-utils" }
|
wasm-utils = { git = "https://github.com/paritytech/wasm-utils" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
@ -25,7 +25,7 @@ extern crate test;
|
|||||||
use self::test::{Bencher, black_box};
|
use self::test::{Bencher, black_box};
|
||||||
|
|
||||||
use util::*;
|
use util::*;
|
||||||
use evm::action_params::ActionParams;
|
use vm::ActionParams;
|
||||||
use evm::{self, Factory, VMType};
|
use evm::{self, Factory, VMType};
|
||||||
use evm::tests::FakeExt;
|
use evm::tests::FakeExt;
|
||||||
|
|
||||||
|
@ -17,142 +17,8 @@
|
|||||||
//! Evm interface.
|
//! Evm interface.
|
||||||
|
|
||||||
use std::{ops, cmp, fmt};
|
use std::{ops, cmp, fmt};
|
||||||
use util::{U128, U256, U512, trie};
|
use util::{U128, U256, U512};
|
||||||
use action_params::ActionParams;
|
use vm::{Ext, Result, ReturnData, GasLeft, Error};
|
||||||
use {Ext};
|
|
||||||
|
|
||||||
use super::wasm;
|
|
||||||
|
|
||||||
/// Evm errors.
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub enum Error {
|
|
||||||
/// `OutOfGas` is returned when transaction execution runs out of gas.
|
|
||||||
/// The state should be reverted to the state from before the
|
|
||||||
/// transaction execution. But it does not mean that transaction
|
|
||||||
/// was invalid. Balance still should be transfered and nonce
|
|
||||||
/// should be increased.
|
|
||||||
OutOfGas,
|
|
||||||
/// `BadJumpDestination` is returned when execution tried to move
|
|
||||||
/// to position that wasn't marked with JUMPDEST instruction
|
|
||||||
BadJumpDestination {
|
|
||||||
/// Position the code tried to jump to.
|
|
||||||
destination: usize
|
|
||||||
},
|
|
||||||
/// `BadInstructions` is returned when given instruction is not supported
|
|
||||||
BadInstruction {
|
|
||||||
/// Unrecognized opcode
|
|
||||||
instruction: u8,
|
|
||||||
},
|
|
||||||
/// `StackUnderflow` when there is not enough stack elements to execute instruction
|
|
||||||
StackUnderflow {
|
|
||||||
/// Invoked instruction
|
|
||||||
instruction: &'static str,
|
|
||||||
/// How many stack elements was requested by instruction
|
|
||||||
wanted: usize,
|
|
||||||
/// How many elements were on stack
|
|
||||||
on_stack: usize
|
|
||||||
},
|
|
||||||
/// When execution would exceed defined Stack Limit
|
|
||||||
OutOfStack {
|
|
||||||
/// Invoked instruction
|
|
||||||
instruction: &'static str,
|
|
||||||
/// How many stack elements instruction wanted to push
|
|
||||||
wanted: usize,
|
|
||||||
/// What was the stack limit
|
|
||||||
limit: usize
|
|
||||||
},
|
|
||||||
/// Built-in contract failed on given input
|
|
||||||
BuiltIn(&'static str),
|
|
||||||
/// When execution tries to modify the state in static context
|
|
||||||
MutableCallInStaticContext,
|
|
||||||
/// Likely to cause consensus issues.
|
|
||||||
Internal(String),
|
|
||||||
/// Wasm runtime error
|
|
||||||
Wasm(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Box<trie::TrieError>> for Error {
|
|
||||||
fn from(err: Box<trie::TrieError>) -> Self {
|
|
||||||
Error::Internal(format!("Internal error: {}", err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<wasm::RuntimeError> for Error {
|
|
||||||
fn from(err: wasm::RuntimeError) -> Self {
|
|
||||||
Error::Wasm(format!("Runtime error: {:?}", err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
use self::Error::*;
|
|
||||||
match *self {
|
|
||||||
OutOfGas => write!(f, "Out of gas"),
|
|
||||||
BadJumpDestination { destination } => write!(f, "Bad jump destination {:x}", destination),
|
|
||||||
BadInstruction { instruction } => write!(f, "Bad instruction {:x}", instruction),
|
|
||||||
StackUnderflow { instruction, wanted, on_stack } => write!(f, "Stack underflow {} {}/{}", instruction, wanted, on_stack),
|
|
||||||
OutOfStack { instruction, wanted, limit } => write!(f, "Out of stack {} {}/{}", instruction, wanted, limit),
|
|
||||||
BuiltIn(name) => write!(f, "Built-in failed: {}", name),
|
|
||||||
Internal(ref msg) => write!(f, "Internal error: {}", msg),
|
|
||||||
MutableCallInStaticContext => write!(f, "Mutable call in static context"),
|
|
||||||
Wasm(ref msg) => write!(f, "Internal error: {}", msg),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A specialized version of Result over EVM errors.
|
|
||||||
pub type Result<T> = ::std::result::Result<T, Error>;
|
|
||||||
|
|
||||||
/// Return data buffer. Holds memory from a previous call and a slice into that memory.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ReturnData {
|
|
||||||
mem: Vec<u8>,
|
|
||||||
offset: usize,
|
|
||||||
size: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::std::ops::Deref for ReturnData {
|
|
||||||
type Target = [u8];
|
|
||||||
fn deref(&self) -> &[u8] {
|
|
||||||
&self.mem[self.offset..self.offset + self.size]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ReturnData {
|
|
||||||
/// Create empty `ReturnData`.
|
|
||||||
pub fn empty() -> Self {
|
|
||||||
ReturnData {
|
|
||||||
mem: Vec::new(),
|
|
||||||
offset: 0,
|
|
||||||
size: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Create `ReturnData` from give buffer and slice.
|
|
||||||
pub fn new(mem: Vec<u8>, offset: usize, size: usize) -> Self {
|
|
||||||
ReturnData {
|
|
||||||
mem: mem,
|
|
||||||
offset: offset,
|
|
||||||
size: size,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gas Left: either it is a known value, or it needs to be computed by processing
|
|
||||||
/// a return instruction.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum GasLeft {
|
|
||||||
/// Known gas left
|
|
||||||
Known(U256),
|
|
||||||
/// Return or Revert instruction must be processed.
|
|
||||||
NeedsReturn {
|
|
||||||
/// Amount of gas left.
|
|
||||||
gas_left: U256,
|
|
||||||
/// Return data buffer.
|
|
||||||
data: ReturnData,
|
|
||||||
/// Apply or revert state changes on revert.
|
|
||||||
apply_state: bool
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Finalization result. Gas Left: either it is a known value, or it needs to be computed by processing
|
/// Finalization result. Gas Left: either it is a known value, or it needs to be computed by processing
|
||||||
/// a return instruction.
|
/// a return instruction.
|
||||||
@ -281,15 +147,6 @@ impl CostType for usize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evm interface
|
|
||||||
pub trait Evm {
|
|
||||||
/// This function should be used to execute transaction.
|
|
||||||
///
|
|
||||||
/// It returns either an error, a known amount of gas left, or parameters to be used
|
|
||||||
/// to compute the final gas left.
|
|
||||||
fn exec(&mut self, params: ActionParams, ext: &mut Ext) -> Result<GasLeft>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use util::U256;
|
use util::U256;
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! Evm factory.
|
//! Evm factory.
|
||||||
//!
|
//!
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use evm::Evm;
|
use vm::Vm;
|
||||||
use util::U256;
|
use util::U256;
|
||||||
use super::interpreter::SharedCache;
|
use super::interpreter::SharedCache;
|
||||||
use super::vmtype::VMType;
|
use super::vmtype::VMType;
|
||||||
@ -33,7 +33,7 @@ impl Factory {
|
|||||||
/// Create fresh instance of VM
|
/// Create fresh instance of VM
|
||||||
/// Might choose implementation depending on supplied gas.
|
/// Might choose implementation depending on supplied gas.
|
||||||
#[cfg(feature = "jit")]
|
#[cfg(feature = "jit")]
|
||||||
pub fn create(&self, gas: U256) -> Box<Evm> {
|
pub fn create(&self, gas: U256) -> Box<Vm> {
|
||||||
match self.evm {
|
match self.evm {
|
||||||
VMType::Jit => {
|
VMType::Jit => {
|
||||||
Box::new(super::jit::JitEvm::default())
|
Box::new(super::jit::JitEvm::default())
|
||||||
@ -49,7 +49,7 @@ impl Factory {
|
|||||||
/// Create fresh instance of VM
|
/// Create fresh instance of VM
|
||||||
/// Might choose implementation depending on supplied gas.
|
/// Might choose implementation depending on supplied gas.
|
||||||
#[cfg(not(feature = "jit"))]
|
#[cfg(not(feature = "jit"))]
|
||||||
pub fn create(&self, gas: U256) -> Box<Evm> {
|
pub fn create(&self, gas: U256) -> Box<Vm> {
|
||||||
match self.evm {
|
match self.evm {
|
||||||
VMType::Interpreter => if Self::can_fit_in_usize(gas) {
|
VMType::Interpreter => if Self::can_fit_in_usize(gas) {
|
||||||
Box::new(super::interpreter::Interpreter::<usize>::new(self.evm_cache.clone()))
|
Box::new(super::interpreter::Interpreter::<usize>::new(self.evm_cache.clone()))
|
||||||
|
@ -14,18 +14,19 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::cmp;
|
||||||
use util::*;
|
use util::*;
|
||||||
use super::u256_to_address;
|
use super::u256_to_address;
|
||||||
|
|
||||||
use {evm, ext};
|
use {evm, vm};
|
||||||
use instructions::{self, Instruction, InstructionInfo};
|
use instructions::{self, Instruction, InstructionInfo};
|
||||||
use interpreter::stack::Stack;
|
use interpreter::stack::Stack;
|
||||||
use schedule::Schedule;
|
use vm::Schedule;
|
||||||
|
|
||||||
macro_rules! overflowing {
|
macro_rules! overflowing {
|
||||||
($x: expr) => {{
|
($x: expr) => {{
|
||||||
let (v, overflow) = $x;
|
let (v, overflow) = $x;
|
||||||
if overflow { return Err(evm::Error::OutOfGas); }
|
if overflow { return Err(vm::Error::OutOfGas); }
|
||||||
v
|
v
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
@ -59,16 +60,16 @@ impl<Gas: evm::CostType> Gasometer<Gas> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify_gas(&self, gas_cost: &Gas) -> evm::Result<()> {
|
pub fn verify_gas(&self, gas_cost: &Gas) -> vm::Result<()> {
|
||||||
match &self.current_gas < gas_cost {
|
match &self.current_gas < gas_cost {
|
||||||
true => Err(evm::Error::OutOfGas),
|
true => Err(vm::Error::OutOfGas),
|
||||||
false => Ok(())
|
false => Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// How much gas is provided to a CALL/CREATE, given that we need to deduct `needed` for this operation
|
/// How much gas is provided to a CALL/CREATE, given that we need to deduct `needed` for this operation
|
||||||
/// and that we `requested` some.
|
/// and that we `requested` some.
|
||||||
pub fn gas_provided(&self, schedule: &Schedule, needed: Gas, requested: Option<U256>) -> evm::Result<Gas> {
|
pub fn gas_provided(&self, schedule: &Schedule, needed: Gas, requested: Option<U256>) -> vm::Result<Gas> {
|
||||||
// Try converting requested gas to `Gas` (`U256/u64`)
|
// Try converting requested gas to `Gas` (`U256/u64`)
|
||||||
// but in EIP150 even if we request more we should never fail from OOG
|
// but in EIP150 even if we request more we should never fail from OOG
|
||||||
let requested = requested.map(Gas::from_u256);
|
let requested = requested.map(Gas::from_u256);
|
||||||
@ -82,7 +83,7 @@ impl<Gas: evm::CostType> Gasometer<Gas> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(Ok(r)) = requested {
|
if let Some(Ok(r)) = requested {
|
||||||
Ok(min(r, max_gas_provided))
|
Ok(cmp::min(r, max_gas_provided))
|
||||||
} else {
|
} else {
|
||||||
Ok(max_gas_provided)
|
Ok(max_gas_provided)
|
||||||
}
|
}
|
||||||
@ -107,12 +108,12 @@ impl<Gas: evm::CostType> Gasometer<Gas> {
|
|||||||
/// it will be the amount of gas that the current context provides to the child context.
|
/// it will be the amount of gas that the current context provides to the child context.
|
||||||
pub fn requirements(
|
pub fn requirements(
|
||||||
&mut self,
|
&mut self,
|
||||||
ext: &ext::Ext,
|
ext: &vm::Ext,
|
||||||
instruction: Instruction,
|
instruction: Instruction,
|
||||||
info: &InstructionInfo,
|
info: &InstructionInfo,
|
||||||
stack: &Stack<U256>,
|
stack: &Stack<U256>,
|
||||||
current_mem_size: usize,
|
current_mem_size: usize,
|
||||||
) -> evm::Result<InstructionRequirements<Gas>> {
|
) -> vm::Result<InstructionRequirements<Gas>> {
|
||||||
let schedule = ext.schedule();
|
let schedule = ext.schedule();
|
||||||
let tier = instructions::get_tier_idx(info.tier);
|
let tier = instructions::get_tier_idx(info.tier);
|
||||||
let default_gas = Gas::from(schedule.tier_step_gas[tier]);
|
let default_gas = Gas::from(schedule.tier_step_gas[tier]);
|
||||||
@ -291,7 +292,7 @@ impl<Gas: evm::CostType> Gasometer<Gas> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mem_gas_cost(&self, schedule: &Schedule, current_mem_size: usize, mem_size: &Gas) -> evm::Result<(Gas, Gas, usize)> {
|
fn mem_gas_cost(&self, schedule: &Schedule, current_mem_size: usize, mem_size: &Gas) -> vm::Result<(Gas, Gas, usize)> {
|
||||||
let gas_for_mem = |mem_size: Gas| {
|
let gas_for_mem = |mem_size: Gas| {
|
||||||
let s = mem_size >> 5;
|
let s = mem_size >> 5;
|
||||||
// s * memory_gas + s * s / quad_coeff_div
|
// s * memory_gas + s * s / quad_coeff_div
|
||||||
@ -319,12 +320,12 @@ impl<Gas: evm::CostType> Gasometer<Gas> {
|
|||||||
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mem_needed_const<Gas: evm::CostType>(mem: &U256, add: usize) -> evm::Result<Gas> {
|
fn mem_needed_const<Gas: evm::CostType>(mem: &U256, add: usize) -> vm::Result<Gas> {
|
||||||
Gas::from_u256(overflowing!(mem.overflowing_add(U256::from(add))))
|
Gas::from_u256(overflowing!(mem.overflowing_add(U256::from(add))))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mem_needed<Gas: evm::CostType>(offset: &U256, size: &U256) -> evm::Result<Gas> {
|
fn mem_needed<Gas: evm::CostType>(offset: &U256, size: &U256) -> vm::Result<Gas> {
|
||||||
if size.is_zero() {
|
if size.is_zero() {
|
||||||
return Ok(Gas::from(0));
|
return Ok(Gas::from(0));
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use util::U256;
|
use util::U256;
|
||||||
use {ReturnData};
|
use vm::ReturnData;
|
||||||
|
|
||||||
const MAX_RETURN_WASTE_BYTES: usize = 16384;
|
const MAX_RETURN_WASTE_BYTES: usize = 16384;
|
||||||
|
|
||||||
|
@ -23,17 +23,23 @@ mod stack;
|
|||||||
mod memory;
|
mod memory;
|
||||||
mod shared_cache;
|
mod shared_cache;
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::{cmp, mem};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use vm::{
|
||||||
|
self, ActionParams, ActionValue, CallType, MessageCallResult,
|
||||||
|
ContractCreateResult, CreateContractAddress, ReturnData, GasLeft
|
||||||
|
};
|
||||||
|
|
||||||
|
use evm::CostType;
|
||||||
|
use instructions::{self, Instruction, InstructionInfo};
|
||||||
|
|
||||||
use self::gasometer::Gasometer;
|
use self::gasometer::Gasometer;
|
||||||
use self::stack::{Stack, VecStack};
|
use self::stack::{Stack, VecStack};
|
||||||
use self::memory::Memory;
|
use self::memory::Memory;
|
||||||
pub use self::shared_cache::SharedCache;
|
pub use self::shared_cache::SharedCache;
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
use action_params::{ActionParams, ActionValue};
|
|
||||||
use call_type::CallType;
|
|
||||||
use instructions::{self, Instruction, InstructionInfo};
|
|
||||||
use evm::{self, GasLeft, CostType, ReturnData};
|
|
||||||
use ext::{self, MessageCallResult, ContractCreateResult, CreateContractAddress};
|
|
||||||
use bit_set::BitSet;
|
use bit_set::BitSet;
|
||||||
|
|
||||||
use util::*;
|
use util::*;
|
||||||
@ -107,8 +113,8 @@ pub struct Interpreter<Cost: CostType> {
|
|||||||
_type: PhantomData<Cost>,
|
_type: PhantomData<Cost>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Cost: CostType> evm::Evm for Interpreter<Cost> {
|
impl<Cost: CostType> vm::Vm for Interpreter<Cost> {
|
||||||
fn exec(&mut self, params: ActionParams, ext: &mut ext::Ext) -> evm::Result<GasLeft> {
|
fn exec(&mut self, params: ActionParams, ext: &mut vm::Ext) -> vm::Result<GasLeft> {
|
||||||
self.mem.clear();
|
self.mem.clear();
|
||||||
|
|
||||||
let mut informant = informant::EvmInformant::new(ext.depth());
|
let mut informant = informant::EvmInformant::new(ext.depth());
|
||||||
@ -205,7 +211,7 @@ impl<Cost: CostType> Interpreter<Cost> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_instruction(&self, ext: &ext::Ext, instruction: Instruction, info: &InstructionInfo, stack: &Stack<U256>) -> evm::Result<()> {
|
fn verify_instruction(&self, ext: &vm::Ext, instruction: Instruction, info: &InstructionInfo, stack: &Stack<U256>) -> vm::Result<()> {
|
||||||
let schedule = ext.schedule();
|
let schedule = ext.schedule();
|
||||||
|
|
||||||
if (instruction == instructions::DELEGATECALL && !schedule.have_delegate_call) ||
|
if (instruction == instructions::DELEGATECALL && !schedule.have_delegate_call) ||
|
||||||
@ -214,25 +220,25 @@ impl<Cost: CostType> Interpreter<Cost> {
|
|||||||
((instruction == instructions::RETURNDATACOPY || instruction == instructions::RETURNDATASIZE) && !schedule.have_return_data) ||
|
((instruction == instructions::RETURNDATACOPY || instruction == instructions::RETURNDATASIZE) && !schedule.have_return_data) ||
|
||||||
(instruction == instructions::REVERT && !schedule.have_revert) {
|
(instruction == instructions::REVERT && !schedule.have_revert) {
|
||||||
|
|
||||||
return Err(evm::Error::BadInstruction {
|
return Err(vm::Error::BadInstruction {
|
||||||
instruction: instruction
|
instruction: instruction
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.tier == instructions::GasPriceTier::Invalid {
|
if info.tier == instructions::GasPriceTier::Invalid {
|
||||||
return Err(evm::Error::BadInstruction {
|
return Err(vm::Error::BadInstruction {
|
||||||
instruction: instruction
|
instruction: instruction
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if !stack.has(info.args) {
|
if !stack.has(info.args) {
|
||||||
Err(evm::Error::StackUnderflow {
|
Err(vm::Error::StackUnderflow {
|
||||||
instruction: info.name,
|
instruction: info.name,
|
||||||
wanted: info.args,
|
wanted: info.args,
|
||||||
on_stack: stack.size()
|
on_stack: stack.size()
|
||||||
})
|
})
|
||||||
} else if stack.size() - info.args + info.ret > schedule.stack_limit {
|
} else if stack.size() - info.args + info.ret > schedule.stack_limit {
|
||||||
Err(evm::Error::OutOfStack {
|
Err(vm::Error::OutOfStack {
|
||||||
instruction: info.name,
|
instruction: info.name,
|
||||||
wanted: info.ret - info.args,
|
wanted: info.ret - info.args,
|
||||||
limit: schedule.stack_limit
|
limit: schedule.stack_limit
|
||||||
@ -272,12 +278,12 @@ impl<Cost: CostType> Interpreter<Cost> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
gas: Cost,
|
gas: Cost,
|
||||||
params: &ActionParams,
|
params: &ActionParams,
|
||||||
ext: &mut ext::Ext,
|
ext: &mut vm::Ext,
|
||||||
instruction: Instruction,
|
instruction: Instruction,
|
||||||
code: &mut CodeReader,
|
code: &mut CodeReader,
|
||||||
stack: &mut Stack<U256>,
|
stack: &mut Stack<U256>,
|
||||||
provided: Option<Cost>
|
provided: Option<Cost>
|
||||||
) -> evm::Result<InstructionResult<Cost>> {
|
) -> vm::Result<InstructionResult<Cost>> {
|
||||||
match instruction {
|
match instruction {
|
||||||
instructions::JUMP => {
|
instructions::JUMP => {
|
||||||
let jump = stack.pop_back();
|
let jump = stack.pop_back();
|
||||||
@ -593,13 +599,13 @@ impl<Cost: CostType> Interpreter<Cost> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_jump(&self, jump_u: U256, valid_jump_destinations: &BitSet) -> evm::Result<usize> {
|
fn verify_jump(&self, jump_u: U256, valid_jump_destinations: &BitSet) -> vm::Result<usize> {
|
||||||
let jump = jump_u.low_u64() as usize;
|
let jump = jump_u.low_u64() as usize;
|
||||||
|
|
||||||
if valid_jump_destinations.contains(jump) && U256::from(jump) == jump_u {
|
if valid_jump_destinations.contains(jump) && U256::from(jump) == jump_u {
|
||||||
Ok(jump)
|
Ok(jump)
|
||||||
} else {
|
} else {
|
||||||
Err(evm::Error::BadJumpDestination {
|
Err(vm::Error::BadJumpDestination {
|
||||||
destination: jump
|
destination: jump
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -617,7 +623,7 @@ impl<Cost: CostType> Interpreter<Cost> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec_stack_instruction(&self, instruction: Instruction, stack: &mut Stack<U256>) -> evm::Result<()> {
|
fn exec_stack_instruction(&self, instruction: Instruction, stack: &mut Stack<U256>) -> vm::Result<()> {
|
||||||
match instruction {
|
match instruction {
|
||||||
instructions::DUP1...instructions::DUP16 => {
|
instructions::DUP1...instructions::DUP16 => {
|
||||||
let position = instructions::get_dup_position(instruction);
|
let position = instructions::get_dup_position(instruction);
|
||||||
@ -822,7 +828,7 @@ impl<Cost: CostType> Interpreter<Cost> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
return Err(evm::Error::BadInstruction {
|
return Err(vm::Error::BadInstruction {
|
||||||
instruction: instruction
|
instruction: instruction
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ use util::*;
|
|||||||
use evmjit;
|
use evmjit;
|
||||||
use evm::{self, GasLeft};
|
use evm::{self, GasLeft};
|
||||||
use evm::CallType;
|
use evm::CallType;
|
||||||
|
use vm::{self, Vm};
|
||||||
|
|
||||||
/// Should be used to convert jit types to ethcore
|
/// Should be used to convert jit types to ethcore
|
||||||
trait FromJit<T>: Sized {
|
trait FromJit<T>: Sized {
|
||||||
@ -318,7 +319,7 @@ pub struct JitEvm {
|
|||||||
context: Option<evmjit::ContextHandle>,
|
context: Option<evmjit::ContextHandle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl evm::Evm for JitEvm {
|
impl vm::Vm for JitEvm {
|
||||||
fn exec(&mut self, params: ActionParams, ext: &mut evm::Ext) -> evm::Result<GasLeft> {
|
fn exec(&mut self, params: ActionParams, ext: &mut evm::Ext) -> evm::Result<GasLeft> {
|
||||||
// Dirty hack. This is unsafe, but we interact with ffi, so it's justified.
|
// Dirty hack. This is unsafe, but we interact with ffi, so it's justified.
|
||||||
let ext_adapter: ExtAdapter<'static> = unsafe { ::std::mem::transmute(ExtAdapter::new(ext, params.address.clone())) };
|
let ext_adapter: ExtAdapter<'static> = unsafe { ::std::mem::transmute(ExtAdapter::new(ext, params.address.clone())) };
|
||||||
@ -370,8 +371,8 @@ impl evm::Evm for JitEvm {
|
|||||||
ext.suicide(&Address::from_jit(&context.suicide_refund_address()));
|
ext.suicide(&Address::from_jit(&context.suicide_refund_address()));
|
||||||
Ok(GasLeft::Known(U256::from(context.gas_left())))
|
Ok(GasLeft::Known(U256::from(context.gas_left())))
|
||||||
},
|
},
|
||||||
evmjit::ReturnCode::OutOfGas => Err(evm::Error::OutOfGas),
|
evmjit::ReturnCode::OutOfGas => Err(vm::Error::OutOfGas),
|
||||||
_err => Err(evm::Error::Internal)
|
_err => Err(vm::Error::Internal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,11 +24,12 @@ extern crate ethjson;
|
|||||||
extern crate rlp;
|
extern crate rlp;
|
||||||
extern crate parity_wasm;
|
extern crate parity_wasm;
|
||||||
extern crate wasm_utils;
|
extern crate wasm_utils;
|
||||||
|
extern crate ethcore_logger;
|
||||||
|
extern crate vm;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
#[cfg(feature = "jit")]
|
#[cfg(feature = "jit")]
|
||||||
@ -37,14 +38,8 @@ extern crate evmjit;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
extern crate rustc_hex;
|
extern crate rustc_hex;
|
||||||
|
|
||||||
pub mod action_params;
|
|
||||||
pub mod call_type;
|
|
||||||
pub mod env_info;
|
|
||||||
pub mod ext;
|
|
||||||
pub mod evm;
|
pub mod evm;
|
||||||
pub mod interpreter;
|
pub mod interpreter;
|
||||||
pub mod schedule;
|
|
||||||
pub mod wasm;
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod factory;
|
pub mod factory;
|
||||||
@ -59,12 +54,12 @@ mod tests;
|
|||||||
#[cfg(all(feature="benches", test))]
|
#[cfg(all(feature="benches", test))]
|
||||||
mod benches;
|
mod benches;
|
||||||
|
|
||||||
pub use self::action_params::ActionParams;
|
pub use vm::{
|
||||||
pub use self::call_type::CallType;
|
Schedule, CleanDustMode, EnvInfo, CallType, ActionParams, Ext,
|
||||||
pub use self::env_info::EnvInfo;
|
ContractCreateResult, MessageCallResult, CreateContractAddress,
|
||||||
pub use self::evm::{Evm, Error, Finalize, FinalizationResult, GasLeft, Result, CostType, ReturnData};
|
GasLeft, ReturnData
|
||||||
pub use self::ext::{Ext, ContractCreateResult, MessageCallResult, CreateContractAddress};
|
};
|
||||||
|
pub use self::evm::{Finalize, FinalizationResult, CostType};
|
||||||
pub use self::instructions::{InstructionInfo, INSTRUCTIONS, push_bytes};
|
pub use self::instructions::{InstructionInfo, INSTRUCTIONS, push_bytes};
|
||||||
pub use self::vmtype::VMType;
|
pub use self::vmtype::VMType;
|
||||||
pub use self::factory::Factory;
|
pub use self::factory::Factory;
|
||||||
pub use self::schedule::{Schedule, CleanDustMode};
|
|
||||||
|
@ -15,212 +15,17 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::hash::Hash;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
use rustc_hex::FromHex;
|
use rustc_hex::FromHex;
|
||||||
use util::*;
|
use util::*;
|
||||||
use action_params::{ActionParams, ActionValue};
|
use vm::{self, ActionParams, ActionValue};
|
||||||
use env_info::EnvInfo;
|
use vm::tests::{FakeExt, FakeCall, FakeCallType, test_finalize};
|
||||||
use call_type::CallType;
|
|
||||||
use schedule::Schedule;
|
|
||||||
use evm::{self, GasLeft, ReturnData};
|
|
||||||
use ext::{Ext, ContractCreateResult, MessageCallResult, CreateContractAddress};
|
|
||||||
use factory::Factory;
|
use factory::Factory;
|
||||||
use vmtype::VMType;
|
use vmtype::VMType;
|
||||||
|
|
||||||
pub struct FakeLogEntry {
|
|
||||||
topics: Vec<H256>,
|
|
||||||
data: Bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash, Debug)]
|
|
||||||
pub enum FakeCallType {
|
|
||||||
Call, Create
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash, Debug)]
|
|
||||||
pub struct FakeCall {
|
|
||||||
pub call_type: FakeCallType,
|
|
||||||
pub gas: U256,
|
|
||||||
pub sender_address: Option<Address>,
|
|
||||||
pub receive_address: Option<Address>,
|
|
||||||
pub value: Option<U256>,
|
|
||||||
pub data: Bytes,
|
|
||||||
pub code_address: Option<Address>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fake externalities test structure.
|
|
||||||
///
|
|
||||||
/// Can't do recursive calls.
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct FakeExt {
|
|
||||||
pub store: HashMap<H256, H256>,
|
|
||||||
pub suicides: HashSet<Address>,
|
|
||||||
pub calls: HashSet<FakeCall>,
|
|
||||||
sstore_clears: usize,
|
|
||||||
depth: usize,
|
|
||||||
blockhashes: HashMap<U256, H256>,
|
|
||||||
codes: HashMap<Address, Arc<Bytes>>,
|
|
||||||
logs: Vec<FakeLogEntry>,
|
|
||||||
info: EnvInfo,
|
|
||||||
schedule: Schedule,
|
|
||||||
balances: HashMap<Address, U256>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// similar to the normal `finalize` function, but ignoring NeedsReturn.
|
|
||||||
fn test_finalize(res: Result<GasLeft, evm::Error>) -> Result<U256, evm::Error> {
|
|
||||||
match res {
|
|
||||||
Ok(GasLeft::Known(gas)) => Ok(gas),
|
|
||||||
Ok(GasLeft::NeedsReturn{..}) => unimplemented!(), // since ret is unimplemented.
|
|
||||||
Err(e) => Err(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FakeExt {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
FakeExt::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Schedule {
|
|
||||||
fn default() -> Self {
|
|
||||||
Schedule::new_frontier()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ext for FakeExt {
|
|
||||||
fn storage_at(&self, key: &H256) -> evm::Result<H256> {
|
|
||||||
Ok(self.store.get(key).unwrap_or(&H256::new()).clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_storage(&mut self, key: H256, value: H256) -> evm::Result<()> {
|
|
||||||
self.store.insert(key, value);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn exists(&self, address: &Address) -> evm::Result<bool> {
|
|
||||||
Ok(self.balances.contains_key(address))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn exists_and_not_null(&self, address: &Address) -> evm::Result<bool> {
|
|
||||||
Ok(self.balances.get(address).map_or(false, |b| !b.is_zero()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn origin_balance(&self) -> evm::Result<U256> {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn balance(&self, address: &Address) -> evm::Result<U256> {
|
|
||||||
Ok(self.balances[address])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn blockhash(&mut self, number: &U256) -> H256 {
|
|
||||||
self.blockhashes.get(number).unwrap_or(&H256::new()).clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create(&mut self, gas: &U256, value: &U256, code: &[u8], _address: CreateContractAddress) -> ContractCreateResult {
|
|
||||||
self.calls.insert(FakeCall {
|
|
||||||
call_type: FakeCallType::Create,
|
|
||||||
gas: *gas,
|
|
||||||
sender_address: None,
|
|
||||||
receive_address: None,
|
|
||||||
value: Some(*value),
|
|
||||||
data: code.to_vec(),
|
|
||||||
code_address: None
|
|
||||||
});
|
|
||||||
ContractCreateResult::Failed
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call(&mut self,
|
|
||||||
gas: &U256,
|
|
||||||
sender_address: &Address,
|
|
||||||
receive_address: &Address,
|
|
||||||
value: Option<U256>,
|
|
||||||
data: &[u8],
|
|
||||||
code_address: &Address,
|
|
||||||
_output: &mut [u8],
|
|
||||||
_call_type: CallType
|
|
||||||
) -> MessageCallResult {
|
|
||||||
|
|
||||||
self.calls.insert(FakeCall {
|
|
||||||
call_type: FakeCallType::Call,
|
|
||||||
gas: *gas,
|
|
||||||
sender_address: Some(sender_address.clone()),
|
|
||||||
receive_address: Some(receive_address.clone()),
|
|
||||||
value: value,
|
|
||||||
data: data.to_vec(),
|
|
||||||
code_address: Some(code_address.clone())
|
|
||||||
});
|
|
||||||
MessageCallResult::Success(*gas, ReturnData::empty())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extcode(&self, address: &Address) -> evm::Result<Arc<Bytes>> {
|
|
||||||
Ok(self.codes.get(address).unwrap_or(&Arc::new(Bytes::new())).clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extcodesize(&self, address: &Address) -> evm::Result<usize> {
|
|
||||||
Ok(self.codes.get(address).map_or(0, |c| c.len()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> evm::Result<()> {
|
|
||||||
self.logs.push(FakeLogEntry {
|
|
||||||
topics: topics,
|
|
||||||
data: data.to_vec()
|
|
||||||
});
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ret(self, _gas: &U256, _data: &ReturnData) -> evm::Result<U256> {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn suicide(&mut self, refund_address: &Address) -> evm::Result<()> {
|
|
||||||
self.suicides.insert(refund_address.clone());
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn schedule(&self) -> &Schedule {
|
|
||||||
&self.schedule
|
|
||||||
}
|
|
||||||
|
|
||||||
fn env_info(&self) -> &EnvInfo {
|
|
||||||
&self.info
|
|
||||||
}
|
|
||||||
|
|
||||||
fn depth(&self) -> usize {
|
|
||||||
self.depth
|
|
||||||
}
|
|
||||||
|
|
||||||
fn inc_sstore_clears(&mut self) {
|
|
||||||
self.sstore_clears += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_stack_underflow() {
|
|
||||||
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
|
||||||
let code = "01600055".from_hex().unwrap();
|
|
||||||
|
|
||||||
let mut params = ActionParams::default();
|
|
||||||
params.address = address.clone();
|
|
||||||
params.gas = U256::from(100_000);
|
|
||||||
params.code = Some(Arc::new(code));
|
|
||||||
let mut ext = FakeExt::new();
|
|
||||||
|
|
||||||
let err = {
|
|
||||||
let mut vm : Box<evm::Evm> = Box::new(super::interpreter::Interpreter::<usize>::new(Arc::new(super::interpreter::SharedCache::default())));
|
|
||||||
test_finalize(vm.exec(params, &mut ext)).unwrap_err()
|
|
||||||
};
|
|
||||||
|
|
||||||
match err {
|
|
||||||
evm::Error::StackUnderflow {wanted, on_stack, ..} => {
|
|
||||||
assert_eq!(wanted, 2);
|
|
||||||
assert_eq!(on_stack, 0);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
assert!(false, "Expected StackUndeflow")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
evm_test!{test_add: test_add_jit, test_add_int}
|
evm_test!{test_add: test_add_jit, test_add_int}
|
||||||
fn test_add(factory: super::Factory) {
|
fn test_add(factory: super::Factory) {
|
||||||
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||||
@ -849,7 +654,7 @@ fn test_badinstruction_int() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match err {
|
match err {
|
||||||
evm::Error::BadInstruction { instruction: 0xaf } => (),
|
vm::Error::BadInstruction { instruction: 0xaf } => (),
|
||||||
_ => assert!(false, "Expected bad instruction")
|
_ => assert!(false, "Expected bad instruction")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ ethcore-io = { path = "../../util/io" }
|
|||||||
ethcore-ipc = { path = "../../ipc/rpc", optional = true }
|
ethcore-ipc = { path = "../../ipc/rpc", optional = true }
|
||||||
ethcore-devtools = { path = "../../devtools" }
|
ethcore-devtools = { path = "../../devtools" }
|
||||||
evm = { path = "../evm" }
|
evm = { path = "../evm" }
|
||||||
|
vm = { path = "../vm" }
|
||||||
rlp = { path = "../../util/rlp" }
|
rlp = { path = "../../util/rlp" }
|
||||||
time = "0.1"
|
time = "0.1"
|
||||||
smallvec = "0.4"
|
smallvec = "0.4"
|
||||||
|
@ -80,6 +80,7 @@ extern crate serde;
|
|||||||
extern crate smallvec;
|
extern crate smallvec;
|
||||||
extern crate stats;
|
extern crate stats;
|
||||||
extern crate time;
|
extern crate time;
|
||||||
|
extern crate vm;
|
||||||
|
|
||||||
#[cfg(feature = "ipc")]
|
#[cfg(feature = "ipc")]
|
||||||
extern crate ethcore_ipc as ipc;
|
extern crate ethcore_ipc as ipc;
|
||||||
|
@ -24,7 +24,7 @@ use ethcore::engines::Engine;
|
|||||||
use ethcore::receipt::Receipt;
|
use ethcore::receipt::Receipt;
|
||||||
use ethcore::state::{self, ProvedExecution};
|
use ethcore::state::{self, ProvedExecution};
|
||||||
use ethcore::transaction::SignedTransaction;
|
use ethcore::transaction::SignedTransaction;
|
||||||
use evm::env_info::EnvInfo;
|
use vm::EnvInfo;
|
||||||
|
|
||||||
use request::{self as net_request, IncompleteRequest, CompleteRequest, Output, OutputKind, Field};
|
use request::{self as net_request, IncompleteRequest, CompleteRequest, Output, OutputKind, Field};
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
"networkID" : "0x2"
|
"networkID" : "0x2"
|
||||||
},
|
},
|
||||||
"genesis": {
|
"genesis": {
|
||||||
"gasLimitBoundDivisor": "0x0400",
|
|
||||||
"seal": {
|
"seal": {
|
||||||
"generic": "0x"
|
"generic": "0x"
|
||||||
},
|
},
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"engine": {
|
"engine": {
|
||||||
"basicAuthority": {
|
"basicAuthority": {
|
||||||
"params": {
|
"params": {
|
||||||
"gasLimitBoundDivisor": "0x0400",
|
|
||||||
"durationLimit": "0x0d",
|
"durationLimit": "0x0d",
|
||||||
"validators": {
|
"validators": {
|
||||||
"safeContract": "0x0000000000000000000000000000000000000005"
|
"safeContract": "0x0000000000000000000000000000000000000005"
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! DB backend wrapper for Account trie
|
//! DB backend wrapper for Account trie
|
||||||
|
use std::collections::HashMap;
|
||||||
use util::*;
|
use util::*;
|
||||||
use rlp::NULL_RLP;
|
use rlp::NULL_RLP;
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ use util::{Bytes, Address, Hashable, U256, H256, ordered_trie_root, SHA3_NULL_RL
|
|||||||
use util::error::{Mismatch, OutOfBounds};
|
use util::error::{Mismatch, OutOfBounds};
|
||||||
|
|
||||||
use basic_types::{LogBloom, Seal};
|
use basic_types::{LogBloom, Seal};
|
||||||
use evm::env_info::{EnvInfo, LastHashes};
|
use vm::{EnvInfo, LastHashes};
|
||||||
use engines::Engine;
|
use engines::Engine;
|
||||||
use error::{Error, BlockError, TransactionError};
|
use error::{Error, BlockError, TransactionError};
|
||||||
use factory::Factories;
|
use factory::Factories;
|
||||||
@ -680,7 +680,7 @@ mod tests {
|
|||||||
use tests::helpers::*;
|
use tests::helpers::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
use engines::Engine;
|
use engines::Engine;
|
||||||
use evm::env_info::LastHashes;
|
use vm::LastHashes;
|
||||||
use error::Error;
|
use error::Error;
|
||||||
use header::Header;
|
use header::Header;
|
||||||
use factory::Factories;
|
use factory::Factories;
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
//! Blockchain database.
|
//! Blockchain database.
|
||||||
|
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::mem;
|
||||||
use bloomchain as bc;
|
use bloomchain as bc;
|
||||||
use util::*;
|
use util::*;
|
||||||
use rlp::*;
|
use rlp::*;
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
//! Blockchain DB extras.
|
//! Blockchain DB extras.
|
||||||
|
|
||||||
|
use std::ops;
|
||||||
|
use std::io::Write;
|
||||||
use bloomchain;
|
use bloomchain;
|
||||||
use blooms::{GroupPosition, BloomGroup};
|
use blooms::{GroupPosition, BloomGroup};
|
||||||
use db::Key;
|
use db::Key;
|
||||||
@ -56,7 +58,7 @@ fn with_index(hash: &H256, i: ExtrasIndex) -> H264 {
|
|||||||
|
|
||||||
pub struct BlockNumberKey([u8; 5]);
|
pub struct BlockNumberKey([u8; 5]);
|
||||||
|
|
||||||
impl Deref for BlockNumberKey {
|
impl ops::Deref for BlockNumberKey {
|
||||||
type Target = [u8];
|
type Target = [u8];
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
@ -88,7 +90,7 @@ impl Key<BlockDetails> for H256 {
|
|||||||
|
|
||||||
pub struct LogGroupKey([u8; 6]);
|
pub struct LogGroupKey([u8; 6]);
|
||||||
|
|
||||||
impl Deref for LogGroupKey {
|
impl ops::Deref for LogGroupKey {
|
||||||
type Target = [u8];
|
type Target = [u8];
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
@ -160,7 +162,8 @@ pub const EPOCH_KEY_PREFIX: &'static [u8; DB_PREFIX_LEN] = &[
|
|||||||
];
|
];
|
||||||
|
|
||||||
pub struct EpochTransitionsKey([u8; EPOCH_KEY_LEN]);
|
pub struct EpochTransitionsKey([u8; EPOCH_KEY_LEN]);
|
||||||
impl Deref for EpochTransitionsKey {
|
|
||||||
|
impl ops::Deref for EpochTransitionsKey {
|
||||||
type Target = [u8];
|
type Target = [u8];
|
||||||
|
|
||||||
fn deref(&self) -> &[u8] { &self.0[..] }
|
fn deref(&self) -> &[u8] { &self.0[..] }
|
||||||
|
@ -36,9 +36,9 @@ impl From<&'static str> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<::evm::Error> for Error {
|
impl Into<::vm::Error> for Error {
|
||||||
fn into(self) -> ::evm::Error {
|
fn into(self) -> ::vm::Error {
|
||||||
::evm::Error::BuiltIn(self.0)
|
::vm::Error::BuiltIn(self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,9 +42,8 @@ use client::{
|
|||||||
};
|
};
|
||||||
use encoded;
|
use encoded;
|
||||||
use engines::{Engine, EpochTransition};
|
use engines::{Engine, EpochTransition};
|
||||||
use evm::env_info::EnvInfo;
|
|
||||||
use evm::env_info::LastHashes;
|
|
||||||
use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError};
|
use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError};
|
||||||
|
use vm::{EnvInfo, LastHashes};
|
||||||
use evm::{Factory as EvmFactory, Schedule};
|
use evm::{Factory as EvmFactory, Schedule};
|
||||||
use executive::{Executive, Executed, TransactOptions, contract_address};
|
use executive::{Executive, Executed, TransactOptions, contract_address};
|
||||||
use factory::Factories;
|
use factory::Factories;
|
||||||
|
@ -23,7 +23,7 @@ use util::kvdb::{self, KeyValueDB};
|
|||||||
use {state, state_db, client, executive, trace, db, spec};
|
use {state, state_db, client, executive, trace, db, spec};
|
||||||
use factory::Factories;
|
use factory::Factories;
|
||||||
use evm::{self, VMType};
|
use evm::{self, VMType};
|
||||||
use evm::action_params::ActionParams;
|
use vm::{self, ActionParams};
|
||||||
|
|
||||||
/// EVM test Error.
|
/// EVM test Error.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -31,7 +31,7 @@ pub enum EvmTestError {
|
|||||||
/// Trie integrity error.
|
/// Trie integrity error.
|
||||||
Trie(util::TrieError),
|
Trie(util::TrieError),
|
||||||
/// EVM error.
|
/// EVM error.
|
||||||
Evm(evm::Error),
|
Evm(vm::Error),
|
||||||
/// Initialization error.
|
/// Initialization error.
|
||||||
Initialization(::error::Error),
|
Initialization(::error::Error),
|
||||||
/// Low-level database error.
|
/// Low-level database error.
|
||||||
|
@ -40,7 +40,7 @@ pub use types::pruning_info::PruningInfo;
|
|||||||
pub use types::call_analytics::CallAnalytics;
|
pub use types::call_analytics::CallAnalytics;
|
||||||
|
|
||||||
pub use executive::{Executed, Executive, TransactOptions};
|
pub use executive::{Executed, Executive, TransactOptions};
|
||||||
pub use evm::env_info::{LastHashes, EnvInfo};
|
pub use vm::{LastHashes, EnvInfo};
|
||||||
|
|
||||||
pub use error::{BlockImportError, TransactionImportError, TransactionImportResult};
|
pub use error::{BlockImportError, TransactionImportError, TransactionImportResult};
|
||||||
pub use verification::VerifierType;
|
pub use verification::VerifierType;
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
//! Test client.
|
//! Test client.
|
||||||
|
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrder};
|
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrder};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::collections::{HashMap, BTreeMap};
|
||||||
|
use std::mem;
|
||||||
use rustc_hex::FromHex;
|
use rustc_hex::FromHex;
|
||||||
use util::*;
|
use util::*;
|
||||||
use rlp::*;
|
use rlp::*;
|
||||||
@ -36,7 +39,8 @@ use log_entry::LocalizedLogEntry;
|
|||||||
use receipt::{Receipt, LocalizedReceipt};
|
use receipt::{Receipt, LocalizedReceipt};
|
||||||
use blockchain::extras::BlockReceipts;
|
use blockchain::extras::BlockReceipts;
|
||||||
use error::{ImportResult, Error as EthcoreError};
|
use error::{ImportResult, Error as EthcoreError};
|
||||||
use evm::{Factory as EvmFactory, VMType, Schedule};
|
use evm::{Factory as EvmFactory, VMType};
|
||||||
|
use vm::Schedule;
|
||||||
use miner::{Miner, MinerService, TransactionImportResult};
|
use miner::{Miner, MinerService, TransactionImportResult};
|
||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
use types::basic_account::BasicAccount;
|
use types::basic_account::BasicAccount;
|
||||||
|
@ -19,7 +19,7 @@ use std::collections::BTreeMap;
|
|||||||
use block::{OpenBlock, SealedBlock, ClosedBlock};
|
use block::{OpenBlock, SealedBlock, ClosedBlock};
|
||||||
use blockchain::TreeRoute;
|
use blockchain::TreeRoute;
|
||||||
use encoded;
|
use encoded;
|
||||||
use evm::env_info::LastHashes;
|
use vm::LastHashes;
|
||||||
use error::{ImportResult, CallError, Error as EthcoreError};
|
use error::{ImportResult, CallError, Error as EthcoreError};
|
||||||
use error::{TransactionImportResult, BlockImportError};
|
use error::{TransactionImportResult, BlockImportError};
|
||||||
use evm::{Factory as EvmFactory, Schedule};
|
use evm::{Factory as EvmFactory, Schedule};
|
||||||
|
@ -17,8 +17,10 @@
|
|||||||
//! A blockchain engine that supports a non-instant BFT proof-of-authority.
|
//! A blockchain engine that supports a non-instant BFT proof-of-authority.
|
||||||
|
|
||||||
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering};
|
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering};
|
||||||
use std::sync::Weak;
|
use std::sync::{Weak, Arc};
|
||||||
use std::time::{UNIX_EPOCH, Duration};
|
use std::time::{UNIX_EPOCH, Duration};
|
||||||
|
use std::collections::{BTreeMap, HashSet, HashMap};
|
||||||
|
use std::cmp;
|
||||||
|
|
||||||
use account_provider::AccountProvider;
|
use account_provider::AccountProvider;
|
||||||
use block::*;
|
use block::*;
|
||||||
@ -446,9 +448,9 @@ impl Engine for AuthorityRound {
|
|||||||
let gas_limit = parent.gas_limit().clone();
|
let gas_limit = parent.gas_limit().clone();
|
||||||
let bound_divisor = self.params().gas_limit_bound_divisor;
|
let bound_divisor = self.params().gas_limit_bound_divisor;
|
||||||
if gas_limit < gas_floor_target {
|
if gas_limit < gas_floor_target {
|
||||||
min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into())
|
cmp::min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into())
|
||||||
} else {
|
} else {
|
||||||
max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1.into())
|
cmp::max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1.into())
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -515,7 +517,7 @@ impl Engine for AuthorityRound {
|
|||||||
fn on_new_block(
|
fn on_new_block(
|
||||||
&self,
|
&self,
|
||||||
block: &mut ExecutedBlock,
|
block: &mut ExecutedBlock,
|
||||||
last_hashes: Arc<::evm::env_info::LastHashes>,
|
last_hashes: Arc<::vm::LastHashes>,
|
||||||
epoch_begin: bool,
|
epoch_begin: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let parent_hash = block.fields().header.parent_hash().clone();
|
let parent_hash = block.fields().header.parent_hash().clone();
|
||||||
@ -813,7 +815,7 @@ impl Engine for AuthorityRound {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_transaction_basic(&self, t: &UnverifiedTransaction, header: &Header) -> result::Result<(), Error> {
|
fn verify_transaction_basic(&self, t: &UnverifiedTransaction, header: &Header) -> Result<(), Error> {
|
||||||
t.check_low_s()?;
|
t.check_low_s()?;
|
||||||
|
|
||||||
if let Some(n) = t.network_id() {
|
if let Some(n) = t.network_id() {
|
||||||
@ -849,6 +851,7 @@ impl Engine for AuthorityRound {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
|
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
|
||||||
use util::*;
|
use util::*;
|
||||||
use header::Header;
|
use header::Header;
|
||||||
@ -939,10 +942,10 @@ mod tests {
|
|||||||
let addr = tap.insert_account("0".sha3().into(), "0").unwrap();
|
let addr = tap.insert_account("0".sha3().into(), "0").unwrap();
|
||||||
let mut parent_header: Header = Header::default();
|
let mut parent_header: Header = Header::default();
|
||||||
parent_header.set_seal(vec![encode(&0usize).into_vec()]);
|
parent_header.set_seal(vec![encode(&0usize).into_vec()]);
|
||||||
parent_header.set_gas_limit(U256::from_str("222222").unwrap());
|
parent_header.set_gas_limit("222222".parse::<U256>().unwrap());
|
||||||
let mut header: Header = Header::default();
|
let mut header: Header = Header::default();
|
||||||
header.set_number(1);
|
header.set_number(1);
|
||||||
header.set_gas_limit(U256::from_str("222222").unwrap());
|
header.set_gas_limit("222222".parse::<U256>().unwrap());
|
||||||
header.set_author(addr);
|
header.set_author(addr);
|
||||||
|
|
||||||
let engine = Spec::new_test_round().engine;
|
let engine = Spec::new_test_round().engine;
|
||||||
@ -965,10 +968,10 @@ mod tests {
|
|||||||
|
|
||||||
let mut parent_header: Header = Header::default();
|
let mut parent_header: Header = Header::default();
|
||||||
parent_header.set_seal(vec![encode(&0usize).into_vec()]);
|
parent_header.set_seal(vec![encode(&0usize).into_vec()]);
|
||||||
parent_header.set_gas_limit(U256::from_str("222222").unwrap());
|
parent_header.set_gas_limit("222222".parse::<U256>().unwrap());
|
||||||
let mut header: Header = Header::default();
|
let mut header: Header = Header::default();
|
||||||
header.set_number(1);
|
header.set_number(1);
|
||||||
header.set_gas_limit(U256::from_str("222222").unwrap());
|
header.set_gas_limit("222222".parse::<U256>().unwrap());
|
||||||
header.set_author(addr);
|
header.set_author(addr);
|
||||||
|
|
||||||
let engine = Spec::new_test_round().engine;
|
let engine = Spec::new_test_round().engine;
|
||||||
@ -991,10 +994,10 @@ mod tests {
|
|||||||
|
|
||||||
let mut parent_header: Header = Header::default();
|
let mut parent_header: Header = Header::default();
|
||||||
parent_header.set_seal(vec![encode(&4usize).into_vec()]);
|
parent_header.set_seal(vec![encode(&4usize).into_vec()]);
|
||||||
parent_header.set_gas_limit(U256::from_str("222222").unwrap());
|
parent_header.set_gas_limit("222222".parse::<U256>().unwrap());
|
||||||
let mut header: Header = Header::default();
|
let mut header: Header = Header::default();
|
||||||
header.set_number(1);
|
header.set_number(1);
|
||||||
header.set_gas_limit(U256::from_str("222222").unwrap());
|
header.set_gas_limit("222222".parse::<U256>().unwrap());
|
||||||
header.set_author(addr);
|
header.set_author(addr);
|
||||||
|
|
||||||
let engine = Spec::new_test_round().engine;
|
let engine = Spec::new_test_round().engine;
|
||||||
@ -1028,10 +1031,10 @@ mod tests {
|
|||||||
|
|
||||||
let mut parent_header: Header = Header::default();
|
let mut parent_header: Header = Header::default();
|
||||||
parent_header.set_seal(vec![encode(&1usize).into_vec()]);
|
parent_header.set_seal(vec![encode(&1usize).into_vec()]);
|
||||||
parent_header.set_gas_limit(U256::from_str("222222").unwrap());
|
parent_header.set_gas_limit("222222".parse::<U256>().unwrap());
|
||||||
let mut header: Header = Header::default();
|
let mut header: Header = Header::default();
|
||||||
header.set_number(1);
|
header.set_number(1);
|
||||||
header.set_gas_limit(U256::from_str("222222").unwrap());
|
header.set_gas_limit("222222".parse::<U256>().unwrap());
|
||||||
header.set_seal(vec![encode(&3usize).into_vec()]);
|
header.set_seal(vec![encode(&3usize).into_vec()]);
|
||||||
|
|
||||||
// Do not report when signer not present.
|
// Do not report when signer not present.
|
||||||
|
@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
//! A blockchain engine that supports a basic, non-BFT proof-of-authority.
|
//! A blockchain engine that supports a basic, non-BFT proof-of-authority.
|
||||||
|
|
||||||
use std::sync::Weak;
|
use std::sync::{Weak, Arc};
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::cmp;
|
||||||
use util::*;
|
use util::*;
|
||||||
use ethkey::{recover, public_to_address, Signature};
|
use ethkey::{recover, public_to_address, Signature};
|
||||||
use account_provider::AccountProvider;
|
use account_provider::AccountProvider;
|
||||||
@ -116,9 +118,9 @@ impl Engine for BasicAuthority {
|
|||||||
let gas_limit = parent.gas_limit().clone();
|
let gas_limit = parent.gas_limit().clone();
|
||||||
let bound_divisor = self.params().gas_limit_bound_divisor;
|
let bound_divisor = self.params().gas_limit_bound_divisor;
|
||||||
if gas_limit < gas_floor_target {
|
if gas_limit < gas_floor_target {
|
||||||
min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into())
|
cmp::min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into())
|
||||||
} else {
|
} else {
|
||||||
max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1.into())
|
cmp::max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1.into())
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -142,7 +144,7 @@ impl Engine for BasicAuthority {
|
|||||||
Seal::None
|
Seal::None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
|
fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
|
||||||
// check the seal fields.
|
// check the seal fields.
|
||||||
// TODO: pull this out into common code.
|
// TODO: pull this out into common code.
|
||||||
if header.seal().len() != self.seal_fields() {
|
if header.seal().len() != self.seal_fields() {
|
||||||
@ -153,11 +155,11 @@ impl Engine for BasicAuthority {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_block_unordered(&self, _header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
|
fn verify_block_unordered(&self, _header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
|
fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
|
||||||
// Do not calculate difficulty for genesis blocks.
|
// Do not calculate difficulty for genesis blocks.
|
||||||
if header.number() == 0 {
|
if header.number() == 0 {
|
||||||
return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() })));
|
return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() })));
|
||||||
@ -249,6 +251,7 @@ impl Engine for BasicAuthority {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::sync::Arc;
|
||||||
use util::*;
|
use util::*;
|
||||||
use block::*;
|
use block::*;
|
||||||
use error::{BlockError, Error};
|
use error::{BlockError, Error};
|
||||||
|
@ -14,8 +14,8 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::{BTreeMap, HashMap};
|
||||||
use util::{Address, HashMap};
|
use util::Address;
|
||||||
use builtin::Builtin;
|
use builtin::Builtin;
|
||||||
use engines::{Engine, Seal};
|
use engines::{Engine, Seal};
|
||||||
use spec::CommonParams;
|
use spec::CommonParams;
|
||||||
@ -63,6 +63,7 @@ impl Engine for InstantSeal {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::sync::Arc;
|
||||||
use util::*;
|
use util::*;
|
||||||
use tests::helpers::*;
|
use tests::helpers::*;
|
||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
|
@ -35,7 +35,9 @@ pub use self::instant_seal::InstantSeal;
|
|||||||
pub use self::null_engine::NullEngine;
|
pub use self::null_engine::NullEngine;
|
||||||
pub use self::tendermint::Tendermint;
|
pub use self::tendermint::Tendermint;
|
||||||
|
|
||||||
use std::sync::Weak;
|
use std::sync::{Weak, Arc};
|
||||||
|
use std::collections::{BTreeMap, HashMap};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
use self::epoch::PendingTransition;
|
use self::epoch::PendingTransition;
|
||||||
|
|
||||||
@ -43,16 +45,14 @@ use account_provider::AccountProvider;
|
|||||||
use block::ExecutedBlock;
|
use block::ExecutedBlock;
|
||||||
use builtin::Builtin;
|
use builtin::Builtin;
|
||||||
use client::Client;
|
use client::Client;
|
||||||
use evm::env_info::{EnvInfo, LastHashes};
|
use vm::{EnvInfo, LastHashes, Schedule, CreateContractAddress};
|
||||||
use error::Error;
|
use error::Error;
|
||||||
use evm::Schedule;
|
|
||||||
use header::{Header, BlockNumber};
|
use header::{Header, BlockNumber};
|
||||||
use receipt::Receipt;
|
use receipt::Receipt;
|
||||||
use trace::FlatTrace;
|
use trace::FlatTrace;
|
||||||
use snapshot::SnapshotComponents;
|
use snapshot::SnapshotComponents;
|
||||||
use spec::CommonParams;
|
use spec::CommonParams;
|
||||||
use transaction::{UnverifiedTransaction, SignedTransaction};
|
use transaction::{UnverifiedTransaction, SignedTransaction};
|
||||||
use evm::CreateContractAddress;
|
|
||||||
|
|
||||||
use ethkey::Signature;
|
use ethkey::Signature;
|
||||||
use util::*;
|
use util::*;
|
||||||
@ -401,13 +401,12 @@ pub trait Engine : Sync + Send {
|
|||||||
|
|
||||||
/// Common engine utilities
|
/// Common engine utilities
|
||||||
pub mod common {
|
pub mod common {
|
||||||
|
use std::sync::Arc;
|
||||||
use block::ExecutedBlock;
|
use block::ExecutedBlock;
|
||||||
use evm::env_info::{EnvInfo, LastHashes};
|
|
||||||
use error::Error;
|
use error::Error;
|
||||||
use transaction::SYSTEM_ADDRESS;
|
use transaction::SYSTEM_ADDRESS;
|
||||||
use executive::Executive;
|
use executive::Executive;
|
||||||
use evm::CallType;
|
use vm::{CallType, ActionParams, ActionValue, EnvInfo, LastHashes};
|
||||||
use evm::action_params::{ActionParams, ActionValue};
|
|
||||||
use trace::{NoopTracer, NoopVMTracer};
|
use trace::{NoopTracer, NoopVMTracer};
|
||||||
use state::Substate;
|
use state::Substate;
|
||||||
|
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
|
|
||||||
//! A signer used by Engines which need to sign messages.
|
//! A signer used by Engines which need to sign messages.
|
||||||
|
|
||||||
use util::{Arc, H256, Address};
|
use std::sync::Arc;
|
||||||
|
use util::{H256, Address};
|
||||||
use ethkey::Signature;
|
use ethkey::Signature;
|
||||||
use account_provider::{self, AccountProvider};
|
use account_provider::{self, AccountProvider};
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
//! Tendermint message handling.
|
//! Tendermint message handling.
|
||||||
|
|
||||||
|
use std::cmp;
|
||||||
use util::*;
|
use util::*;
|
||||||
use super::{Height, View, BlockHash, Step};
|
use super::{Height, View, BlockHash, Step};
|
||||||
use error::Error;
|
use error::Error;
|
||||||
@ -110,13 +111,13 @@ impl Default for VoteStep {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for VoteStep {
|
impl PartialOrd for VoteStep {
|
||||||
fn partial_cmp(&self, m: &VoteStep) -> Option<Ordering> {
|
fn partial_cmp(&self, m: &VoteStep) -> Option<cmp::Ordering> {
|
||||||
Some(self.cmp(m))
|
Some(self.cmp(m))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for VoteStep {
|
impl Ord for VoteStep {
|
||||||
fn cmp(&self, m: &VoteStep) -> Ordering {
|
fn cmp(&self, m: &VoteStep) -> cmp::Ordering {
|
||||||
if self.height != m.height {
|
if self.height != m.height {
|
||||||
self.height.cmp(&m.height)
|
self.height.cmp(&m.height)
|
||||||
} else if self.view != m.view {
|
} else if self.view != m.view {
|
||||||
@ -198,6 +199,7 @@ pub fn message_hash(vote_step: VoteStep, block_hash: H256) -> H256 {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::sync::Arc;
|
||||||
use util::*;
|
use util::*;
|
||||||
use rlp::*;
|
use rlp::*;
|
||||||
use account_provider::AccountProvider;
|
use account_provider::AccountProvider;
|
||||||
|
@ -25,8 +25,10 @@
|
|||||||
mod message;
|
mod message;
|
||||||
mod params;
|
mod params;
|
||||||
|
|
||||||
use std::sync::Weak;
|
use std::sync::{Weak, Arc};
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
|
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
|
||||||
|
use std::collections::{HashSet, BTreeMap, HashMap};
|
||||||
|
use std::cmp;
|
||||||
use util::*;
|
use util::*;
|
||||||
use client::{Client, EngineClient};
|
use client::{Client, EngineClient};
|
||||||
use error::{Error, BlockError};
|
use error::{Error, BlockError};
|
||||||
@ -470,9 +472,9 @@ impl Engine for Tendermint {
|
|||||||
let gas_limit = parent.gas_limit().clone();
|
let gas_limit = parent.gas_limit().clone();
|
||||||
let bound_divisor = self.params().gas_limit_bound_divisor;
|
let bound_divisor = self.params().gas_limit_bound_divisor;
|
||||||
if gas_limit < gas_floor_target {
|
if gas_limit < gas_floor_target {
|
||||||
min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into())
|
cmp::min(gas_floor_target, gas_limit + gas_limit / bound_divisor - 1.into())
|
||||||
} else {
|
} else {
|
||||||
max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1.into())
|
cmp::max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1.into())
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -783,6 +785,7 @@ impl Engine for Tendermint {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::str::FromStr;
|
||||||
use rustc_hex::FromHex;
|
use rustc_hex::FromHex;
|
||||||
use util::*;
|
use util::*;
|
||||||
use block::*;
|
use block::*;
|
||||||
|
@ -126,6 +126,7 @@ impl ValidatorSet for ValidatorContract {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::sync::Arc;
|
||||||
use rustc_hex::FromHex;
|
use rustc_hex::FromHex;
|
||||||
use util::*;
|
use util::*;
|
||||||
use rlp::encode;
|
use rlp::encode;
|
||||||
@ -142,11 +143,11 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn fetches_validators() {
|
fn fetches_validators() {
|
||||||
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_contract, None);
|
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_contract, None);
|
||||||
let vc = Arc::new(ValidatorContract::new(Address::from_str("0000000000000000000000000000000000000005").unwrap()));
|
let vc = Arc::new(ValidatorContract::new("0000000000000000000000000000000000000005".parse::<Address>().unwrap()));
|
||||||
vc.register_contract(Arc::downgrade(&client));
|
vc.register_contract(Arc::downgrade(&client));
|
||||||
let last_hash = client.best_block_header().hash();
|
let last_hash = client.best_block_header().hash();
|
||||||
assert!(vc.contains(&last_hash, &Address::from_str("7d577a597b2742b498cb5cf0c26cdcd726d39e6e").unwrap()));
|
assert!(vc.contains(&last_hash, &"7d577a597b2742b498cb5cf0c26cdcd726d39e6e".parse::<Address>().unwrap()));
|
||||||
assert!(vc.contains(&last_hash, &Address::from_str("82a978b3f5962a5b0957d9ee9eef472ee55b42f1").unwrap()));
|
assert!(vc.contains(&last_hash, &"82a978b3f5962a5b0957d9ee9eef472ee55b42f1".parse::<Address>().unwrap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -155,7 +156,7 @@ mod tests {
|
|||||||
let v1 = tap.insert_account("1".sha3().into(), "").unwrap();
|
let v1 = tap.insert_account("1".sha3().into(), "").unwrap();
|
||||||
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_contract, Some(tap.clone()));
|
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_contract, Some(tap.clone()));
|
||||||
client.engine().register_client(Arc::downgrade(&client));
|
client.engine().register_client(Arc::downgrade(&client));
|
||||||
let validator_contract = Address::from_str("0000000000000000000000000000000000000005").unwrap();
|
let validator_contract = "0000000000000000000000000000000000000005".parse::<Address>().unwrap();
|
||||||
|
|
||||||
// Make sure reporting can be done.
|
// Make sure reporting can be done.
|
||||||
client.miner().set_gas_floor_target(1_000_000.into());
|
client.miner().set_gas_floor_target(1_000_000.into());
|
||||||
|
@ -142,6 +142,8 @@ impl ValidatorSet for Multi {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use account_provider::AccountProvider;
|
use account_provider::AccountProvider;
|
||||||
use client::{BlockChainClient, EngineClient};
|
use client::{BlockChainClient, EngineClient};
|
||||||
use engines::EpochChange;
|
use engines::EpochChange;
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
/// Validator set maintained in a contract, updated using `getValidators` method.
|
/// Validator set maintained in a contract, updated using `getValidators` method.
|
||||||
|
|
||||||
use std::sync::Weak;
|
use std::sync::{Weak, Arc};
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
use native_contracts::ValidatorSet as Provider;
|
use native_contracts::ValidatorSet as Provider;
|
||||||
|
|
||||||
@ -299,7 +299,7 @@ impl ValidatorSet for ValidatorSafeContract {
|
|||||||
let (old_header, state_items) = decode_first_proof(&rlp)?;
|
let (old_header, state_items) = decode_first_proof(&rlp)?;
|
||||||
let old_hash = old_header.hash();
|
let old_hash = old_header.hash();
|
||||||
|
|
||||||
let env_info = ::evm::env_info::EnvInfo {
|
let env_info = ::vm::EnvInfo {
|
||||||
number: old_header.number(),
|
number: old_header.number(),
|
||||||
author: *old_header.author(),
|
author: *old_header.author(),
|
||||||
difficulty: *old_header.difficulty(),
|
difficulty: *old_header.difficulty(),
|
||||||
@ -422,6 +422,7 @@ impl ValidatorSet for ValidatorSafeContract {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::sync::Arc;
|
||||||
use rustc_hex::FromHex;
|
use rustc_hex::FromHex;
|
||||||
use util::*;
|
use util::*;
|
||||||
use types::ids::BlockId;
|
use types::ids::BlockId;
|
||||||
@ -438,11 +439,11 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn fetches_validators() {
|
fn fetches_validators() {
|
||||||
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_safe_contract, None);
|
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_safe_contract, None);
|
||||||
let vc = Arc::new(ValidatorSafeContract::new(Address::from_str("0000000000000000000000000000000000000005").unwrap()));
|
let vc = Arc::new(ValidatorSafeContract::new("0000000000000000000000000000000000000005".parse::<Address>().unwrap()));
|
||||||
vc.register_contract(Arc::downgrade(&client));
|
vc.register_contract(Arc::downgrade(&client));
|
||||||
let last_hash = client.best_block_header().hash();
|
let last_hash = client.best_block_header().hash();
|
||||||
assert!(vc.contains(&last_hash, &Address::from_str("7d577a597b2742b498cb5cf0c26cdcd726d39e6e").unwrap()));
|
assert!(vc.contains(&last_hash, &"7d577a597b2742b498cb5cf0c26cdcd726d39e6e".parse::<Address>().unwrap()));
|
||||||
assert!(vc.contains(&last_hash, &Address::from_str("82a978b3f5962a5b0957d9ee9eef472ee55b42f1").unwrap()));
|
assert!(vc.contains(&last_hash, &"82a978b3f5962a5b0957d9ee9eef472ee55b42f1".parse::<Address>().unwrap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -454,7 +455,7 @@ mod tests {
|
|||||||
let network_id = Spec::new_validator_safe_contract().network_id();
|
let network_id = Spec::new_validator_safe_contract().network_id();
|
||||||
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_safe_contract, Some(tap));
|
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_safe_contract, Some(tap));
|
||||||
client.engine().register_client(Arc::downgrade(&client));
|
client.engine().register_client(Arc::downgrade(&client));
|
||||||
let validator_contract = Address::from_str("0000000000000000000000000000000000000005").unwrap();
|
let validator_contract = "0000000000000000000000000000000000000005".parse::<Address>().unwrap();
|
||||||
|
|
||||||
client.miner().set_engine_signer(v1, "".into()).unwrap();
|
client.miner().set_engine_signer(v1, "".into()).unwrap();
|
||||||
// Remove "1" validator.
|
// Remove "1" validator.
|
||||||
@ -520,7 +521,7 @@ mod tests {
|
|||||||
|
|
||||||
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_safe_contract, None);
|
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_safe_contract, None);
|
||||||
let engine = client.engine().clone();
|
let engine = client.engine().clone();
|
||||||
let validator_contract = Address::from_str("0000000000000000000000000000000000000005").unwrap();
|
let validator_contract = "0000000000000000000000000000000000000005".parse::<Address>().unwrap();
|
||||||
|
|
||||||
let last_hash = client.best_block_header().hash();
|
let last_hash = client.best_block_header().hash();
|
||||||
let mut new_header = Header::default();
|
let mut new_header = Header::default();
|
||||||
|
@ -17,8 +17,9 @@
|
|||||||
/// Used for Engine testing.
|
/// Used for Engine testing.
|
||||||
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
|
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
|
||||||
use util::{Arc, Bytes, H256, Address, HeapSizeOf};
|
use util::{Bytes, H256, Address, HeapSizeOf};
|
||||||
|
|
||||||
use engines::{Call, Engine};
|
use engines::{Call, Engine};
|
||||||
use header::{Header, BlockNumber};
|
use header::{Header, BlockNumber};
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
//! Collects votes on hashes at each Message::Round.
|
//! Collects votes on hashes at each Message::Round.
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
use std::collections::{BTreeMap, HashSet, HashMap};
|
||||||
|
use std::hash::Hash;
|
||||||
use util::*;
|
use util::*;
|
||||||
use rlp::{Encodable, RlpStream};
|
use rlp::{Encodable, RlpStream};
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
//! General error types for use in ethcore.
|
//! General error types for use in ethcore.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
use util::*;
|
use util::*;
|
||||||
use io::*;
|
use io::*;
|
||||||
use header::BlockNumber;
|
use header::BlockNumber;
|
||||||
|
@ -15,11 +15,14 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::cmp;
|
||||||
|
use std::collections::{BTreeMap, HashMap};
|
||||||
|
use std::sync::Arc;
|
||||||
use ethash::{quick_get_difficulty, slow_get_seedhash, EthashManager};
|
use ethash::{quick_get_difficulty, slow_get_seedhash, EthashManager};
|
||||||
use util::*;
|
use util::*;
|
||||||
use block::*;
|
use block::*;
|
||||||
use builtin::Builtin;
|
use builtin::Builtin;
|
||||||
use evm::env_info::EnvInfo;
|
use vm::EnvInfo;
|
||||||
use error::{BlockError, Error, TransactionError};
|
use error::{BlockError, Error, TransactionError};
|
||||||
use trace::{Tracer, ExecutiveTracer,RewardType};
|
use trace::{Tracer, ExecutiveTracer,RewardType};
|
||||||
use header::{Header, BlockNumber};
|
use header::{Header, BlockNumber};
|
||||||
@ -30,7 +33,7 @@ use engines::{self, Engine, CloseOutcome};
|
|||||||
use evm::Schedule;
|
use evm::Schedule;
|
||||||
use ethjson;
|
use ethjson;
|
||||||
use rlp::{self, UntrustedRlp};
|
use rlp::{self, UntrustedRlp};
|
||||||
use evm::env_info::LastHashes;
|
use vm::LastHashes;
|
||||||
|
|
||||||
/// Parity tries to round block.gas_limit to multiple of this constant
|
/// Parity tries to round block.gas_limit to multiple of this constant
|
||||||
pub const PARITY_GAS_LIMIT_DETERMINANT: U256 = U256([37, 0, 0, 0]);
|
pub const PARITY_GAS_LIMIT_DETERMINANT: U256 = U256([37, 0, 0, 0]);
|
||||||
@ -224,15 +227,15 @@ impl Engine for Arc<Ethash> {
|
|||||||
let lower_limit = gas_limit - gas_limit / bound_divisor + 1.into();
|
let lower_limit = gas_limit - gas_limit / bound_divisor + 1.into();
|
||||||
let upper_limit = gas_limit + gas_limit / bound_divisor - 1.into();
|
let upper_limit = gas_limit + gas_limit / bound_divisor - 1.into();
|
||||||
let gas_limit = if gas_limit < gas_floor_target {
|
let gas_limit = if gas_limit < gas_floor_target {
|
||||||
let gas_limit = min(gas_floor_target, upper_limit);
|
let gas_limit = cmp::min(gas_floor_target, upper_limit);
|
||||||
round_block_gas_limit(gas_limit, lower_limit, upper_limit)
|
round_block_gas_limit(gas_limit, lower_limit, upper_limit)
|
||||||
} else if gas_limit > gas_ceil_target {
|
} else if gas_limit > gas_ceil_target {
|
||||||
let gas_limit = max(gas_ceil_target, lower_limit);
|
let gas_limit = cmp::max(gas_ceil_target, lower_limit);
|
||||||
round_block_gas_limit(gas_limit, lower_limit, upper_limit)
|
round_block_gas_limit(gas_limit, lower_limit, upper_limit)
|
||||||
} else {
|
} else {
|
||||||
let total_lower_limit = max(lower_limit, gas_floor_target);
|
let total_lower_limit = cmp::max(lower_limit, gas_floor_target);
|
||||||
let total_upper_limit = min(upper_limit, gas_ceil_target);
|
let total_upper_limit = cmp::min(upper_limit, gas_ceil_target);
|
||||||
let gas_limit = max(gas_floor_target, min(total_upper_limit,
|
let gas_limit = cmp::max(gas_floor_target, cmp::min(total_upper_limit,
|
||||||
lower_limit + (header.gas_used().clone() * 6.into() / 5.into()) / bound_divisor));
|
lower_limit + (header.gas_used().clone() * 6.into() / 5.into()) / bound_divisor));
|
||||||
round_block_gas_limit(gas_limit, total_lower_limit, total_upper_limit)
|
round_block_gas_limit(gas_limit, total_lower_limit, total_upper_limit)
|
||||||
};
|
};
|
||||||
@ -329,7 +332,7 @@ impl Engine for Arc<Ethash> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
|
fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
|
||||||
// check the seal fields.
|
// check the seal fields.
|
||||||
if header.seal().len() != self.seal_fields() {
|
if header.seal().len() != self.seal_fields() {
|
||||||
return Err(From::from(BlockError::InvalidSealArity(
|
return Err(From::from(BlockError::InvalidSealArity(
|
||||||
@ -367,7 +370,7 @@ impl Engine for Arc<Ethash> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
|
fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
|
||||||
if header.seal().len() != self.seal_fields() {
|
if header.seal().len() != self.seal_fields() {
|
||||||
return Err(From::from(BlockError::InvalidSealArity(
|
return Err(From::from(BlockError::InvalidSealArity(
|
||||||
Mismatch { expected: self.seal_fields(), found: header.seal().len() }
|
Mismatch { expected: self.seal_fields(), found: header.seal().len() }
|
||||||
@ -386,7 +389,7 @@ impl Engine for Arc<Ethash> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
|
fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
|
||||||
// we should not calculate difficulty for genesis blocks
|
// we should not calculate difficulty for genesis blocks
|
||||||
if header.number() == 0 {
|
if header.number() == 0 {
|
||||||
return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() })));
|
return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() })));
|
||||||
@ -410,7 +413,7 @@ impl Engine for Arc<Ethash> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_transaction_basic(&self, t: &UnverifiedTransaction, header: &Header) -> result::Result<(), Error> {
|
fn verify_transaction_basic(&self, t: &UnverifiedTransaction, header: &Header) -> Result<(), Error> {
|
||||||
if header.number() >= self.ethash_params.min_gas_price_transition && t.gas_price < self.ethash_params.min_gas_price {
|
if header.number() >= self.ethash_params.min_gas_price_transition && t.gas_price < self.ethash_params.min_gas_price {
|
||||||
return Err(TransactionError::InsufficientGasPrice { minimal: self.ethash_params.min_gas_price, got: t.gas_price }.into());
|
return Err(TransactionError::InsufficientGasPrice { minimal: self.ethash_params.min_gas_price, got: t.gas_price }.into());
|
||||||
}
|
}
|
||||||
@ -503,28 +506,28 @@ impl Ethash {
|
|||||||
if diff_inc <= threshold {
|
if diff_inc <= threshold {
|
||||||
*parent.difficulty() + *parent.difficulty() / difficulty_bound_divisor * (threshold - diff_inc).into()
|
*parent.difficulty() + *parent.difficulty() / difficulty_bound_divisor * (threshold - diff_inc).into()
|
||||||
} else {
|
} else {
|
||||||
let multiplier = min(diff_inc - threshold, 99).into();
|
let multiplier = cmp::min(diff_inc - threshold, 99).into();
|
||||||
parent.difficulty().saturating_sub(
|
parent.difficulty().saturating_sub(
|
||||||
*parent.difficulty() / difficulty_bound_divisor * multiplier
|
*parent.difficulty() / difficulty_bound_divisor * multiplier
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
target = max(min_difficulty, target);
|
target = cmp::max(min_difficulty, target);
|
||||||
if header.number() < self.ethash_params.bomb_defuse_transition {
|
if header.number() < self.ethash_params.bomb_defuse_transition {
|
||||||
if header.number() < self.ethash_params.ecip1010_pause_transition {
|
if header.number() < self.ethash_params.ecip1010_pause_transition {
|
||||||
let period = ((parent.number() + 1) / EXP_DIFF_PERIOD) as usize;
|
let period = ((parent.number() + 1) / EXP_DIFF_PERIOD) as usize;
|
||||||
if period > 1 {
|
if period > 1 {
|
||||||
target = max(min_difficulty, target + (U256::from(1) << (period - 2)));
|
target = cmp::max(min_difficulty, target + (U256::from(1) << (period - 2)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if header.number() < self.ethash_params.ecip1010_continue_transition {
|
else if header.number() < self.ethash_params.ecip1010_continue_transition {
|
||||||
let fixed_difficulty = ((self.ethash_params.ecip1010_pause_transition / EXP_DIFF_PERIOD) - 2) as usize;
|
let fixed_difficulty = ((self.ethash_params.ecip1010_pause_transition / EXP_DIFF_PERIOD) - 2) as usize;
|
||||||
target = max(min_difficulty, target + (U256::from(1) << fixed_difficulty));
|
target = cmp::max(min_difficulty, target + (U256::from(1) << fixed_difficulty));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let period = ((parent.number() + 1) / EXP_DIFF_PERIOD) as usize;
|
let period = ((parent.number() + 1) / EXP_DIFF_PERIOD) as usize;
|
||||||
let delay = ((self.ethash_params.ecip1010_continue_transition - self.ethash_params.ecip1010_pause_transition) / EXP_DIFF_PERIOD) as usize;
|
let delay = ((self.ethash_params.ecip1010_continue_transition - self.ethash_params.ecip1010_pause_transition) / EXP_DIFF_PERIOD) as usize;
|
||||||
target = max(min_difficulty, target + (U256::from(1) << (period - delay - 2)));
|
target = cmp::max(min_difficulty, target + (U256::from(1) << (period - delay - 2)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
target
|
target
|
||||||
@ -569,6 +572,9 @@ impl Header {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::sync::Arc;
|
||||||
use util::*;
|
use util::*;
|
||||||
use block::*;
|
use block::*;
|
||||||
use tests::helpers::*;
|
use tests::helpers::*;
|
||||||
|
@ -134,23 +134,4 @@ mod tests {
|
|||||||
|
|
||||||
let _ = frontier.engine;
|
let _ = frontier.engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn all_spec_files_valid() {
|
|
||||||
let tmp = ::std::env::temp_dir();
|
|
||||||
new_olympic(&tmp);
|
|
||||||
new_foundation(&tmp);
|
|
||||||
new_classic(&tmp);
|
|
||||||
new_expanse(&tmp);
|
|
||||||
new_kovan(&tmp);
|
|
||||||
new_ropsten(&tmp);
|
|
||||||
new_morden(&tmp);
|
|
||||||
new_frontier_test();
|
|
||||||
new_homestead_test();
|
|
||||||
new_eip150_test();
|
|
||||||
new_eip161_test();
|
|
||||||
new_transition_test();
|
|
||||||
new_mainnet_like();
|
|
||||||
new_metropolis_test();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! Transaction execution format module.
|
//! Transaction execution format module.
|
||||||
|
|
||||||
use util::{Bytes, U256, Address, U512, trie};
|
use util::{Bytes, U256, Address, U512, trie};
|
||||||
use evm;
|
use vm;
|
||||||
use trace::{VMTrace, FlatTrace};
|
use trace::{VMTrace, FlatTrace};
|
||||||
use log_entry::LogEntry;
|
use log_entry::LogEntry;
|
||||||
use state_diff::StateDiff;
|
use state_diff::StateDiff;
|
||||||
@ -28,7 +28,7 @@ use std::fmt;
|
|||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Executed {
|
pub struct Executed {
|
||||||
/// True if the outer call/create resulted in an exceptional exit.
|
/// True if the outer call/create resulted in an exceptional exit.
|
||||||
pub exception: Option<evm::Error>,
|
pub exception: Option<vm::Error>,
|
||||||
|
|
||||||
/// Gas paid up front for execution of transaction.
|
/// Gas paid up front for execution of transaction.
|
||||||
pub gas: U256,
|
pub gas: U256,
|
||||||
|
@ -15,14 +15,16 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! Transaction Execution environment.
|
//! Transaction Execution environment.
|
||||||
|
use std::cmp;
|
||||||
|
use std::sync::Arc;
|
||||||
use util::*;
|
use util::*;
|
||||||
use evm::action_params::{ActionParams, ActionValue};
|
|
||||||
use state::{Backend as StateBackend, State, Substate, CleanupMode};
|
use state::{Backend as StateBackend, State, Substate, CleanupMode};
|
||||||
use engines::Engine;
|
use engines::Engine;
|
||||||
use evm::CallType;
|
use vm::EnvInfo;
|
||||||
use evm::env_info::EnvInfo;
|
|
||||||
use error::ExecutionError;
|
use error::ExecutionError;
|
||||||
use evm::{self, wasm, Factory, Ext, Finalize, CreateContractAddress, FinalizationResult, ReturnData, CleanDustMode};
|
use evm::{CallType, Factory, Finalize, FinalizationResult};
|
||||||
|
use vm::{self, Ext, CreateContractAddress, ReturnData, CleanDustMode, ActionParams, ActionValue};
|
||||||
|
use wasm;
|
||||||
use externalities::*;
|
use externalities::*;
|
||||||
use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer};
|
use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer, VMTrace, VMTracer, ExecutiveVMTracer, NoopVMTracer};
|
||||||
use transaction::{Action, SignedTransaction};
|
use transaction::{Action, SignedTransaction};
|
||||||
@ -75,7 +77,7 @@ pub struct TransactOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn executor<E>(engine: &E, vm_factory: &Factory, params: &ActionParams)
|
pub fn executor<E>(engine: &E, vm_factory: &Factory, params: &ActionParams)
|
||||||
-> Box<evm::Evm> where E: Engine + ?Sized
|
-> Box<vm::Vm> where E: Engine + ?Sized
|
||||||
{
|
{
|
||||||
if engine.supports_wasm() && params.code.as_ref().map_or(false, |code| code.len() > 4 && &code[0..4] == WASM_MAGIC_NUMBER) {
|
if engine.supports_wasm() && params.code.as_ref().map_or(false, |code| code.len() > 4 && &code[0..4] == WASM_MAGIC_NUMBER) {
|
||||||
Box::new(
|
Box::new(
|
||||||
@ -269,7 +271,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
|||||||
output_policy: OutputPolicy,
|
output_policy: OutputPolicy,
|
||||||
tracer: &mut T,
|
tracer: &mut T,
|
||||||
vm_tracer: &mut V
|
vm_tracer: &mut V
|
||||||
) -> evm::Result<FinalizationResult> where T: Tracer, V: VMTracer {
|
) -> vm::Result<FinalizationResult> where T: Tracer, V: VMTracer {
|
||||||
|
|
||||||
let depth_threshold = ::io::LOCAL_STACK_SIZE.with(|sz| sz.get() / STACK_SIZE_PER_DEPTH);
|
let depth_threshold = ::io::LOCAL_STACK_SIZE.with(|sz| sz.get() / STACK_SIZE_PER_DEPTH);
|
||||||
let static_call = params.call_type == CallType::StaticCall;
|
let static_call = params.call_type == CallType::StaticCall;
|
||||||
@ -299,7 +301,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
|||||||
/// Calls contract function with given contract params.
|
/// Calls contract function with given contract params.
|
||||||
/// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides).
|
/// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides).
|
||||||
/// Modifies the substate and the output.
|
/// Modifies the substate and the output.
|
||||||
/// Returns either gas_left or `evm::Error`.
|
/// Returns either gas_left or `vm::Error`.
|
||||||
pub fn call<T, V>(
|
pub fn call<T, V>(
|
||||||
&mut self,
|
&mut self,
|
||||||
params: ActionParams,
|
params: ActionParams,
|
||||||
@ -307,14 +309,14 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
|||||||
mut output: BytesRef,
|
mut output: BytesRef,
|
||||||
tracer: &mut T,
|
tracer: &mut T,
|
||||||
vm_tracer: &mut V
|
vm_tracer: &mut V
|
||||||
) -> evm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer {
|
) -> vm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer {
|
||||||
|
|
||||||
trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info);
|
trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info);
|
||||||
if (params.call_type == CallType::StaticCall ||
|
if (params.call_type == CallType::StaticCall ||
|
||||||
((params.call_type == CallType::Call || params.call_type == CallType::DelegateCall) &&
|
((params.call_type == CallType::Call || params.call_type == CallType::DelegateCall) &&
|
||||||
self.static_flag))
|
self.static_flag))
|
||||||
&& params.value.value() > 0.into() {
|
&& params.value.value() > 0.into() {
|
||||||
return Err(evm::Error::MutableCallInStaticContext);
|
return Err(vm::Error::MutableCallInStaticContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
// backup used in case of running out of gas
|
// backup used in case of running out of gas
|
||||||
@ -344,7 +346,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
|||||||
if cost <= params.gas {
|
if cost <= params.gas {
|
||||||
if let Err(e) = builtin.execute(data, &mut output) {
|
if let Err(e) = builtin.execute(data, &mut output) {
|
||||||
self.state.revert_to_checkpoint();
|
self.state.revert_to_checkpoint();
|
||||||
let evm_err: evm::evm::Error = e.into();
|
let evm_err: vm::Error = e.into();
|
||||||
tracer.trace_failed_call(trace_info, vec![], evm_err.clone().into());
|
tracer.trace_failed_call(trace_info, vec![], evm_err.clone().into());
|
||||||
Err(evm_err)
|
Err(evm_err)
|
||||||
} else {
|
} else {
|
||||||
@ -371,9 +373,9 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
|||||||
// just drain the whole gas
|
// just drain the whole gas
|
||||||
self.state.revert_to_checkpoint();
|
self.state.revert_to_checkpoint();
|
||||||
|
|
||||||
tracer.trace_failed_call(trace_info, vec![], evm::Error::OutOfGas.into());
|
tracer.trace_failed_call(trace_info, vec![], vm::Error::OutOfGas.into());
|
||||||
|
|
||||||
Err(evm::Error::OutOfGas)
|
Err(vm::Error::OutOfGas)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let trace_info = tracer.prepare_trace_call(¶ms);
|
let trace_info = tracer.prepare_trace_call(¶ms);
|
||||||
@ -432,17 +434,17 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
|||||||
substate: &mut Substate,
|
substate: &mut Substate,
|
||||||
tracer: &mut T,
|
tracer: &mut T,
|
||||||
vm_tracer: &mut V,
|
vm_tracer: &mut V,
|
||||||
) -> evm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer {
|
) -> vm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer {
|
||||||
|
|
||||||
let scheme = self.engine.create_address_scheme(self.info.number);
|
let scheme = self.engine.create_address_scheme(self.info.number);
|
||||||
if scheme != CreateContractAddress::FromSenderAndNonce && self.state.exists_and_has_code(¶ms.address)? {
|
if scheme != CreateContractAddress::FromSenderAndNonce && self.state.exists_and_has_code(¶ms.address)? {
|
||||||
return Err(evm::Error::OutOfGas);
|
return Err(vm::Error::OutOfGas);
|
||||||
}
|
}
|
||||||
|
|
||||||
if params.call_type == CallType::StaticCall || self.static_flag {
|
if params.call_type == CallType::StaticCall || self.static_flag {
|
||||||
let trace_info = tracer.prepare_trace_create(¶ms);
|
let trace_info = tracer.prepare_trace_create(¶ms);
|
||||||
tracer.trace_failed_create(trace_info, vec![], evm::Error::MutableCallInStaticContext.into());
|
tracer.trace_failed_create(trace_info, vec![], vm::Error::MutableCallInStaticContext.into());
|
||||||
return Err(evm::Error::MutableCallInStaticContext);
|
return Err(vm::Error::MutableCallInStaticContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
// backup used in case of running out of gas
|
// backup used in case of running out of gas
|
||||||
@ -496,7 +498,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
t: &SignedTransaction,
|
t: &SignedTransaction,
|
||||||
mut substate: Substate,
|
mut substate: Substate,
|
||||||
result: evm::Result<(U256, ReturnData)>,
|
result: vm::Result<(U256, ReturnData)>,
|
||||||
output: Bytes,
|
output: Bytes,
|
||||||
trace: Vec<FlatTrace>,
|
trace: Vec<FlatTrace>,
|
||||||
vm_trace: Option<VMTrace>
|
vm_trace: Option<VMTrace>
|
||||||
@ -538,7 +540,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
|||||||
self.state.kill_garbage(&substate.touched, schedule.kill_empty, &min_balance, schedule.kill_dust == CleanDustMode::WithCodeAndStorage)?;
|
self.state.kill_garbage(&substate.touched, schedule.kill_empty, &min_balance, schedule.kill_dust == CleanDustMode::WithCodeAndStorage)?;
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Err(evm::Error::Internal(msg)) => Err(ExecutionError::Internal(msg)),
|
Err(vm::Error::Internal(msg)) => Err(ExecutionError::Internal(msg)),
|
||||||
Err(exception) => {
|
Err(exception) => {
|
||||||
Ok(Executed {
|
Ok(Executed {
|
||||||
exception: Some(exception),
|
exception: Some(exception),
|
||||||
@ -572,20 +574,20 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enact_result(&mut self, result: &evm::Result<FinalizationResult>, substate: &mut Substate, un_substate: Substate) {
|
fn enact_result(&mut self, result: &vm::Result<FinalizationResult>, substate: &mut Substate, un_substate: Substate) {
|
||||||
match *result {
|
match *result {
|
||||||
Err(evm::Error::OutOfGas)
|
Err(vm::Error::OutOfGas)
|
||||||
| Err(evm::Error::BadJumpDestination {..})
|
| Err(vm::Error::BadJumpDestination {..})
|
||||||
| Err(evm::Error::BadInstruction {.. })
|
| Err(vm::Error::BadInstruction {.. })
|
||||||
| Err(evm::Error::StackUnderflow {..})
|
| Err(vm::Error::StackUnderflow {..})
|
||||||
| Err(evm::Error::BuiltIn {..})
|
| Err(vm::Error::BuiltIn {..})
|
||||||
| Err(evm::Error::Wasm {..})
|
| Err(vm::Error::Wasm {..})
|
||||||
| Err(evm::Error::OutOfStack {..})
|
| Err(vm::Error::OutOfStack {..})
|
||||||
| Err(evm::Error::MutableCallInStaticContext)
|
| Err(vm::Error::MutableCallInStaticContext)
|
||||||
| Ok(FinalizationResult { apply_state: false, .. }) => {
|
| Ok(FinalizationResult { apply_state: false, .. }) => {
|
||||||
self.state.revert_to_checkpoint();
|
self.state.revert_to_checkpoint();
|
||||||
},
|
},
|
||||||
Ok(_) | Err(evm::Error::Internal(_)) => {
|
Ok(_) | Err(vm::Error::Internal(_)) => {
|
||||||
self.state.discard_checkpoint();
|
self.state.discard_checkpoint();
|
||||||
substate.accrue(un_substate);
|
substate.accrue(un_substate);
|
||||||
}
|
}
|
||||||
@ -597,14 +599,14 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::str::FromStr;
|
||||||
use rustc_hex::FromHex;
|
use rustc_hex::FromHex;
|
||||||
use ethkey::{Generator, Random};
|
use ethkey::{Generator, Random};
|
||||||
use super::*;
|
use super::*;
|
||||||
use util::{H256, U256, U512, Address, FromStr};
|
use util::{H256, U256, U512, Address};
|
||||||
use util::bytes::BytesRef;
|
use util::bytes::BytesRef;
|
||||||
use evm::action_params::{ActionParams, ActionValue};
|
use vm::{ActionParams, ActionValue, CallType, EnvInfo, CreateContractAddress};
|
||||||
use evm::env_info::EnvInfo;
|
use evm::{Factory, VMType};
|
||||||
use evm::{Factory, VMType, CreateContractAddress};
|
|
||||||
use error::ExecutionError;
|
use error::ExecutionError;
|
||||||
use state::{Substate, CleanupMode};
|
use state::{Substate, CleanupMode};
|
||||||
use tests::helpers::*;
|
use tests::helpers::*;
|
||||||
@ -613,8 +615,6 @@ mod tests {
|
|||||||
use trace::{VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, VMTracer, NoopVMTracer, ExecutiveVMTracer};
|
use trace::{VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, VMTracer, NoopVMTracer, ExecutiveVMTracer};
|
||||||
use transaction::{Action, Transaction};
|
use transaction::{Action, Transaction};
|
||||||
|
|
||||||
use evm::CallType;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_contract_address() {
|
fn test_contract_address() {
|
||||||
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
||||||
|
@ -15,14 +15,17 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! Transaction Execution environment.
|
//! Transaction Execution environment.
|
||||||
|
use std::cmp;
|
||||||
|
use std::sync::Arc;
|
||||||
use util::*;
|
use util::*;
|
||||||
use evm::action_params::{ActionParams, ActionValue};
|
|
||||||
use state::{Backend as StateBackend, State, Substate, CleanupMode};
|
use state::{Backend as StateBackend, State, Substate, CleanupMode};
|
||||||
use engines::Engine;
|
use engines::Engine;
|
||||||
use evm::env_info::EnvInfo;
|
|
||||||
use executive::*;
|
use executive::*;
|
||||||
use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult, CreateContractAddress, ReturnData};
|
use vm::{
|
||||||
use evm::CallType;
|
self, ActionParams, ActionValue, EnvInfo, CallType, Schedule,
|
||||||
|
Ext, ContractCreateResult, MessageCallResult, CreateContractAddress,
|
||||||
|
ReturnData
|
||||||
|
};
|
||||||
use transaction::UNSIGNED_SENDER;
|
use transaction::UNSIGNED_SENDER;
|
||||||
use trace::{Tracer, VMTracer};
|
use trace::{Tracer, VMTracer};
|
||||||
|
|
||||||
@ -109,31 +112,31 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Externalities<'a, T, V, B, E>
|
|||||||
impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
|
impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
|
||||||
where T: Tracer, V: VMTracer, B: StateBackend, E: Engine + ?Sized
|
where T: Tracer, V: VMTracer, B: StateBackend, E: Engine + ?Sized
|
||||||
{
|
{
|
||||||
fn storage_at(&self, key: &H256) -> evm::Result<H256> {
|
fn storage_at(&self, key: &H256) -> vm::Result<H256> {
|
||||||
self.state.storage_at(&self.origin_info.address, key).map_err(Into::into)
|
self.state.storage_at(&self.origin_info.address, key).map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_storage(&mut self, key: H256, value: H256) -> evm::Result<()> {
|
fn set_storage(&mut self, key: H256, value: H256) -> vm::Result<()> {
|
||||||
if self.static_flag {
|
if self.static_flag {
|
||||||
Err(evm::Error::MutableCallInStaticContext)
|
Err(vm::Error::MutableCallInStaticContext)
|
||||||
} else {
|
} else {
|
||||||
self.state.set_storage(&self.origin_info.address, key, value).map_err(Into::into)
|
self.state.set_storage(&self.origin_info.address, key, value).map_err(Into::into)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exists(&self, address: &Address) -> evm::Result<bool> {
|
fn exists(&self, address: &Address) -> vm::Result<bool> {
|
||||||
self.state.exists(address).map_err(Into::into)
|
self.state.exists(address).map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exists_and_not_null(&self, address: &Address) -> evm::Result<bool> {
|
fn exists_and_not_null(&self, address: &Address) -> vm::Result<bool> {
|
||||||
self.state.exists_and_not_null(address).map_err(Into::into)
|
self.state.exists_and_not_null(address).map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn origin_balance(&self) -> evm::Result<U256> {
|
fn origin_balance(&self) -> vm::Result<U256> {
|
||||||
self.balance(&self.origin_info.address).map_err(Into::into)
|
self.balance(&self.origin_info.address).map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn balance(&self, address: &Address) -> evm::Result<U256> {
|
fn balance(&self, address: &Address) -> vm::Result<U256> {
|
||||||
self.state.balance(address).map_err(Into::into)
|
self.state.balance(address).map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,16 +277,16 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extcode(&self, address: &Address) -> evm::Result<Arc<Bytes>> {
|
fn extcode(&self, address: &Address) -> vm::Result<Arc<Bytes>> {
|
||||||
Ok(self.state.code(address)?.unwrap_or_else(|| Arc::new(vec![])))
|
Ok(self.state.code(address)?.unwrap_or_else(|| Arc::new(vec![])))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extcodesize(&self, address: &Address) -> evm::Result<usize> {
|
fn extcodesize(&self, address: &Address) -> vm::Result<usize> {
|
||||||
Ok(self.state.code_size(address)?.unwrap_or(0))
|
Ok(self.state.code_size(address)?.unwrap_or(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature="dev", allow(match_ref_pats))]
|
#[cfg_attr(feature="dev", allow(match_ref_pats))]
|
||||||
fn ret(mut self, gas: &U256, data: &ReturnData) -> evm::Result<U256>
|
fn ret(mut self, gas: &U256, data: &ReturnData) -> vm::Result<U256>
|
||||||
where Self: Sized {
|
where Self: Sized {
|
||||||
let handle_copy = |to: &mut Option<&mut Bytes>| {
|
let handle_copy = |to: &mut Option<&mut Bytes>| {
|
||||||
to.as_mut().map(|b| **b = data.to_vec());
|
to.as_mut().map(|b| **b = data.to_vec());
|
||||||
@ -307,7 +310,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
|
|||||||
let return_cost = U256::from(data.len()) * U256::from(self.schedule.create_data_gas);
|
let return_cost = U256::from(data.len()) * U256::from(self.schedule.create_data_gas);
|
||||||
if return_cost > *gas || data.len() > self.schedule.create_data_limit {
|
if return_cost > *gas || data.len() > self.schedule.create_data_limit {
|
||||||
return match self.schedule.exceptional_failed_code_deposit {
|
return match self.schedule.exceptional_failed_code_deposit {
|
||||||
true => Err(evm::Error::OutOfGas),
|
true => Err(vm::Error::OutOfGas),
|
||||||
false => Ok(*gas)
|
false => Ok(*gas)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -320,11 +323,11 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> evm::Result<()> {
|
fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> vm::Result<()> {
|
||||||
use log_entry::LogEntry;
|
use log_entry::LogEntry;
|
||||||
|
|
||||||
if self.static_flag {
|
if self.static_flag {
|
||||||
return Err(evm::Error::MutableCallInStaticContext);
|
return Err(vm::Error::MutableCallInStaticContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
let address = self.origin_info.address.clone();
|
let address = self.origin_info.address.clone();
|
||||||
@ -337,9 +340,9 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suicide(&mut self, refund_address: &Address) -> evm::Result<()> {
|
fn suicide(&mut self, refund_address: &Address) -> vm::Result<()> {
|
||||||
if self.static_flag {
|
if self.static_flag {
|
||||||
return Err(evm::Error::MutableCallInStaticContext);
|
return Err(vm::Error::MutableCallInStaticContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
let address = self.origin_info.address.clone();
|
let address = self.origin_info.address.clone();
|
||||||
@ -396,13 +399,11 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
|
|||||||
mod tests {
|
mod tests {
|
||||||
use util::*;
|
use util::*;
|
||||||
use engines::Engine;
|
use engines::Engine;
|
||||||
use evm::env_info::EnvInfo;
|
use evm::{EnvInfo, Ext, CallType};
|
||||||
use evm::Ext;
|
|
||||||
use state::{State, Substate};
|
use state::{State, Substate};
|
||||||
use tests::helpers::*;
|
use tests::helpers::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
use trace::{NoopTracer, NoopVMTracer};
|
use trace::{NoopTracer, NoopVMTracer};
|
||||||
use evm::CallType;
|
|
||||||
|
|
||||||
fn get_test_origin() -> OriginInfo {
|
fn get_test_origin() -> OriginInfo {
|
||||||
OriginInfo {
|
OriginInfo {
|
||||||
@ -470,7 +471,7 @@ mod tests {
|
|||||||
|
|
||||||
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false);
|
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false);
|
||||||
|
|
||||||
let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap());
|
let hash = ext.blockhash(&"0000000000000000000000000000000000000000000000000000000000120000".parse::<U256>().unwrap());
|
||||||
|
|
||||||
assert_eq!(hash, H256::zero());
|
assert_eq!(hash, H256::zero());
|
||||||
}
|
}
|
||||||
@ -494,7 +495,7 @@ mod tests {
|
|||||||
|
|
||||||
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false);
|
let mut ext = Externalities::new(state, &setup.env_info, &*setup.engine, 0, get_test_origin(), &mut setup.sub_state, OutputPolicy::InitContract(None), &mut tracer, &mut vm_tracer, false);
|
||||||
|
|
||||||
let hash = ext.blockhash(&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap());
|
let hash = ext.blockhash(&"0000000000000000000000000000000000000000000000000000000000120000".parse::<U256>().unwrap());
|
||||||
|
|
||||||
assert_eq!(test_hash, hash);
|
assert_eq!(test_hash, hash);
|
||||||
}
|
}
|
||||||
@ -513,10 +514,10 @@ mod tests {
|
|||||||
|
|
||||||
// this should panic because we have no balance on any account
|
// this should panic because we have no balance on any account
|
||||||
ext.call(
|
ext.call(
|
||||||
&U256::from_str("0000000000000000000000000000000000000000000000000000000000120000").unwrap(),
|
&"0000000000000000000000000000000000000000000000000000000000120000".parse::<U256>().unwrap(),
|
||||||
&Address::new(),
|
&Address::new(),
|
||||||
&Address::new(),
|
&Address::new(),
|
||||||
Some(U256::from_str("0000000000000000000000000000000000000000000000000000000000150000").unwrap()),
|
Some("0000000000000000000000000000000000000000000000000000000000150000".parse::<U256>().unwrap()),
|
||||||
&[],
|
&[],
|
||||||
&Address::new(),
|
&Address::new(),
|
||||||
&mut output,
|
&mut output,
|
||||||
|
@ -16,13 +16,13 @@
|
|||||||
|
|
||||||
//! Block header.
|
//! Block header.
|
||||||
|
|
||||||
|
use std::cmp;
|
||||||
|
use std::cell::RefCell;
|
||||||
use util::*;
|
use util::*;
|
||||||
use basic_types::{LogBloom, ZERO_LOGBLOOM};
|
use basic_types::{LogBloom, ZERO_LOGBLOOM};
|
||||||
use time::get_time;
|
use time::get_time;
|
||||||
use rlp::*;
|
use rlp::*;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
|
||||||
|
|
||||||
pub use basic_types::Seal;
|
pub use basic_types::Seal;
|
||||||
|
|
||||||
pub use types::BlockNumber;
|
pub use types::BlockNumber;
|
||||||
@ -175,7 +175,7 @@ impl Header {
|
|||||||
/// Set the timestamp field of the header.
|
/// Set the timestamp field of the header.
|
||||||
pub fn set_timestamp(&mut self, a: u64) { self.timestamp = a; self.note_dirty(); }
|
pub fn set_timestamp(&mut self, a: u64) { self.timestamp = a; self.note_dirty(); }
|
||||||
/// Set the timestamp field of the header to the current time.
|
/// Set the timestamp field of the header to the current time.
|
||||||
pub fn set_timestamp_now(&mut self, but_later_than: u64) { self.timestamp = max(get_time().sec as u64, but_later_than + 1); self.note_dirty(); }
|
pub fn set_timestamp_now(&mut self, but_later_than: u64) { self.timestamp = cmp::max(get_time().sec as u64, but_later_than + 1); self.note_dirty(); }
|
||||||
/// Set the number field of the header.
|
/// Set the number field of the header.
|
||||||
pub fn set_number(&mut self, a: BlockNumber) { self.number = a; self.note_dirty(); }
|
pub fn set_number(&mut self, a: BlockNumber) { self.number = a; self.note_dirty(); }
|
||||||
/// Set the author field of the header.
|
/// Set the author field of the header.
|
||||||
@ -275,7 +275,7 @@ impl Decodable for Header {
|
|||||||
number: r.val_at(8)?,
|
number: r.val_at(8)?,
|
||||||
gas_limit: r.val_at(9)?,
|
gas_limit: r.val_at(9)?,
|
||||||
gas_used: r.val_at(10)?,
|
gas_used: r.val_at(10)?,
|
||||||
timestamp: min(r.val_at::<U256>(11)?, u64::max_value().into()).as_u64(),
|
timestamp: cmp::min(r.val_at::<U256>(11)?, u64::max_value().into()).as_u64(),
|
||||||
extra_data: r.val_at(12)?,
|
extra_data: r.val_at(12)?,
|
||||||
seal: vec![],
|
seal: vec![],
|
||||||
hash: RefCell::new(Some(r.as_raw().sha3())),
|
hash: RefCell::new(Some(r.as_raw().sha3())),
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use super::test_common::*;
|
use std::sync::Arc;
|
||||||
use client::{BlockChainClient, Client, ClientConfig};
|
use client::{BlockChainClient, Client, ClientConfig};
|
||||||
use block::Block;
|
use block::Block;
|
||||||
use ethereum;
|
use ethereum;
|
||||||
|
@ -14,16 +14,18 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
use super::test_common::*;
|
use super::test_common::*;
|
||||||
use evm::action_params::ActionParams;
|
|
||||||
use state::{Backend as StateBackend, State, Substate};
|
use state::{Backend as StateBackend, State, Substate};
|
||||||
use executive::*;
|
use executive::*;
|
||||||
use engines::Engine;
|
use engines::Engine;
|
||||||
use evm::env_info::EnvInfo;
|
use evm::{VMType, Finalize};
|
||||||
use evm;
|
use vm::{
|
||||||
use evm::{Schedule, Ext, Finalize, VMType, ContractCreateResult, MessageCallResult, CreateContractAddress, ReturnData};
|
self, ActionParams, CallType, Schedule, Ext,
|
||||||
|
ContractCreateResult, EnvInfo, MessageCallResult,
|
||||||
|
CreateContractAddress, ReturnData,
|
||||||
|
};
|
||||||
use externalities::*;
|
use externalities::*;
|
||||||
use evm::CallType;
|
|
||||||
use tests::helpers::*;
|
use tests::helpers::*;
|
||||||
use ethjson;
|
use ethjson;
|
||||||
use trace::{Tracer, NoopTracer};
|
use trace::{Tracer, NoopTracer};
|
||||||
@ -88,27 +90,27 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> TestExt<'a, T, V, B, E>
|
|||||||
impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for TestExt<'a, T, V, B, E>
|
impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for TestExt<'a, T, V, B, E>
|
||||||
where T: Tracer, V: VMTracer, B: StateBackend, E: Engine + ?Sized
|
where T: Tracer, V: VMTracer, B: StateBackend, E: Engine + ?Sized
|
||||||
{
|
{
|
||||||
fn storage_at(&self, key: &H256) -> evm::Result<H256> {
|
fn storage_at(&self, key: &H256) -> vm::Result<H256> {
|
||||||
self.ext.storage_at(key)
|
self.ext.storage_at(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_storage(&mut self, key: H256, value: H256) -> evm::Result<()> {
|
fn set_storage(&mut self, key: H256, value: H256) -> vm::Result<()> {
|
||||||
self.ext.set_storage(key, value)
|
self.ext.set_storage(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exists(&self, address: &Address) -> evm::Result<bool> {
|
fn exists(&self, address: &Address) -> vm::Result<bool> {
|
||||||
self.ext.exists(address)
|
self.ext.exists(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exists_and_not_null(&self, address: &Address) -> evm::Result<bool> {
|
fn exists_and_not_null(&self, address: &Address) -> vm::Result<bool> {
|
||||||
self.ext.exists_and_not_null(address)
|
self.ext.exists_and_not_null(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn balance(&self, address: &Address) -> evm::Result<U256> {
|
fn balance(&self, address: &Address) -> vm::Result<U256> {
|
||||||
self.ext.balance(address)
|
self.ext.balance(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn origin_balance(&self) -> evm::Result<U256> {
|
fn origin_balance(&self) -> vm::Result<U256> {
|
||||||
self.ext.origin_balance()
|
self.ext.origin_balance()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,23 +148,23 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for TestExt<'a, T, V, B, E>
|
|||||||
MessageCallResult::Success(*gas, ReturnData::empty())
|
MessageCallResult::Success(*gas, ReturnData::empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extcode(&self, address: &Address) -> evm::Result<Arc<Bytes>> {
|
fn extcode(&self, address: &Address) -> vm::Result<Arc<Bytes>> {
|
||||||
self.ext.extcode(address)
|
self.ext.extcode(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extcodesize(&self, address: &Address) -> evm::Result<usize> {
|
fn extcodesize(&self, address: &Address) -> vm::Result<usize> {
|
||||||
self.ext.extcodesize(address)
|
self.ext.extcodesize(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> evm::Result<()> {
|
fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> vm::Result<()> {
|
||||||
self.ext.log(topics, data)
|
self.ext.log(topics, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ret(self, gas: &U256, data: &ReturnData) -> Result<U256, evm::Error> {
|
fn ret(self, gas: &U256, data: &ReturnData) -> Result<U256, vm::Error> {
|
||||||
self.ext.ret(gas, data)
|
self.ext.ret(gas, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suicide(&mut self, refund_address: &Address) -> evm::Result<()> {
|
fn suicide(&mut self, refund_address: &Address) -> vm::Result<()> {
|
||||||
self.ext.suicide(refund_address)
|
self.ext.suicide(refund_address)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ use spec::Spec;
|
|||||||
use ethjson;
|
use ethjson;
|
||||||
use ethjson::state::test::ForkSpec;
|
use ethjson::state::test::ForkSpec;
|
||||||
use transaction::SignedTransaction;
|
use transaction::SignedTransaction;
|
||||||
use evm::env_info::EnvInfo;
|
use vm::EnvInfo;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref FRONTIER: Spec = ethereum::new_frontier_test();
|
pub static ref FRONTIER: Spec = ethereum::new_frontier_test();
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
pub use util::*;
|
pub use util::*;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use std::io::Read;
|
||||||
use std::fs::{File, read_dir};
|
use std::fs::{File, read_dir};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
|
@ -106,6 +106,11 @@ extern crate semver;
|
|||||||
extern crate stats;
|
extern crate stats;
|
||||||
extern crate time;
|
extern crate time;
|
||||||
extern crate transient_hashmap;
|
extern crate transient_hashmap;
|
||||||
|
extern crate using_queue;
|
||||||
|
extern crate table;
|
||||||
|
extern crate bloomable;
|
||||||
|
extern crate vm;
|
||||||
|
extern crate wasm;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
@ -15,9 +15,11 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::time::{Instant, Duration};
|
use std::time::{Instant, Duration};
|
||||||
|
use std::collections::{BTreeMap, HashSet};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use util::*;
|
use util::*;
|
||||||
use util::using_queue::{UsingQueue, GetAction};
|
use using_queue::{UsingQueue, GetAction};
|
||||||
use account_provider::{AccountProvider, SignError as AccountError};
|
use account_provider::{AccountProvider, SignError as AccountError};
|
||||||
use state::{State, CleanupMode};
|
use state::{State, CleanupMode};
|
||||||
use client::{MiningBlockChainClient, Executive, Executed, EnvInfo, TransactOptions, BlockId, CallAnalytics, TransactionId};
|
use client::{MiningBlockChainClient, Executive, Executed, EnvInfo, TransactOptions, BlockId, CallAnalytics, TransactionId};
|
||||||
|
@ -106,7 +106,7 @@ use std::cmp;
|
|||||||
use std::collections::{HashSet, HashMap, BTreeSet, BTreeMap};
|
use std::collections::{HashSet, HashMap, BTreeSet, BTreeMap};
|
||||||
use linked_hash_map::LinkedHashMap;
|
use linked_hash_map::LinkedHashMap;
|
||||||
use util::{Address, H256, U256, HeapSizeOf};
|
use util::{Address, H256, U256, HeapSizeOf};
|
||||||
use util::table::Table;
|
use table::Table;
|
||||||
use transaction::*;
|
use transaction::*;
|
||||||
use error::{Error, TransactionError};
|
use error::{Error, TransactionError};
|
||||||
use client::TransactionImportResult;
|
use client::TransactionImportResult;
|
||||||
@ -1447,7 +1447,7 @@ fn check_if_removed(sender: &Address, nonce: &U256, dropped: Option<HashMap<Addr
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod test {
|
pub mod test {
|
||||||
use rustc_hex::FromHex;
|
use rustc_hex::FromHex;
|
||||||
use util::table::*;
|
use table::Table;
|
||||||
use util::*;
|
use util::*;
|
||||||
use ethkey::{Random, Generator};
|
use ethkey::{Random, Generator};
|
||||||
use error::{Error, TransactionError};
|
use error::{Error, TransactionError};
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
extern crate hyper;
|
extern crate hyper;
|
||||||
|
|
||||||
|
use std::io::Write;
|
||||||
use hyper::header::ContentType;
|
use hyper::header::ContentType;
|
||||||
use hyper::method::Method;
|
use hyper::method::Method;
|
||||||
use hyper::client::{Request, Response, Client};
|
use hyper::client::{Request, Response, Client};
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use util::*;
|
use util::*;
|
||||||
use state::Account;
|
use state::Account;
|
||||||
use ethjson;
|
use ethjson;
|
||||||
@ -166,7 +168,7 @@ pub fn diff_pod(pre: Option<&PodAccount>, post: Option<&PodAccount>) -> Option<A
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use util::*;
|
use std::collections::BTreeMap;
|
||||||
use types::account_diff::*;
|
use types::account_diff::*;
|
||||||
use super::{PodAccount, diff_pod};
|
use super::{PodAccount, diff_pod};
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
//! State of all accounts in the system expressed in Plain Old Data.
|
//! State of all accounts in the system expressed in Plain Old Data.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use util::*;
|
use util::*;
|
||||||
use pod_account::{self, PodAccount};
|
use pod_account::{self, PodAccount};
|
||||||
use types::state_diff::StateDiff;
|
use types::state_diff::StateDiff;
|
||||||
@ -77,7 +79,7 @@ pub fn diff_pod(pre: &PodState, post: &PodState) -> StateDiff {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use util::*;
|
use std::collections::BTreeMap;
|
||||||
use types::state_diff::*;
|
use types::state_diff::*;
|
||||||
use types::account_diff::*;
|
use types::account_diff::*;
|
||||||
use pod_account::PodAccount;
|
use pod_account::PodAccount;
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
//! Creates and registers client and network services.
|
//! Creates and registers client and network services.
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::path::Path;
|
||||||
use util::*;
|
use util::*;
|
||||||
use io::*;
|
use io::*;
|
||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
|
@ -16,14 +16,17 @@
|
|||||||
|
|
||||||
//! Parameters for a block chain.
|
//! Parameters for a block chain.
|
||||||
|
|
||||||
|
use std::io::Read;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::sync::Arc;
|
||||||
use rustc_hex::FromHex;
|
use rustc_hex::FromHex;
|
||||||
use super::genesis::Genesis;
|
use super::genesis::Genesis;
|
||||||
use super::seal::Generic as GenericSeal;
|
use super::seal::Generic as GenericSeal;
|
||||||
|
|
||||||
use evm::action_params::{ActionValue, ActionParams};
|
|
||||||
use builtin::Builtin;
|
use builtin::Builtin;
|
||||||
use engines::{Engine, NullEngine, InstantSeal, BasicAuthority, AuthorityRound, Tendermint, DEFAULT_BLOCKHASH_CONTRACT};
|
use engines::{Engine, NullEngine, InstantSeal, BasicAuthority, AuthorityRound, Tendermint, DEFAULT_BLOCKHASH_CONTRACT};
|
||||||
use evm::env_info::EnvInfo;
|
use vm::{EnvInfo, CallType, ActionValue, ActionParams};
|
||||||
use error::Error;
|
use error::Error;
|
||||||
use ethereum;
|
use ethereum;
|
||||||
use ethjson;
|
use ethjson;
|
||||||
@ -36,7 +39,6 @@ use state_db::StateDB;
|
|||||||
use state::{Backend, State, Substate};
|
use state::{Backend, State, Substate};
|
||||||
use state::backend::Basic as BasicBackend;
|
use state::backend::Basic as BasicBackend;
|
||||||
use trace::{NoopTracer, NoopVMTracer};
|
use trace::{NoopTracer, NoopVMTracer};
|
||||||
use evm::CallType;
|
|
||||||
use util::*;
|
use util::*;
|
||||||
|
|
||||||
/// Parameters common to ethereum-like blockchains.
|
/// Parameters common to ethereum-like blockchains.
|
||||||
@ -102,14 +104,14 @@ pub struct CommonParams {
|
|||||||
|
|
||||||
impl CommonParams {
|
impl CommonParams {
|
||||||
/// Schedule for an EVM in the post-EIP-150-era of the Ethereum main net.
|
/// Schedule for an EVM in the post-EIP-150-era of the Ethereum main net.
|
||||||
pub fn schedule(&self, block_number: u64) -> ::evm::Schedule {
|
pub fn schedule(&self, block_number: u64) -> ::vm::Schedule {
|
||||||
let mut schedule = ::evm::Schedule::new_post_eip150(usize::max_value(), true, true, true);
|
let mut schedule = ::vm::Schedule::new_post_eip150(usize::max_value(), true, true, true);
|
||||||
self.update_schedule(block_number, &mut schedule);
|
self.update_schedule(block_number, &mut schedule);
|
||||||
schedule
|
schedule
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply common spec config parameters to the schedule.
|
/// Apply common spec config parameters to the schedule.
|
||||||
pub fn update_schedule(&self, block_number: u64, schedule: &mut ::evm::Schedule) {
|
pub fn update_schedule(&self, block_number: u64, schedule: &mut ::vm::Schedule) {
|
||||||
schedule.have_create2 = block_number >= self.eip86_transition;
|
schedule.have_create2 = block_number >= self.eip86_transition;
|
||||||
schedule.have_revert = block_number >= self.eip140_transition;
|
schedule.have_revert = block_number >= self.eip140_transition;
|
||||||
schedule.have_static_call = block_number >= self.eip214_transition;
|
schedule.have_static_call = block_number >= self.eip214_transition;
|
||||||
@ -119,8 +121,8 @@ impl CommonParams {
|
|||||||
}
|
}
|
||||||
if block_number >= self.dust_protection_transition {
|
if block_number >= self.dust_protection_transition {
|
||||||
schedule.kill_dust = match self.remove_dust_contracts {
|
schedule.kill_dust = match self.remove_dust_contracts {
|
||||||
true => ::evm::CleanDustMode::WithCodeAndStorage,
|
true => ::vm::CleanDustMode::WithCodeAndStorage,
|
||||||
false => ::evm::CleanDustMode::BasicOnly,
|
false => ::vm::CleanDustMode::BasicOnly,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -517,6 +519,7 @@ impl Spec {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::str::FromStr;
|
||||||
use util::*;
|
use util::*;
|
||||||
use views::*;
|
use views::*;
|
||||||
use tests::helpers::get_temp_state_db;
|
use tests::helpers::get_temp_state_db;
|
||||||
@ -529,19 +532,6 @@ mod tests {
|
|||||||
assert!(Spec::load(::std::env::temp_dir(), &[] as &[u8]).is_err());
|
assert!(Spec::load(::std::env::temp_dir(), &[] as &[u8]).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn all_spec_files_valid() {
|
|
||||||
Spec::new_test();
|
|
||||||
Spec::new_null();
|
|
||||||
Spec::new_test_constructor();
|
|
||||||
Spec::new_instant();
|
|
||||||
Spec::new_test_round();
|
|
||||||
Spec::new_test_tendermint();
|
|
||||||
Spec::new_validator_safe_contract();
|
|
||||||
Spec::new_validator_contract();
|
|
||||||
Spec::new_validator_multi();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_chain() {
|
fn test_chain() {
|
||||||
let test_spec = Spec::new_test();
|
let test_spec = Spec::new_test();
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
//! Single account in the system.
|
//! Single account in the system.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::collections::HashMap;
|
||||||
use util::*;
|
use util::*;
|
||||||
use pod_account::*;
|
use pod_account::*;
|
||||||
use rlp::*;
|
use rlp::*;
|
||||||
|
@ -21,10 +21,13 @@
|
|||||||
|
|
||||||
use std::cell::{RefCell, RefMut};
|
use std::cell::{RefCell, RefMut};
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
|
use std::collections::{HashMap, BTreeMap, HashSet};
|
||||||
|
use std::fmt;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use receipt::Receipt;
|
use receipt::Receipt;
|
||||||
use engines::Engine;
|
use engines::Engine;
|
||||||
use evm::env_info::EnvInfo;
|
use vm::EnvInfo;
|
||||||
use error::Error;
|
use error::Error;
|
||||||
use executive::{Executive, TransactOptions};
|
use executive::{Executive, TransactOptions};
|
||||||
use factory::Factories;
|
use factory::Factories;
|
||||||
@ -982,7 +985,7 @@ mod tests {
|
|||||||
use ethkey::Secret;
|
use ethkey::Secret;
|
||||||
use util::{U256, H256, Address, Hashable};
|
use util::{U256, H256, Address, Hashable};
|
||||||
use tests::helpers::*;
|
use tests::helpers::*;
|
||||||
use evm::env_info::EnvInfo;
|
use vm::EnvInfo;
|
||||||
use spec::*;
|
use spec::*;
|
||||||
use transaction::*;
|
use transaction::*;
|
||||||
use ethcore_logger::init_log;
|
use ethcore_logger::init_log;
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::collections::{VecDeque, HashSet};
|
use std::collections::{VecDeque, HashSet};
|
||||||
|
use std::sync::Arc;
|
||||||
use lru_cache::LruCache;
|
use lru_cache::LruCache;
|
||||||
use util::cache::MemoryLruCache;
|
use util::cache::MemoryLruCache;
|
||||||
use util::journaldb::JournalDB;
|
use util::journaldb::JournalDB;
|
||||||
@ -23,7 +24,7 @@ use util::hash::{H256};
|
|||||||
use util::hashdb::HashDB;
|
use util::hashdb::HashDB;
|
||||||
use state::{self, Account};
|
use state::{self, Account};
|
||||||
use header::BlockNumber;
|
use header::BlockNumber;
|
||||||
use util::{Arc, Address, DBTransaction, UtilError, Mutex, Hashable};
|
use util::{Address, DBTransaction, UtilError, Mutex, Hashable};
|
||||||
use bloom_journal::{Bloom, BloomJournal};
|
use bloom_journal::{Bloom, BloomJournal};
|
||||||
use db::COL_ACCOUNT_BLOOM;
|
use db::COL_ACCOUNT_BLOOM;
|
||||||
use byteorder::{LittleEndian, ByteOrder};
|
use byteorder::{LittleEndian, ByteOrder};
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::sync::Arc;
|
||||||
use io::IoChannel;
|
use io::IoChannel;
|
||||||
use client::{BlockChainClient, MiningBlockChainClient, Client, ClientConfig, BlockId};
|
use client::{BlockChainClient, MiningBlockChainClient, Client, ClientConfig, BlockId};
|
||||||
use state::{self, State, CleanupMode};
|
use state::{self, State, CleanupMode};
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
//! Tests of EVM integration with transaction execution.
|
//! Tests of EVM integration with transaction execution.
|
||||||
|
|
||||||
use evm::action_params::{ActionParams, ActionValue};
|
use std::sync::Arc;
|
||||||
use evm::env_info::EnvInfo;
|
use vm::{EnvInfo, ActionParams, ActionValue, CallType};
|
||||||
use evm::{Factory, VMType};
|
use evm::{Factory, VMType};
|
||||||
use evm::call_type::CallType;
|
|
||||||
use executive::Executive;
|
use executive::Executive;
|
||||||
use state::Substate;
|
use state::Substate;
|
||||||
use tests::helpers::*;
|
use tests::helpers::*;
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::sync::Arc;
|
||||||
use ethkey::KeyPair;
|
use ethkey::KeyPair;
|
||||||
use io::*;
|
use io::*;
|
||||||
use client::{BlockChainClient, Client, ClientConfig};
|
use client::{BlockChainClient, Client, ClientConfig};
|
||||||
@ -347,7 +349,7 @@ pub fn get_good_dummy_block_fork_seq(start_number: usize, count: usize, parent_h
|
|||||||
for i in start_number .. start_number + count + 1 {
|
for i in start_number .. start_number + count + 1 {
|
||||||
let mut block_header = Header::new();
|
let mut block_header = Header::new();
|
||||||
block_header.set_gas_limit(test_engine.params().min_gas_limit);
|
block_header.set_gas_limit(test_engine.params().min_gas_limit);
|
||||||
block_header.set_difficulty(U256::from(i).mul(U256([0, 1, 0, 0])));
|
block_header.set_difficulty(U256::from(i) * U256([0, 1, 0, 0]));
|
||||||
block_header.set_timestamp(rolling_timestamp);
|
block_header.set_timestamp(rolling_timestamp);
|
||||||
block_header.set_number(i as u64);
|
block_header.set_number(i as u64);
|
||||||
block_header.set_parent_hash(parent);
|
block_header.set_parent_hash(parent);
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! Simple executive tracer.
|
//! Simple executive tracer.
|
||||||
|
|
||||||
use util::{Bytes, Address, U256};
|
use util::{Bytes, Address, U256};
|
||||||
use evm::action_params::ActionParams;
|
use vm::ActionParams;
|
||||||
use trace::trace::{Call, Create, Action, Res, CreateResult, CallResult, VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, Suicide, Reward, RewardType};
|
use trace::trace::{Call, Create, Action, Res, CreateResult, CallResult, VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, Suicide, Reward, RewardType};
|
||||||
use trace::{Tracer, VMTracer, FlatTrace, TraceError};
|
use trace::{Tracer, VMTracer, FlatTrace, TraceError};
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ pub use self::types::filter::{Filter, AddressesFilter};
|
|||||||
|
|
||||||
use util::{Bytes, Address, U256, H256, DBTransaction};
|
use util::{Bytes, Address, U256, H256, DBTransaction};
|
||||||
use self::trace::{Call, Create};
|
use self::trace::{Call, Create};
|
||||||
use evm::action_params::ActionParams;
|
use vm::ActionParams;
|
||||||
use header::BlockNumber;
|
use header::BlockNumber;
|
||||||
|
|
||||||
/// This trait is used by executive to build traces.
|
/// This trait is used by executive to build traces.
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! Nonoperative tracer.
|
//! Nonoperative tracer.
|
||||||
|
|
||||||
use util::{Bytes, Address, U256};
|
use util::{Bytes, Address, U256};
|
||||||
use evm::action_params::ActionParams;
|
use vm::ActionParams;
|
||||||
use trace::{Tracer, VMTracer, FlatTrace, TraceError};
|
use trace::{Tracer, VMTracer, FlatTrace, TraceError};
|
||||||
use trace::trace::{Call, Create, VMTrace, RewardType};
|
use trace::trace::{Call, Create, VMTrace, RewardType};
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use rlp::{Encodable, RlpStream, Decodable, DecoderError, UntrustedRlp};
|
use rlp::{Encodable, RlpStream, Decodable, DecoderError, UntrustedRlp};
|
||||||
use evm::Error as EvmError;
|
use vm::Error as VmError;
|
||||||
|
|
||||||
/// Trace evm errors.
|
/// Trace evm errors.
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
@ -45,24 +45,24 @@ pub enum Error {
|
|||||||
Wasm,
|
Wasm,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a EvmError> for Error {
|
impl<'a> From<&'a VmError> for Error {
|
||||||
fn from(e: &'a EvmError) -> Self {
|
fn from(e: &'a VmError) -> Self {
|
||||||
match *e {
|
match *e {
|
||||||
EvmError::OutOfGas => Error::OutOfGas,
|
VmError::OutOfGas => Error::OutOfGas,
|
||||||
EvmError::BadJumpDestination { .. } => Error::BadJumpDestination,
|
VmError::BadJumpDestination { .. } => Error::BadJumpDestination,
|
||||||
EvmError::BadInstruction { .. } => Error::BadInstruction,
|
VmError::BadInstruction { .. } => Error::BadInstruction,
|
||||||
EvmError::StackUnderflow { .. } => Error::StackUnderflow,
|
VmError::StackUnderflow { .. } => Error::StackUnderflow,
|
||||||
EvmError::OutOfStack { .. } => Error::OutOfStack,
|
VmError::OutOfStack { .. } => Error::OutOfStack,
|
||||||
EvmError::BuiltIn { .. } => Error::BuiltIn,
|
VmError::BuiltIn { .. } => Error::BuiltIn,
|
||||||
EvmError::Wasm { .. } => Error::Wasm,
|
VmError::Wasm { .. } => Error::Wasm,
|
||||||
EvmError::Internal(_) => Error::Internal,
|
VmError::Internal(_) => Error::Internal,
|
||||||
EvmError::MutableCallInStaticContext => Error::MutableCallInStaticContext,
|
VmError::MutableCallInStaticContext => Error::MutableCallInStaticContext,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<EvmError> for Error {
|
impl From<VmError> for Error {
|
||||||
fn from(e: EvmError) -> Self {
|
fn from(e: VmError) -> Self {
|
||||||
Error::from(&e)
|
Error::from(&e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ use std::ops::Range;
|
|||||||
use bloomchain::{Filter as BloomFilter, Bloom, Number};
|
use bloomchain::{Filter as BloomFilter, Bloom, Number};
|
||||||
use util::Address;
|
use util::Address;
|
||||||
use util::sha3::Hashable;
|
use util::sha3::Hashable;
|
||||||
use util::bloom::Bloomable;
|
use bloomable::Bloomable;
|
||||||
use basic_types::LogBloom;
|
use basic_types::LogBloom;
|
||||||
use trace::flat::FlatTrace;
|
use trace::flat::FlatTrace;
|
||||||
use super::trace::{Action, Res};
|
use super::trace::{Action, Res};
|
||||||
@ -141,7 +141,7 @@ impl Filter {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use util::Address;
|
use util::Address;
|
||||||
use util::sha3::Hashable;
|
use util::sha3::Hashable;
|
||||||
use util::bloom::Bloomable;
|
use bloomable::Bloomable;
|
||||||
use trace::trace::{Action, Call, Res, Create, CreateResult, Suicide, Reward};
|
use trace::trace::{Action, Call, Res, Create, CreateResult, Suicide, Reward};
|
||||||
use trace::flat::FlatTrace;
|
use trace::flat::FlatTrace;
|
||||||
use trace::{Filter, AddressesFilter, TraceError, RewardType};
|
use trace::{Filter, AddressesFilter, TraceError, RewardType};
|
||||||
|
@ -18,10 +18,10 @@
|
|||||||
|
|
||||||
use util::{U256, Bytes, Address};
|
use util::{U256, Bytes, Address};
|
||||||
use util::sha3::Hashable;
|
use util::sha3::Hashable;
|
||||||
use util::bloom::Bloomable;
|
use bloomable::Bloomable;
|
||||||
use rlp::*;
|
use rlp::*;
|
||||||
|
|
||||||
use evm::action_params::ActionParams;
|
use vm::ActionParams;
|
||||||
use basic_types::LogBloom;
|
use basic_types::LogBloom;
|
||||||
use evm::CallType;
|
use evm::CallType;
|
||||||
use super::error::Error;
|
use super::error::Error;
|
||||||
|
@ -19,7 +19,9 @@
|
|||||||
|
|
||||||
use std::thread::{self, JoinHandle};
|
use std::thread::{self, JoinHandle};
|
||||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering as AtomicOrdering};
|
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering as AtomicOrdering};
|
||||||
use std::sync::{Condvar as SCondvar, Mutex as SMutex};
|
use std::sync::{Condvar as SCondvar, Mutex as SMutex, Arc};
|
||||||
|
use std::cmp;
|
||||||
|
use std::collections::{VecDeque, HashSet, HashMap};
|
||||||
use util::*;
|
use util::*;
|
||||||
use io::*;
|
use io::*;
|
||||||
use error::*;
|
use error::*;
|
||||||
@ -234,8 +236,8 @@ impl<K: Kind> VerificationQueue<K> {
|
|||||||
let scale_verifiers = config.verifier_settings.scale_verifiers;
|
let scale_verifiers = config.verifier_settings.scale_verifiers;
|
||||||
|
|
||||||
let num_cpus = ::num_cpus::get();
|
let num_cpus = ::num_cpus::get();
|
||||||
let max_verifiers = min(num_cpus, MAX_VERIFIERS);
|
let max_verifiers = cmp::min(num_cpus, MAX_VERIFIERS);
|
||||||
let default_amount = max(1, min(max_verifiers, config.verifier_settings.num_verifiers));
|
let default_amount = cmp::max(1, cmp::min(max_verifiers, config.verifier_settings.num_verifiers));
|
||||||
let state = Arc::new((Mutex::new(State::Work(default_amount)), Condvar::new()));
|
let state = Arc::new((Mutex::new(State::Work(default_amount)), Condvar::new()));
|
||||||
let mut verifier_handles = Vec::with_capacity(max_verifiers);
|
let mut verifier_handles = Vec::with_capacity(max_verifiers);
|
||||||
|
|
||||||
@ -278,8 +280,8 @@ impl<K: Kind> VerificationQueue<K> {
|
|||||||
processing: RwLock::new(HashMap::new()),
|
processing: RwLock::new(HashMap::new()),
|
||||||
empty: empty,
|
empty: empty,
|
||||||
ticks_since_adjustment: AtomicUsize::new(0),
|
ticks_since_adjustment: AtomicUsize::new(0),
|
||||||
max_queue_size: max(config.max_queue_size, MIN_QUEUE_LIMIT),
|
max_queue_size: cmp::max(config.max_queue_size, MIN_QUEUE_LIMIT),
|
||||||
max_mem_use: max(config.max_mem_use, MIN_MEM_LIMIT),
|
max_mem_use: cmp::max(config.max_mem_use, MIN_MEM_LIMIT),
|
||||||
scale_verifiers: scale_verifiers,
|
scale_verifiers: scale_verifiers,
|
||||||
verifier_handles: verifier_handles,
|
verifier_handles: verifier_handles,
|
||||||
state: state,
|
state: state,
|
||||||
@ -567,7 +569,7 @@ impl<K: Kind> VerificationQueue<K> {
|
|||||||
/// Removes up to `max` verified items from the queue
|
/// Removes up to `max` verified items from the queue
|
||||||
pub fn drain(&self, max: usize) -> Vec<K::Verified> {
|
pub fn drain(&self, max: usize) -> Vec<K::Verified> {
|
||||||
let mut verified = self.verification.verified.lock();
|
let mut verified = self.verification.verified.lock();
|
||||||
let count = min(max, verified.len());
|
let count = cmp::min(max, verified.len());
|
||||||
let result = verified.drain(..count).collect::<Vec<_>>();
|
let result = verified.drain(..count).collect::<Vec<_>>();
|
||||||
|
|
||||||
let drained_size = result.iter().map(HeapSizeOf::heap_size_of_children).fold(0, |a, c| a + c);
|
let drained_size = result.iter().map(HeapSizeOf::heap_size_of_children).fold(0, |a, c| a + c);
|
||||||
@ -687,8 +689,8 @@ impl<K: Kind> VerificationQueue<K> {
|
|||||||
// or below 1.
|
// or below 1.
|
||||||
fn scale_verifiers(&self, target: usize) {
|
fn scale_verifiers(&self, target: usize) {
|
||||||
let current = self.num_verifiers();
|
let current = self.num_verifiers();
|
||||||
let target = min(self.verifier_handles.len(), target);
|
let target = cmp::min(self.verifier_handles.len(), target);
|
||||||
let target = max(1, target);
|
let target = cmp::max(1, target);
|
||||||
|
|
||||||
debug!(target: "verification", "Scaling from {} to {} verifiers", current, target);
|
debug!(target: "verification", "Scaling from {} to {} verifiers", current, target);
|
||||||
|
|
||||||
@ -725,7 +727,6 @@ impl<K: Kind> Drop for VerificationQueue<K> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use util::*;
|
|
||||||
use io::*;
|
use io::*;
|
||||||
use spec::*;
|
use spec::*;
|
||||||
use super::{BlockQueue, Config, State};
|
use super::{BlockQueue, Config, State};
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
//! 2. Signatures verification done in the queue.
|
//! 2. Signatures verification done in the queue.
|
||||||
//! 3. Final verification against the blockchain done before enactment.
|
//! 3. Final verification against the blockchain done before enactment.
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
use util::*;
|
use util::*;
|
||||||
use engines::Engine;
|
use engines::Engine;
|
||||||
use error::{BlockError, Error};
|
use error::{BlockError, Error};
|
||||||
@ -264,6 +265,7 @@ fn verify_block_integrity(block: &[u8], transactions_root: &H256, uncles_hash: &
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::collections::{BTreeMap, HashMap};
|
||||||
use util::*;
|
use util::*;
|
||||||
use ethkey::{Random, Generator};
|
use ethkey::{Random, Generator};
|
||||||
use header::*;
|
use header::*;
|
||||||
|
@ -8,6 +8,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
|||||||
rlp = { path = "../../util/rlp" }
|
rlp = { path = "../../util/rlp" }
|
||||||
ethcore-util = { path = "../../util" }
|
ethcore-util = { path = "../../util" }
|
||||||
ethjson = { path = "../../json" }
|
ethjson = { path = "../../json" }
|
||||||
|
bloomable = { path = "../../util/bloomable" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rustc-hex= "1.0"
|
rustc-hex= "1.0"
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
//! Blockchain filter
|
//! Blockchain filter
|
||||||
|
|
||||||
use util::{Address, H256, Hashable, H2048};
|
use util::{Address, H256, Hashable, H2048};
|
||||||
use util::bloom::Bloomable;
|
use bloomable::Bloomable;
|
||||||
use ids::BlockId;
|
use ids::BlockId;
|
||||||
use log_entry::LogEntry;
|
use log_entry::LogEntry;
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
extern crate ethcore_util as util;
|
extern crate ethcore_util as util;
|
||||||
extern crate ethjson;
|
extern crate ethjson;
|
||||||
extern crate rlp;
|
extern crate rlp;
|
||||||
|
extern crate bloomable;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
extern crate rustc_hex;
|
extern crate rustc_hex;
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use util::{H256, Address, Bytes, HeapSizeOf, Hashable};
|
use util::{H256, Address, Bytes, HeapSizeOf, Hashable};
|
||||||
use util::bloom::Bloomable;
|
use bloomable::Bloomable;
|
||||||
use rlp::*;
|
use rlp::*;
|
||||||
|
|
||||||
use {BlockNumber};
|
use {BlockNumber};
|
||||||
@ -114,8 +114,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_empty_log_bloom() {
|
fn test_empty_log_bloom() {
|
||||||
let bloom = H2048::from_str("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
let bloom = "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".parse::<H2048>().unwrap();
|
||||||
let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap();
|
let address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse::<Address>().unwrap();
|
||||||
let log = LogEntry {
|
let log = LogEntry {
|
||||||
address: address,
|
address: address,
|
||||||
topics: vec![],
|
topics: vec![],
|
||||||
|
14
ethcore/vm/Cargo.toml
Normal file
14
ethcore/vm/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[package]
|
||||||
|
name = "vm"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
byteorder = "1.0"
|
||||||
|
ethcore-util = { path = "../../util" }
|
||||||
|
log = "0.3"
|
||||||
|
common-types = { path = "../types" }
|
||||||
|
evmjit = { path = "../../evmjit", optional = true }
|
||||||
|
ethjson = { path = "../../json" }
|
||||||
|
lazy_static = "0.2"
|
||||||
|
rlp = { path = "../../util/rlp" }
|
@ -20,7 +20,7 @@ use util::hash::{H256};
|
|||||||
use util::sha3::{Hashable, SHA3_EMPTY};
|
use util::sha3::{Hashable, SHA3_EMPTY};
|
||||||
use ethjson;
|
use ethjson;
|
||||||
|
|
||||||
use {CallType};
|
use call_type::CallType;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
100
ethcore/vm/src/error.rs
Normal file
100
ethcore/vm/src/error.rs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity 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.
|
||||||
|
|
||||||
|
// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! VM errors module
|
||||||
|
|
||||||
|
use util::trie;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
/// VM errors.
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum Error {
|
||||||
|
/// `OutOfGas` is returned when transaction execution runs out of gas.
|
||||||
|
/// The state should be reverted to the state from before the
|
||||||
|
/// transaction execution. But it does not mean that transaction
|
||||||
|
/// was invalid. Balance still should be transfered and nonce
|
||||||
|
/// should be increased.
|
||||||
|
OutOfGas,
|
||||||
|
/// `BadJumpDestination` is returned when execution tried to move
|
||||||
|
/// to position that wasn't marked with JUMPDEST instruction
|
||||||
|
BadJumpDestination {
|
||||||
|
/// Position the code tried to jump to.
|
||||||
|
destination: usize
|
||||||
|
},
|
||||||
|
/// `BadInstructions` is returned when given instruction is not supported
|
||||||
|
BadInstruction {
|
||||||
|
/// Unrecognized opcode
|
||||||
|
instruction: u8,
|
||||||
|
},
|
||||||
|
/// `StackUnderflow` when there is not enough stack elements to execute instruction
|
||||||
|
StackUnderflow {
|
||||||
|
/// Invoked instruction
|
||||||
|
instruction: &'static str,
|
||||||
|
/// How many stack elements was requested by instruction
|
||||||
|
wanted: usize,
|
||||||
|
/// How many elements were on stack
|
||||||
|
on_stack: usize
|
||||||
|
},
|
||||||
|
/// When execution would exceed defined Stack Limit
|
||||||
|
OutOfStack {
|
||||||
|
/// Invoked instruction
|
||||||
|
instruction: &'static str,
|
||||||
|
/// How many stack elements instruction wanted to push
|
||||||
|
wanted: usize,
|
||||||
|
/// What was the stack limit
|
||||||
|
limit: usize
|
||||||
|
},
|
||||||
|
/// Built-in contract failed on given input
|
||||||
|
BuiltIn(&'static str),
|
||||||
|
/// When execution tries to modify the state in static context
|
||||||
|
MutableCallInStaticContext,
|
||||||
|
/// Likely to cause consensus issues.
|
||||||
|
Internal(String),
|
||||||
|
/// Wasm runtime error
|
||||||
|
Wasm(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl From<Box<trie::TrieError>> for Error {
|
||||||
|
fn from(err: Box<trie::TrieError>) -> Self {
|
||||||
|
Error::Internal(format!("Internal error: {}", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl From<wasm::RuntimeError> for Error {
|
||||||
|
// fn from(err: wasm::RuntimeError) -> Self {
|
||||||
|
// Error::Wasm(format!("Runtime error: {:?}", err))
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
use self::Error::*;
|
||||||
|
match *self {
|
||||||
|
OutOfGas => write!(f, "Out of gas"),
|
||||||
|
BadJumpDestination { destination } => write!(f, "Bad jump destination {:x}", destination),
|
||||||
|
BadInstruction { instruction } => write!(f, "Bad instruction {:x}", instruction),
|
||||||
|
StackUnderflow { instruction, wanted, on_stack } => write!(f, "Stack underflow {} {}/{}", instruction, wanted, on_stack),
|
||||||
|
OutOfStack { instruction, wanted, limit } => write!(f, "Out of stack {} {}/{}", instruction, wanted, limit),
|
||||||
|
BuiltIn(name) => write!(f, "Built-in failed: {}", name),
|
||||||
|
Internal(ref msg) => write!(f, "Internal error: {}", msg),
|
||||||
|
MutableCallInStaticContext => write!(f, "Mutable call in static context"),
|
||||||
|
Wasm(ref msg) => write!(f, "Internal error: {}", msg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Result<T> = ::std::result::Result<T, Error>;
|
@ -16,11 +16,13 @@
|
|||||||
|
|
||||||
//! Interface for Evm externalities.
|
//! Interface for Evm externalities.
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
use util::*;
|
use util::*;
|
||||||
use call_type::CallType;
|
use call_type::CallType;
|
||||||
use env_info::EnvInfo;
|
use env_info::EnvInfo;
|
||||||
use schedule::Schedule;
|
use schedule::Schedule;
|
||||||
use evm::{self, ReturnData};
|
use return_data::ReturnData;
|
||||||
|
use error::Result;
|
||||||
|
|
||||||
/// Result of externalities create function.
|
/// Result of externalities create function.
|
||||||
pub enum ContractCreateResult {
|
pub enum ContractCreateResult {
|
||||||
@ -56,22 +58,22 @@ pub enum CreateContractAddress {
|
|||||||
/// Externalities interface for EVMs
|
/// Externalities interface for EVMs
|
||||||
pub trait Ext {
|
pub trait Ext {
|
||||||
/// Returns a value for given key.
|
/// Returns a value for given key.
|
||||||
fn storage_at(&self, key: &H256) -> evm::Result<H256>;
|
fn storage_at(&self, key: &H256) -> Result<H256>;
|
||||||
|
|
||||||
/// Stores a value for given key.
|
/// Stores a value for given key.
|
||||||
fn set_storage(&mut self, key: H256, value: H256) -> evm::Result<()>;
|
fn set_storage(&mut self, key: H256, value: H256) -> Result<()>;
|
||||||
|
|
||||||
/// Determine whether an account exists.
|
/// Determine whether an account exists.
|
||||||
fn exists(&self, address: &Address) -> evm::Result<bool>;
|
fn exists(&self, address: &Address) -> Result<bool>;
|
||||||
|
|
||||||
/// Determine whether an account exists and is not null (zero balance/nonce, no code).
|
/// Determine whether an account exists and is not null (zero balance/nonce, no code).
|
||||||
fn exists_and_not_null(&self, address: &Address) -> evm::Result<bool>;
|
fn exists_and_not_null(&self, address: &Address) -> Result<bool>;
|
||||||
|
|
||||||
/// Balance of the origin account.
|
/// Balance of the origin account.
|
||||||
fn origin_balance(&self) -> evm::Result<U256>;
|
fn origin_balance(&self) -> Result<U256>;
|
||||||
|
|
||||||
/// Returns address balance.
|
/// Returns address balance.
|
||||||
fn balance(&self, address: &Address) -> evm::Result<U256>;
|
fn balance(&self, address: &Address) -> Result<U256>;
|
||||||
|
|
||||||
/// Returns the hash of one of the 256 most recent complete blocks.
|
/// Returns the hash of one of the 256 most recent complete blocks.
|
||||||
fn blockhash(&mut self, number: &U256) -> H256;
|
fn blockhash(&mut self, number: &U256) -> H256;
|
||||||
@ -99,21 +101,21 @@ pub trait Ext {
|
|||||||
) -> MessageCallResult;
|
) -> MessageCallResult;
|
||||||
|
|
||||||
/// Returns code at given address
|
/// Returns code at given address
|
||||||
fn extcode(&self, address: &Address) -> evm::Result<Arc<Bytes>>;
|
fn extcode(&self, address: &Address) -> Result<Arc<Bytes>>;
|
||||||
|
|
||||||
/// Returns code size at given address
|
/// Returns code size at given address
|
||||||
fn extcodesize(&self, address: &Address) -> evm::Result<usize>;
|
fn extcodesize(&self, address: &Address) -> Result<usize>;
|
||||||
|
|
||||||
/// Creates log entry with given topics and data
|
/// Creates log entry with given topics and data
|
||||||
fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> evm::Result<()>;
|
fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> Result<()>;
|
||||||
|
|
||||||
/// Should be called when transaction calls `RETURN` opcode.
|
/// Should be called when transaction calls `RETURN` opcode.
|
||||||
/// Returns gas_left if cost of returning the data is not too high.
|
/// Returns gas_left if cost of returning the data is not too high.
|
||||||
fn ret(self, gas: &U256, data: &ReturnData) -> evm::Result<U256>;
|
fn ret(self, gas: &U256, data: &ReturnData) -> Result<U256>;
|
||||||
|
|
||||||
/// Should be called when contract commits suicide.
|
/// Should be called when contract commits suicide.
|
||||||
/// Address to which funds should be refunded.
|
/// Address to which funds should be refunded.
|
||||||
fn suicide(&mut self, refund_address: &Address) -> evm::Result<()> ;
|
fn suicide(&mut self, refund_address: &Address) -> Result<()> ;
|
||||||
|
|
||||||
/// Returns schedule.
|
/// Returns schedule.
|
||||||
fn schedule(&self) -> &Schedule;
|
fn schedule(&self) -> &Schedule;
|
48
ethcore/vm/src/lib.rs
Normal file
48
ethcore/vm/src/lib.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity 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.
|
||||||
|
|
||||||
|
// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Virtual machines support library
|
||||||
|
|
||||||
|
extern crate ethcore_util as util;
|
||||||
|
extern crate common_types as types;
|
||||||
|
extern crate ethjson;
|
||||||
|
extern crate rlp;
|
||||||
|
|
||||||
|
mod action_params;
|
||||||
|
mod call_type;
|
||||||
|
mod env_info;
|
||||||
|
mod schedule;
|
||||||
|
mod ext;
|
||||||
|
mod return_data;
|
||||||
|
mod error;
|
||||||
|
|
||||||
|
pub mod tests;
|
||||||
|
|
||||||
|
pub use action_params::{ActionParams, ActionValue};
|
||||||
|
pub use call_type::CallType;
|
||||||
|
pub use env_info::{EnvInfo, LastHashes};
|
||||||
|
pub use schedule::{Schedule, CleanDustMode};
|
||||||
|
pub use ext::{Ext, MessageCallResult, ContractCreateResult, CreateContractAddress};
|
||||||
|
pub use return_data::{ReturnData, GasLeft};
|
||||||
|
pub use error::{Error, Result};
|
||||||
|
|
||||||
|
/// Virtual Machine interface
|
||||||
|
pub trait Vm {
|
||||||
|
/// This function should be used to execute transaction.
|
||||||
|
/// It returns either an error, a known amount of gas left, or parameters to be used
|
||||||
|
/// to compute the final gas left.
|
||||||
|
fn exec(&mut self, params: ActionParams, ext: &mut Ext) -> Result<GasLeft>;
|
||||||
|
}
|
68
ethcore/vm/src/return_data.rs
Normal file
68
ethcore/vm/src/return_data.rs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
|
||||||
|
// Parity 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.
|
||||||
|
|
||||||
|
// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Return data structures
|
||||||
|
|
||||||
|
use util::U256;
|
||||||
|
|
||||||
|
/// Return data buffer. Holds memory from a previous call and a slice into that memory.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ReturnData {
|
||||||
|
mem: Vec<u8>,
|
||||||
|
offset: usize,
|
||||||
|
size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::ops::Deref for ReturnData {
|
||||||
|
type Target = [u8];
|
||||||
|
fn deref(&self) -> &[u8] {
|
||||||
|
&self.mem[self.offset..self.offset + self.size]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReturnData {
|
||||||
|
/// Create empty `ReturnData`.
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
ReturnData {
|
||||||
|
mem: Vec::new(),
|
||||||
|
offset: 0,
|
||||||
|
size: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Create `ReturnData` from give buffer and slice.
|
||||||
|
pub fn new(mem: Vec<u8>, offset: usize, size: usize) -> Self {
|
||||||
|
ReturnData {
|
||||||
|
mem: mem,
|
||||||
|
offset: offset,
|
||||||
|
size: size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gas Left: either it is a known value, or it needs to be computed by processing
|
||||||
|
/// a return instruction.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum GasLeft {
|
||||||
|
/// Known gas left
|
||||||
|
Known(U256),
|
||||||
|
/// Return or Revert instruction must be processed.
|
||||||
|
NeedsReturn {
|
||||||
|
/// Amount of gas left.
|
||||||
|
gas_left: U256,
|
||||||
|
/// Return data buffer.
|
||||||
|
data: ReturnData,
|
||||||
|
/// Apply or revert state changes on revert.
|
||||||
|
apply_state: bool
|
||||||
|
},
|
||||||
|
}
|
@ -250,6 +250,12 @@ impl Schedule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Schedule {
|
||||||
|
fn default() -> Self {
|
||||||
|
Schedule::new_frontier()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn schedule_evm_assumptions() {
|
fn schedule_evm_assumptions() {
|
||||||
@ -260,3 +266,4 @@ fn schedule_evm_assumptions() {
|
|||||||
assert_eq!(s1.quad_coeff_div, 512);
|
assert_eq!(s1.quad_coeff_div, 512);
|
||||||
assert_eq!(s2.quad_coeff_div, 512);
|
assert_eq!(s2.quad_coeff_div, 512);
|
||||||
}
|
}
|
||||||
|
|
187
ethcore/vm/src/tests.rs
Normal file
187
ethcore/vm/src/tests.rs
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity 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.
|
||||||
|
|
||||||
|
// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
|
use util::{H256, U256, Address, Bytes};
|
||||||
|
use {
|
||||||
|
CallType, Schedule, EnvInfo,
|
||||||
|
ReturnData, Ext, ContractCreateResult, MessageCallResult,
|
||||||
|
CreateContractAddress, Result, GasLeft,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct FakeLogEntry {
|
||||||
|
pub topics: Vec<H256>,
|
||||||
|
pub data: Bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Hash, Debug)]
|
||||||
|
pub enum FakeCallType {
|
||||||
|
Call, Create
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Hash, Debug)]
|
||||||
|
pub struct FakeCall {
|
||||||
|
pub call_type: FakeCallType,
|
||||||
|
pub gas: U256,
|
||||||
|
pub sender_address: Option<Address>,
|
||||||
|
pub receive_address: Option<Address>,
|
||||||
|
pub value: Option<U256>,
|
||||||
|
pub data: Bytes,
|
||||||
|
pub code_address: Option<Address>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fake externalities test structure.
|
||||||
|
///
|
||||||
|
/// Can't do recursive calls.
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct FakeExt {
|
||||||
|
pub store: HashMap<H256, H256>,
|
||||||
|
pub suicides: HashSet<Address>,
|
||||||
|
pub calls: HashSet<FakeCall>,
|
||||||
|
pub sstore_clears: usize,
|
||||||
|
pub depth: usize,
|
||||||
|
pub blockhashes: HashMap<U256, H256>,
|
||||||
|
pub codes: HashMap<Address, Arc<Bytes>>,
|
||||||
|
pub logs: Vec<FakeLogEntry>,
|
||||||
|
pub info: EnvInfo,
|
||||||
|
pub schedule: Schedule,
|
||||||
|
pub balances: HashMap<Address, U256>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// similar to the normal `finalize` function, but ignoring NeedsReturn.
|
||||||
|
pub fn test_finalize(res: Result<GasLeft>) -> Result<U256> {
|
||||||
|
match res {
|
||||||
|
Ok(GasLeft::Known(gas)) => Ok(gas),
|
||||||
|
Ok(GasLeft::NeedsReturn{..}) => unimplemented!(), // since ret is unimplemented.
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FakeExt {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
FakeExt::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ext for FakeExt {
|
||||||
|
fn storage_at(&self, key: &H256) -> Result<H256> {
|
||||||
|
Ok(self.store.get(key).unwrap_or(&H256::new()).clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_storage(&mut self, key: H256, value: H256) -> Result<()> {
|
||||||
|
self.store.insert(key, value);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exists(&self, address: &Address) -> Result<bool> {
|
||||||
|
Ok(self.balances.contains_key(address))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exists_and_not_null(&self, address: &Address) -> Result<bool> {
|
||||||
|
Ok(self.balances.get(address).map_or(false, |b| !b.is_zero()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn origin_balance(&self) -> Result<U256> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn balance(&self, address: &Address) -> Result<U256> {
|
||||||
|
Ok(self.balances[address])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blockhash(&mut self, number: &U256) -> H256 {
|
||||||
|
self.blockhashes.get(number).unwrap_or(&H256::new()).clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create(&mut self, gas: &U256, value: &U256, code: &[u8], _address: CreateContractAddress) -> ContractCreateResult {
|
||||||
|
self.calls.insert(FakeCall {
|
||||||
|
call_type: FakeCallType::Create,
|
||||||
|
gas: *gas,
|
||||||
|
sender_address: None,
|
||||||
|
receive_address: None,
|
||||||
|
value: Some(*value),
|
||||||
|
data: code.to_vec(),
|
||||||
|
code_address: None
|
||||||
|
});
|
||||||
|
ContractCreateResult::Failed
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(&mut self,
|
||||||
|
gas: &U256,
|
||||||
|
sender_address: &Address,
|
||||||
|
receive_address: &Address,
|
||||||
|
value: Option<U256>,
|
||||||
|
data: &[u8],
|
||||||
|
code_address: &Address,
|
||||||
|
_output: &mut [u8],
|
||||||
|
_call_type: CallType
|
||||||
|
) -> MessageCallResult {
|
||||||
|
|
||||||
|
self.calls.insert(FakeCall {
|
||||||
|
call_type: FakeCallType::Call,
|
||||||
|
gas: *gas,
|
||||||
|
sender_address: Some(sender_address.clone()),
|
||||||
|
receive_address: Some(receive_address.clone()),
|
||||||
|
value: value,
|
||||||
|
data: data.to_vec(),
|
||||||
|
code_address: Some(code_address.clone())
|
||||||
|
});
|
||||||
|
MessageCallResult::Success(*gas, ReturnData::empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extcode(&self, address: &Address) -> Result<Arc<Bytes>> {
|
||||||
|
Ok(self.codes.get(address).unwrap_or(&Arc::new(Bytes::new())).clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extcodesize(&self, address: &Address) -> Result<usize> {
|
||||||
|
Ok(self.codes.get(address).map_or(0, |c| c.len()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn log(&mut self, topics: Vec<H256>, data: &[u8]) -> Result<()> {
|
||||||
|
self.logs.push(FakeLogEntry {
|
||||||
|
topics: topics,
|
||||||
|
data: data.to_vec()
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ret(self, _gas: &U256, _data: &ReturnData) -> Result<U256> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn suicide(&mut self, refund_address: &Address) -> Result<()> {
|
||||||
|
self.suicides.insert(refund_address.clone());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn schedule(&self) -> &Schedule {
|
||||||
|
&self.schedule
|
||||||
|
}
|
||||||
|
|
||||||
|
fn env_info(&self) -> &EnvInfo {
|
||||||
|
&self.info
|
||||||
|
}
|
||||||
|
|
||||||
|
fn depth(&self) -> usize {
|
||||||
|
self.depth
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inc_sstore_clears(&mut self) {
|
||||||
|
self.sstore_clears += 1;
|
||||||
|
}
|
||||||
|
}
|
13
ethcore/wasm/Cargo.toml
Normal file
13
ethcore/wasm/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "wasm"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
byteorder = "1.0"
|
||||||
|
ethcore-util = { path = "../../util" }
|
||||||
|
log = "0.3"
|
||||||
|
parity-wasm = "0.12"
|
||||||
|
wasm-utils = { git = "https://github.com/paritytech/wasm-utils" }
|
||||||
|
vm = { path = "../vm" }
|
||||||
|
ethcore-logger = { path = "../../logger" }
|
@ -61,6 +61,21 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
|
|||||||
&[I32; 4],
|
&[I32; 4],
|
||||||
Some(I32),
|
Some(I32),
|
||||||
),
|
),
|
||||||
|
Static(
|
||||||
|
"_ccall",
|
||||||
|
&[I32; 6],
|
||||||
|
Some(I32),
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"_dcall",
|
||||||
|
&[I32; 5],
|
||||||
|
Some(I32),
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"_scall",
|
||||||
|
&[I32; 5],
|
||||||
|
Some(I32),
|
||||||
|
),
|
||||||
Static(
|
Static(
|
||||||
"abort",
|
"abort",
|
||||||
&[I32],
|
&[I32],
|
||||||
@ -72,48 +87,57 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[
|
|||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
Static(
|
Static(
|
||||||
"invoke_vii",
|
"abortOnCannotGrowMemory",
|
||||||
&[I32; 3],
|
&[I32; 0],
|
||||||
None,
|
Some(I32)
|
||||||
),
|
|
||||||
Static(
|
|
||||||
"invoke_vi",
|
|
||||||
&[I32; 2],
|
|
||||||
None,
|
|
||||||
),
|
|
||||||
Static(
|
|
||||||
"invoke_v",
|
|
||||||
&[I32],
|
|
||||||
None,
|
|
||||||
),
|
|
||||||
Static(
|
|
||||||
"invoke_iii",
|
|
||||||
&[I32; 3],
|
|
||||||
Some(I32),
|
|
||||||
),
|
|
||||||
Static(
|
|
||||||
"___resumeException",
|
|
||||||
&[I32],
|
|
||||||
None,
|
|
||||||
),
|
),
|
||||||
|
|
||||||
|
/*
|
||||||
|
THIS IS EXPERIMENTAL RUST-ONLY RUNTIME EXTERNS, THEY ARE SUBJECT TO CHANGE
|
||||||
|
|
||||||
|
AVOID YOUR WASM CONTAINS ANY OF THESE OTHERWISE
|
||||||
|
EITHER FACE THE NEED OF HARDFORK
|
||||||
|
OR YOU CAN STUCK ON SPECIFIC RUST VERSION FOR WASM COMPILATION
|
||||||
|
*/
|
||||||
|
|
||||||
Static(
|
Static(
|
||||||
"_rust_begin_unwind",
|
"_rust_begin_unwind",
|
||||||
&[I32; 4],
|
&[I32; 4],
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
Static(
|
|
||||||
"___cxa_find_matching_catch_2",
|
|
||||||
&[],
|
|
||||||
Some(I32),
|
|
||||||
),
|
|
||||||
Static(
|
|
||||||
"___gxx_personality_v0",
|
|
||||||
&[I32; 6],
|
|
||||||
Some(I32),
|
|
||||||
),
|
|
||||||
Static(
|
Static(
|
||||||
"_emscripten_memcpy_big",
|
"_emscripten_memcpy_big",
|
||||||
&[I32; 3],
|
&[I32; 3],
|
||||||
Some(I32),
|
Some(I32),
|
||||||
)
|
),
|
||||||
|
Static(
|
||||||
|
"___syscall6",
|
||||||
|
&[I32; 2],
|
||||||
|
Some(I32),
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"___syscall140",
|
||||||
|
&[I32; 2],
|
||||||
|
Some(I32)
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"___syscall146",
|
||||||
|
&[I32; 2],
|
||||||
|
Some(I32)
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"___syscall54",
|
||||||
|
&[I32; 2],
|
||||||
|
Some(I32)
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"_llvm_trap",
|
||||||
|
&[I32; 0],
|
||||||
|
None
|
||||||
|
),
|
||||||
|
Static(
|
||||||
|
"___setErrNo",
|
||||||
|
&[I32; 1],
|
||||||
|
None
|
||||||
|
),
|
||||||
];
|
];
|
@ -16,6 +16,14 @@
|
|||||||
|
|
||||||
//! Wasm Interpreter
|
//! Wasm Interpreter
|
||||||
|
|
||||||
|
extern crate vm;
|
||||||
|
extern crate ethcore_util as util;
|
||||||
|
#[macro_use] extern crate log;
|
||||||
|
extern crate ethcore_logger;
|
||||||
|
extern crate byteorder;
|
||||||
|
extern crate parity_wasm;
|
||||||
|
extern crate wasm_utils;
|
||||||
|
|
||||||
mod runtime;
|
mod runtime;
|
||||||
mod ptr;
|
mod ptr;
|
||||||
mod call_args;
|
mod call_args;
|
||||||
@ -30,11 +38,9 @@ const DEFAULT_STACK_SPACE: u32 = 5 * 1024 * 1024;
|
|||||||
|
|
||||||
use parity_wasm::{interpreter, elements};
|
use parity_wasm::{interpreter, elements};
|
||||||
use parity_wasm::interpreter::ModuleInstanceInterface;
|
use parity_wasm::interpreter::ModuleInstanceInterface;
|
||||||
use wasm_utils;
|
|
||||||
|
|
||||||
use evm::{self, GasLeft, ReturnData};
|
use vm::{GasLeft, ReturnData, ActionParams};
|
||||||
use action_params::ActionParams;
|
use self::runtime::{Runtime, RuntimeContext};
|
||||||
use self::runtime::Runtime;
|
|
||||||
|
|
||||||
pub use self::runtime::Error as RuntimeError;
|
pub use self::runtime::Error as RuntimeError;
|
||||||
|
|
||||||
@ -56,9 +62,9 @@ impl WasmInterpreter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl evm::Evm for WasmInterpreter {
|
impl vm::Vm for WasmInterpreter {
|
||||||
|
|
||||||
fn exec(&mut self, params: ActionParams, ext: &mut ::ext::Ext) -> evm::Result<GasLeft> {
|
fn exec(&mut self, params: ActionParams, ext: &mut vm::Ext) -> vm::Result<GasLeft> {
|
||||||
use parity_wasm::elements::Deserialize;
|
use parity_wasm::elements::Deserialize;
|
||||||
|
|
||||||
let code = params.code.expect("exec is only called on contract with code; qed");
|
let code = params.code.expect("exec is only called on contract with code; qed");
|
||||||
@ -74,7 +80,7 @@ impl evm::Evm for WasmInterpreter {
|
|||||||
.expect("Linear memory to exist in wasm runtime");
|
.expect("Linear memory to exist in wasm runtime");
|
||||||
|
|
||||||
if params.gas > ::std::u64::MAX.into() {
|
if params.gas > ::std::u64::MAX.into() {
|
||||||
return Err(evm::Error::Wasm("Wasm interpreter cannot run contracts with gas >= 2^64".to_owned()));
|
return Err(vm::Error::Wasm("Wasm interpreter cannot run contracts with gas >= 2^64".to_owned()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut runtime = Runtime::with_params(
|
let mut runtime = Runtime::with_params(
|
||||||
@ -82,6 +88,7 @@ impl evm::Evm for WasmInterpreter {
|
|||||||
env_memory,
|
env_memory,
|
||||||
DEFAULT_STACK_SPACE,
|
DEFAULT_STACK_SPACE,
|
||||||
params.gas.low_u64(),
|
params.gas.low_u64(),
|
||||||
|
RuntimeContext::new(params.address, params.sender),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut cursor = ::std::io::Cursor::new(&*code);
|
let mut cursor = ::std::io::Cursor::new(&*code);
|
||||||
@ -90,7 +97,7 @@ impl evm::Evm for WasmInterpreter {
|
|||||||
elements::Module::deserialize(
|
elements::Module::deserialize(
|
||||||
&mut cursor
|
&mut cursor
|
||||||
).map_err(|err| {
|
).map_err(|err| {
|
||||||
evm::Error::Wasm(format!("Error deserializing contract code ({:?})", err))
|
vm::Error::Wasm(format!("Error deserializing contract code ({:?})", err))
|
||||||
})?
|
})?
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -111,7 +118,7 @@ impl evm::Evm for WasmInterpreter {
|
|||||||
interpreter::env_native_module(env_instance, native_bindings(&mut runtime))
|
interpreter::env_native_module(env_instance, native_bindings(&mut runtime))
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
// todo: prefer explicit panic here also?
|
// todo: prefer explicit panic here also?
|
||||||
evm::Error::Wasm(format!("Error instantiating native bindings: {:?}", err))
|
vm::Error::Wasm(format!("Error instantiating native bindings: {:?}", err))
|
||||||
})?
|
})?
|
||||||
)
|
)
|
||||||
).add_argument(interpreter::RuntimeValue::I32(d_ptr.as_raw() as i32));
|
).add_argument(interpreter::RuntimeValue::I32(d_ptr.as_raw() as i32));
|
||||||
@ -119,13 +126,13 @@ impl evm::Evm for WasmInterpreter {
|
|||||||
let module_instance = self.program.add_module("contract", contract_module, Some(&execution_params.externals))
|
let module_instance = self.program.add_module("contract", contract_module, Some(&execution_params.externals))
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
trace!(target: "wasm", "Error adding contract module: {:?}", err);
|
trace!(target: "wasm", "Error adding contract module: {:?}", err);
|
||||||
evm::Error::from(RuntimeError::Interpreter(err))
|
vm::Error::from(RuntimeError::Interpreter(err))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
module_instance.execute_export("_call", execution_params)
|
module_instance.execute_export("_call", execution_params)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
trace!(target: "wasm", "Error executing contract: {:?}", err);
|
trace!(target: "wasm", "Error executing contract: {:?}", err);
|
||||||
evm::Error::from(RuntimeError::Interpreter(err))
|
vm::Error::from(RuntimeError::Interpreter(err))
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,3 +164,9 @@ fn native_bindings<'a>(runtime: &'a mut Runtime) -> interpreter::UserFunctions<'
|
|||||||
functions: ::std::borrow::Cow::from(env::SIGNATURES),
|
functions: ::std::borrow::Cow::from(env::SIGNATURES),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<runtime::Error> for vm::Error {
|
||||||
|
fn from(err: runtime::Error) -> vm::Error {
|
||||||
|
vm::Error::Wasm(format!("WASM runtime-error: {:?}", err))
|
||||||
|
}
|
||||||
|
}
|
@ -20,11 +20,11 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use byteorder::{LittleEndian, ByteOrder};
|
use byteorder::{LittleEndian, ByteOrder};
|
||||||
|
|
||||||
use ext;
|
use vm;
|
||||||
|
|
||||||
use parity_wasm::interpreter;
|
use parity_wasm::interpreter;
|
||||||
use util::{Address, H256, U256};
|
use util::{Address, H256, U256};
|
||||||
|
|
||||||
|
use vm::CallType;
|
||||||
use super::ptr::{WasmPtr, Error as PtrError};
|
use super::ptr::{WasmPtr, Error as PtrError};
|
||||||
use super::call_args::CallArgs;
|
use super::call_args::CallArgs;
|
||||||
|
|
||||||
@ -57,22 +57,38 @@ impl From<PtrError> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct RuntimeContext {
|
||||||
|
address: Address,
|
||||||
|
sender: Address,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RuntimeContext {
|
||||||
|
pub fn new(address: Address, sender: Address) -> Self {
|
||||||
|
RuntimeContext {
|
||||||
|
address: address,
|
||||||
|
sender: sender,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Runtime enviroment data for wasm contract execution
|
/// Runtime enviroment data for wasm contract execution
|
||||||
pub struct Runtime<'a> {
|
pub struct Runtime<'a> {
|
||||||
gas_counter: u64,
|
gas_counter: u64,
|
||||||
gas_limit: u64,
|
gas_limit: u64,
|
||||||
dynamic_top: u32,
|
dynamic_top: u32,
|
||||||
ext: &'a mut ext::Ext,
|
ext: &'a mut vm::Ext,
|
||||||
memory: Arc<interpreter::MemoryInstance>,
|
memory: Arc<interpreter::MemoryInstance>,
|
||||||
|
context: RuntimeContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Runtime<'a> {
|
impl<'a> Runtime<'a> {
|
||||||
/// New runtime for wasm contract with specified params
|
/// New runtime for wasm contract with specified params
|
||||||
pub fn with_params<'b>(
|
pub fn with_params<'b>(
|
||||||
ext: &'b mut ext::Ext,
|
ext: &'b mut vm::Ext,
|
||||||
memory: Arc<interpreter::MemoryInstance>,
|
memory: Arc<interpreter::MemoryInstance>,
|
||||||
stack_space: u32,
|
stack_space: u32,
|
||||||
gas_limit: u64,
|
gas_limit: u64,
|
||||||
|
context: RuntimeContext,
|
||||||
) -> Runtime<'b> {
|
) -> Runtime<'b> {
|
||||||
Runtime {
|
Runtime {
|
||||||
gas_counter: 0,
|
gas_counter: 0,
|
||||||
@ -80,6 +96,7 @@ impl<'a> Runtime<'a> {
|
|||||||
dynamic_top: stack_space,
|
dynamic_top: stack_space,
|
||||||
memory: memory,
|
memory: memory,
|
||||||
ext: ext,
|
ext: ext,
|
||||||
|
context: context,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,20 +170,141 @@ impl<'a> Runtime<'a> {
|
|||||||
.map_err(|_| interpreter::Error::Trap("Gas state error".to_owned()))?
|
.map_err(|_| interpreter::Error::Trap("Gas state error".to_owned()))?
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
match self.ext.create(&gas_left, &endowment, &code, ext::CreateContractAddress::FromSenderAndCodeHash) {
|
match self.ext.create(&gas_left, &endowment, &code, vm::CreateContractAddress::FromSenderAndCodeHash) {
|
||||||
ext::ContractCreateResult::Created(address, gas_left) => {
|
vm::ContractCreateResult::Created(address, gas_left) => {
|
||||||
self.memory.set(result_ptr, &*address)?;
|
self.memory.set(result_ptr, &*address)?;
|
||||||
self.gas_counter = self.gas_limit - gas_left.low_u64();
|
self.gas_counter = self.gas_limit - gas_left.low_u64();
|
||||||
trace!(target: "wasm", "runtime: create contract success (@{:?})", address);
|
trace!(target: "wasm", "runtime: create contract success (@{:?})", address);
|
||||||
Ok(Some(0i32.into()))
|
Ok(Some(0i32.into()))
|
||||||
},
|
},
|
||||||
ext::ContractCreateResult::Failed => {
|
vm::ContractCreateResult::Failed => {
|
||||||
trace!(target: "wasm", "runtime: create contract fail");
|
trace!(target: "wasm", "runtime: create contract fail");
|
||||||
Ok(Some((-1i32).into()))
|
Ok(Some((-1i32).into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn call(&mut self, context: interpreter::CallerContext)
|
||||||
|
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// method signature:
|
||||||
|
// fn (
|
||||||
|
// address: *const u8,
|
||||||
|
// val_ptr: *const u8,
|
||||||
|
// input_ptr: *const u8,
|
||||||
|
// input_len: u32,
|
||||||
|
// result_ptr: *mut u8,
|
||||||
|
// result_len: u32,
|
||||||
|
// ) -> i32
|
||||||
|
|
||||||
|
self.do_call(true, CallType::Call, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn call_code(&mut self, context: interpreter::CallerContext)
|
||||||
|
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// signature (same as static call):
|
||||||
|
// fn (
|
||||||
|
// address: *const u8,
|
||||||
|
// input_ptr: *const u8,
|
||||||
|
// input_len: u32,
|
||||||
|
// result_ptr: *mut u8,
|
||||||
|
// result_len: u32,
|
||||||
|
// ) -> i32
|
||||||
|
|
||||||
|
self.do_call(false, CallType::CallCode, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_call(
|
||||||
|
&mut self,
|
||||||
|
use_val: bool,
|
||||||
|
call_type: CallType,
|
||||||
|
context: interpreter::CallerContext,
|
||||||
|
)
|
||||||
|
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||||
|
{
|
||||||
|
|
||||||
|
trace!(target: "wasm", "runtime: call code");
|
||||||
|
let mut context = context;
|
||||||
|
let result_alloc_len = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
|
trace!(target: "wasm", " result_len: {:?}", result_alloc_len);
|
||||||
|
|
||||||
|
let result_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
|
trace!(target: "wasm", " result_ptr: {:?}", result_ptr);
|
||||||
|
|
||||||
|
let input_len = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
|
trace!(target: "wasm", " input_len: {:?}", input_len);
|
||||||
|
|
||||||
|
let input_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
|
trace!(target: "wasm", " input_ptr: {:?}", input_ptr);
|
||||||
|
|
||||||
|
let val = if use_val { Some(self.pop_u256(&mut context)?) }
|
||||||
|
else { None };
|
||||||
|
trace!(target: "wasm", " val: {:?}", val);
|
||||||
|
|
||||||
|
let address = self.pop_address(&mut context)?;
|
||||||
|
trace!(target: "wasm", " address: {:?}", address);
|
||||||
|
|
||||||
|
if let Some(ref val) = val {
|
||||||
|
let address_balance = self.ext.balance(&self.context.address)
|
||||||
|
.map_err(|_| interpreter::Error::Trap("Gas state error".to_owned()))?;
|
||||||
|
|
||||||
|
if &address_balance < val {
|
||||||
|
trace!(target: "wasm", "runtime: call failed due to balance check");
|
||||||
|
return Ok(Some((-1i32).into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut result = Vec::with_capacity(result_alloc_len as usize);
|
||||||
|
result.resize(result_alloc_len as usize, 0);
|
||||||
|
let gas = self.gas_left()
|
||||||
|
.map_err(|_| interpreter::Error::Trap("Gas state error".to_owned()))?
|
||||||
|
.into();
|
||||||
|
// todo: optimize to use memory views once it's in
|
||||||
|
let payload = self.memory.get(input_ptr, input_len as usize)?;
|
||||||
|
|
||||||
|
let call_result = self.ext.call(
|
||||||
|
&gas,
|
||||||
|
&self.context.sender,
|
||||||
|
&self.context.address,
|
||||||
|
val,
|
||||||
|
&payload,
|
||||||
|
&address,
|
||||||
|
&mut result[..],
|
||||||
|
call_type,
|
||||||
|
);
|
||||||
|
|
||||||
|
match call_result {
|
||||||
|
vm::MessageCallResult::Success(gas_left, _) => {
|
||||||
|
self.gas_counter = self.gas_limit - gas_left.low_u64();
|
||||||
|
self.memory.set(result_ptr, &result)?;
|
||||||
|
Ok(Some(0i32.into()))
|
||||||
|
},
|
||||||
|
vm::MessageCallResult::Failed => {
|
||||||
|
Ok(Some((-1i32).into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn static_call(&mut self, context: interpreter::CallerContext)
|
||||||
|
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||||
|
{
|
||||||
|
// signature (same as code call):
|
||||||
|
// fn (
|
||||||
|
// address: *const u8,
|
||||||
|
// input_ptr: *const u8,
|
||||||
|
// input_len: u32,
|
||||||
|
// result_ptr: *mut u8,
|
||||||
|
// result_len: u32,
|
||||||
|
// ) -> i32
|
||||||
|
|
||||||
|
self.do_call(false, CallType::StaticCall, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Allocate memory using the wasm stack params
|
/// Allocate memory using the wasm stack params
|
||||||
pub fn malloc(&mut self, context: interpreter::CallerContext)
|
pub fn malloc(&mut self, context: interpreter::CallerContext)
|
||||||
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
-> Result<Option<interpreter::RuntimeValue>, interpreter::Error>
|
||||||
@ -338,6 +476,15 @@ impl<'a> interpreter::UserFunctionExecutor for Runtime<'a> {
|
|||||||
"_create" => {
|
"_create" => {
|
||||||
self.create(context)
|
self.create(context)
|
||||||
},
|
},
|
||||||
|
"_ccall" => {
|
||||||
|
self.call(context)
|
||||||
|
},
|
||||||
|
"_dcall" => {
|
||||||
|
self.call_code(context)
|
||||||
|
},
|
||||||
|
"_scall" => {
|
||||||
|
self.static_call(context)
|
||||||
|
},
|
||||||
"_debug" => {
|
"_debug" => {
|
||||||
self.debug_log(context)
|
self.debug_log(context)
|
||||||
},
|
},
|
||||||
@ -348,7 +495,7 @@ impl<'a> interpreter::UserFunctionExecutor for Runtime<'a> {
|
|||||||
self.mem_copy(context)
|
self.mem_copy(context)
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
trace!("Unknown env func: '{}'", name);
|
trace!(target: "wasm", "Trapped due to unhandled function: '{}'", name);
|
||||||
self.user_trap(context)
|
self.user_trap(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -15,20 +15,20 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use byteorder::{LittleEndian, ByteOrder};
|
||||||
use super::super::tests::{FakeExt, FakeCall, FakeCallType};
|
|
||||||
use super::WasmInterpreter;
|
|
||||||
use evm::{self, Evm, GasLeft};
|
|
||||||
use action_params::{ActionParams, ActionValue};
|
|
||||||
use util::{U256, H256, Address};
|
use util::{U256, H256, Address};
|
||||||
|
|
||||||
|
use super::WasmInterpreter;
|
||||||
|
use vm::{self, Vm, GasLeft, ActionParams, ActionValue};
|
||||||
|
use vm::tests::{FakeCall, FakeExt, FakeCallType};
|
||||||
|
|
||||||
macro_rules! load_sample {
|
macro_rules! load_sample {
|
||||||
($name: expr) => {
|
($name: expr) => {
|
||||||
include_bytes!(concat!("../../../res/wasm-tests/compiled/", $name)).to_vec()
|
include_bytes!(concat!("../../res/wasm-tests/compiled/", $name)).to_vec()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_finalize(res: Result<GasLeft, evm::Error>) -> Result<U256, evm::Error> {
|
fn test_finalize(res: Result<GasLeft, vm::Error>) -> Result<U256, vm::Error> {
|
||||||
match res {
|
match res {
|
||||||
Ok(GasLeft::Known(gas)) => Ok(gas),
|
Ok(GasLeft::Known(gas)) => Ok(gas),
|
||||||
Ok(GasLeft::NeedsReturn{..}) => unimplemented!(), // since ret is unimplemented.
|
Ok(GasLeft::NeedsReturn{..}) => unimplemented!(), // since ret is unimplemented.
|
||||||
@ -85,7 +85,7 @@ fn logger() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
println!("ext.store: {:?}", ext.store);
|
println!("ext.store: {:?}", ext.store);
|
||||||
assert_eq!(gas_left, U256::from(99581));
|
assert_eq!(gas_left, U256::from(99590));
|
||||||
let address_val: H256 = address.into();
|
let address_val: H256 = address.into();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ext.store.get(&"0100000000000000000000000000000000000000000000000000000000000000".parse().unwrap()).expect("storage key to exist"),
|
ext.store.get(&"0100000000000000000000000000000000000000000000000000000000000000".parse().unwrap()).expect("storage key to exist"),
|
||||||
@ -136,7 +136,7 @@ fn identity() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(99_689));
|
assert_eq!(gas_left, U256::from(99_687));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Address::from_slice(&result),
|
Address::from_slice(&result),
|
||||||
@ -170,7 +170,7 @@ fn dispersion() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(99_402));
|
assert_eq!(gas_left, U256::from(99_423));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result,
|
result,
|
||||||
@ -199,7 +199,7 @@ fn suicide_not() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(99_703));
|
assert_eq!(gas_left, U256::from(99_656));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result,
|
result,
|
||||||
@ -233,12 +233,14 @@ fn suicide() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(99_747));
|
assert_eq!(gas_left, U256::from(99_740));
|
||||||
assert!(ext.suicides.contains(&refund));
|
assert!(ext.suicides.contains(&refund));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create() {
|
fn create() {
|
||||||
|
::ethcore_logger::init_log();
|
||||||
|
|
||||||
let mut params = ActionParams::default();
|
let mut params = ActionParams::default();
|
||||||
params.gas = U256::from(100_000);
|
params.gas = U256::from(100_000);
|
||||||
params.code = Some(Arc::new(load_sample!("creator.wasm")));
|
params.code = Some(Arc::new(load_sample!("creator.wasm")));
|
||||||
@ -262,7 +264,7 @@ fn create() {
|
|||||||
assert!(ext.calls.contains(
|
assert!(ext.calls.contains(
|
||||||
&FakeCall {
|
&FakeCall {
|
||||||
call_type: FakeCallType::Create,
|
call_type: FakeCallType::Create,
|
||||||
gas: U256::from(99_778),
|
gas: U256::from(99_767),
|
||||||
sender_address: None,
|
sender_address: None,
|
||||||
receive_address: None,
|
receive_address: None,
|
||||||
value: Some(1_000_000_000.into()),
|
value: Some(1_000_000_000.into()),
|
||||||
@ -270,5 +272,119 @@ fn create() {
|
|||||||
code_address: None,
|
code_address: None,
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
assert_eq!(gas_left, U256::from(99_768));
|
assert_eq!(gas_left, U256::from(99_759));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn call_code() {
|
||||||
|
::ethcore_logger::init_log();
|
||||||
|
|
||||||
|
let sender: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap();
|
||||||
|
let receiver: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
|
||||||
|
|
||||||
|
let mut params = ActionParams::default();
|
||||||
|
params.sender = sender.clone();
|
||||||
|
params.address = receiver.clone();
|
||||||
|
params.gas = U256::from(100_000);
|
||||||
|
params.code = Some(Arc::new(load_sample!("call_code.wasm")));
|
||||||
|
params.data = Some(Vec::new());
|
||||||
|
params.value = ActionValue::transfer(1_000_000_000);
|
||||||
|
|
||||||
|
let mut ext = FakeExt::new();
|
||||||
|
|
||||||
|
let (gas_left, result) = {
|
||||||
|
let mut interpreter = wasm_interpreter();
|
||||||
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
||||||
|
match result {
|
||||||
|
GasLeft::Known(_) => { panic!("Call test should return payload"); },
|
||||||
|
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
trace!(target: "wasm", "fake_calls: {:?}", &ext.calls);
|
||||||
|
assert!(ext.calls.contains(
|
||||||
|
&FakeCall {
|
||||||
|
call_type: FakeCallType::Call,
|
||||||
|
gas: U256::from(99_061),
|
||||||
|
sender_address: Some(sender),
|
||||||
|
receive_address: Some(receiver),
|
||||||
|
value: None,
|
||||||
|
data: vec![1u8, 2, 3, 5, 7, 11],
|
||||||
|
code_address: Some("0d13710000000000000000000000000000000000".parse().unwrap()),
|
||||||
|
}
|
||||||
|
));
|
||||||
|
assert_eq!(gas_left, U256::from(94196));
|
||||||
|
|
||||||
|
// siphash result
|
||||||
|
let res = LittleEndian::read_u32(&result[..]);
|
||||||
|
assert_eq!(res, 4198595614);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn call_static() {
|
||||||
|
::ethcore_logger::init_log();
|
||||||
|
|
||||||
|
let sender: Address = "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6".parse().unwrap();
|
||||||
|
let receiver: Address = "01030507090b0d0f11131517191b1d1f21232527".parse().unwrap();
|
||||||
|
|
||||||
|
let mut params = ActionParams::default();
|
||||||
|
params.sender = sender.clone();
|
||||||
|
params.address = receiver.clone();
|
||||||
|
params.gas = U256::from(100_000);
|
||||||
|
params.code = Some(Arc::new(load_sample!("call_static.wasm")));
|
||||||
|
params.data = Some(Vec::new());
|
||||||
|
params.value = ActionValue::transfer(1_000_000_000);
|
||||||
|
|
||||||
|
let mut ext = FakeExt::new();
|
||||||
|
|
||||||
|
let (gas_left, result) = {
|
||||||
|
let mut interpreter = wasm_interpreter();
|
||||||
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
||||||
|
match result {
|
||||||
|
GasLeft::Known(_) => { panic!("Static call test should return payload"); },
|
||||||
|
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
trace!(target: "wasm", "fake_calls: {:?}", &ext.calls);
|
||||||
|
assert!(ext.calls.contains(
|
||||||
|
&FakeCall {
|
||||||
|
call_type: FakeCallType::Call,
|
||||||
|
gas: U256::from(99_061),
|
||||||
|
sender_address: Some(sender),
|
||||||
|
receive_address: Some(receiver),
|
||||||
|
value: None,
|
||||||
|
data: vec![1u8, 2, 3, 5, 7, 11],
|
||||||
|
code_address: Some("13077bfb00000000000000000000000000000000".parse().unwrap()),
|
||||||
|
}
|
||||||
|
));
|
||||||
|
assert_eq!(gas_left, U256::from(94196));
|
||||||
|
|
||||||
|
// siphash result
|
||||||
|
let res = LittleEndian::read_u32(&result[..]);
|
||||||
|
assert_eq!(res, 317632590);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Realloc test
|
||||||
|
#[test]
|
||||||
|
fn realloc() {
|
||||||
|
let code = load_sample!("realloc.wasm");
|
||||||
|
|
||||||
|
let mut params = ActionParams::default();
|
||||||
|
params.gas = U256::from(100_000);
|
||||||
|
params.code = Some(Arc::new(code));
|
||||||
|
params.data = Some(vec![0u8]);
|
||||||
|
let mut ext = FakeExt::new();
|
||||||
|
|
||||||
|
let (gas_left, result) = {
|
||||||
|
let mut interpreter = wasm_interpreter();
|
||||||
|
let result = interpreter.exec(params, &mut ext).expect("Interpreter to execute without any errors");
|
||||||
|
match result {
|
||||||
|
GasLeft::Known(_) => { panic!("Realloc should return payload"); },
|
||||||
|
GasLeft::NeedsReturn { gas_left: gas, data: result, apply_state: _apply } => (gas, result.to_vec()),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
assert_eq!(gas_left, U256::from(98326));
|
||||||
|
assert_eq!(result, vec![0u8; 2]);
|
||||||
}
|
}
|
@ -25,7 +25,7 @@ extern crate panic_hook;
|
|||||||
use std::{env, fmt, process};
|
use std::{env, fmt, process};
|
||||||
use std::num::ParseIntError;
|
use std::num::ParseIntError;
|
||||||
use docopt::Docopt;
|
use docopt::Docopt;
|
||||||
use rustc_hex::{FromHex, FromHexError};
|
use rustc_hex::{ToHex, FromHex, FromHexError};
|
||||||
use ethkey::{KeyPair, Random, Brain, Prefix, Error as EthkeyError, Generator, sign, verify_public, verify_address};
|
use ethkey::{KeyPair, Random, Brain, Prefix, Error as EthkeyError, Generator, sign, verify_public, verify_address};
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
@ -170,7 +170,7 @@ fn main() {
|
|||||||
fn display(keypair: KeyPair, mode: DisplayMode) -> String {
|
fn display(keypair: KeyPair, mode: DisplayMode) -> String {
|
||||||
match mode {
|
match mode {
|
||||||
DisplayMode::KeyPair => format!("{}", keypair),
|
DisplayMode::KeyPair => format!("{}", keypair),
|
||||||
DisplayMode::Secret => format!("{:?}", keypair.secret()),
|
DisplayMode::Secret => format!("{}", keypair.secret().to_hex()),
|
||||||
DisplayMode::Public => format!("{:?}", keypair.public()),
|
DisplayMode::Public => format!("{:?}", keypair.public()),
|
||||||
DisplayMode::Address => format!("{:?}", keypair.address()),
|
DisplayMode::Address => format!("{:?}", keypair.address()),
|
||||||
}
|
}
|
||||||
@ -248,9 +248,9 @@ address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned();
|
|||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
let expected =
|
let expected =
|
||||||
"secret: 17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55
|
"secret: aa22b54c0cb43ee30a014afe5ef3664b1cde299feabca46cd3167a85a57c39f2
|
||||||
public: 689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124
|
public: c4c5398da6843632c123f543d714d2d2277716c11ff612b2a2f23c6bda4d6f0327c31cd58c55a9572c3cc141dade0c32747a13b7ef34c241b26c84adbb28fcf4
|
||||||
address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned();
|
address: 006e27b6a72e1f34c626762f3c4761547aff1421".to_owned();
|
||||||
assert_eq!(execute(command).unwrap(), expected);
|
assert_eq!(execute(command).unwrap(), expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,7 +261,7 @@ address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned();
|
|||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
let expected = "17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55".to_owned();
|
let expected = "aa22b54c0cb43ee30a014afe5ef3664b1cde299feabca46cd3167a85a57c39f2".to_owned();
|
||||||
assert_eq!(execute(command).unwrap(), expected);
|
assert_eq!(execute(command).unwrap(), expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,7 +272,7 @@ address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned();
|
|||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
let expected = "689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124".to_owned();
|
let expected = "c4c5398da6843632c123f543d714d2d2277716c11ff612b2a2f23c6bda4d6f0327c31cd58c55a9572c3cc141dade0c32747a13b7ef34c241b26c84adbb28fcf4".to_owned();
|
||||||
assert_eq!(execute(command).unwrap(), expected);
|
assert_eq!(execute(command).unwrap(), expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,7 +283,7 @@ address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned();
|
|||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
let expected = "26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned();
|
let expected = "006e27b6a72e1f34c626762f3c4761547aff1421".to_owned();
|
||||||
assert_eq!(execute(command).unwrap(), expected);
|
assert_eq!(execute(command).unwrap(), expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use rustc_hex::ToHex;
|
||||||
use secp256k1::key;
|
use secp256k1::key;
|
||||||
use bigint::hash::H256;
|
use bigint::hash::H256;
|
||||||
use {Error, SECP256K1};
|
use {Error, SECP256K1};
|
||||||
@ -26,6 +27,12 @@ pub struct Secret {
|
|||||||
inner: H256,
|
inner: H256,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToHex for Secret {
|
||||||
|
fn to_hex(&self) -> String {
|
||||||
|
self.inner.to_hex()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Secret {
|
impl fmt::Debug for Secret {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(fmt, "Secret: 0x{:x}{:x}..{:x}{:x}", self.inner[0], self.inner[1], self.inner[30], self.inner[31])
|
write!(fmt, "Secret: 0x{:x}{:x}..{:x}{:x}", self.inner[0], self.inner[1], self.inner[30], self.inner[31])
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user