diff --git a/Cargo.lock b/Cargo.lock index 035e5517c..6597c44a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,10 +24,9 @@ dependencies = [ "ethcore-stratum 1.4.0", "ethcore-util 1.5.0", "ethsync 1.5.0", - "fdlimit 0.1.0", + "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", "isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "json-ipc-server 0.2.4 (git+https://github.com/ethcore/json-ipc-server.git)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -175,6 +174,15 @@ dependencies = [ "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cookie" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam" version = "0.2.9" @@ -296,7 +304,7 @@ dependencies = [ "ethstore 0.1.0", "evmjit 1.4.0", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.9.4 (git+https://github.com/ethcore/hyper)", + "hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -340,9 +348,9 @@ dependencies = [ "ethcore-rpc 1.5.0", "ethcore-util 1.5.0", "fetch 0.1.0", - "hyper 0.9.4 (git+https://github.com/ethcore/hyper)", - "jsonrpc-core 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc-http-server.git)", + "hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)", + "jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)", + "jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc.git)", "linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -503,9 +511,9 @@ dependencies = [ "ethstore 0.1.0", "ethsync 1.5.0", "fetch 0.1.0", - "json-ipc-server 0.2.4 (git+https://github.com/ethcore/json-ipc-server.git)", - "jsonrpc-core 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc-http-server.git)", + "jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)", + "jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc.git)", + "jsonrpc-ipc-server 0.2.4 (git+https://github.com/ethcore/jsonrpc.git)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.1.0", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -526,7 +534,7 @@ dependencies = [ "ethcore-io 1.5.0", "ethcore-rpc 1.5.0", "ethcore-util 1.5.0", - "jsonrpc-core 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-ui 1.4.0", @@ -545,8 +553,8 @@ dependencies = [ "ethcore-ipc-codegen 1.4.0", "ethcore-ipc-nano 1.4.0", "ethcore-util 1.5.0", - "json-tcp-server 0.1.0 (git+https://github.com/ethcore/json-tcp-server)", - "jsonrpc-core 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)", + "jsonrpc-tcp-server 0.1.0 (git+https://github.com/ethcore/jsonrpc.git)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)", @@ -676,7 +684,8 @@ dependencies = [ [[package]] name = "fdlimit" -version = "0.1.0" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -686,7 +695,7 @@ name = "fetch" version = "0.1.0" dependencies = [ "https-fetch 0.1.0", - "hyper 0.9.4 (git+https://github.com/ethcore/hyper)", + "hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -748,27 +757,6 @@ dependencies = [ "rustls 0.1.2 (git+https://github.com/ctz/rustls)", ] -[[package]] -name = "hyper" -version = "0.9.4" -source = "git+https://github.com/ethcore/hyper#9e346c1d4bc30cd4142dea9d8a0b117d30858ca4" -dependencies = [ - "cookie 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rotor 0.6.3 (git+https://github.com/ethcore/rotor)", - "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "spmc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "hyper" version = "0.9.10" @@ -789,6 +777,25 @@ dependencies = [ "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "hyper" +version = "0.10.0-a.0" +source = "git+https://github.com/ethcore/hyper#7d4f7fa0baddcb2b0c523f7c05855d67de94fe88" +dependencies = [ + "cookie 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rotor 0.6.3 (git+https://github.com/ethcore/rotor)", + "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "spmc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "idna" version = "0.1.0" @@ -831,39 +838,10 @@ name = "itoa" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "json-ipc-server" -version = "0.2.4" -source = "git+https://github.com/ethcore/json-ipc-server.git#4642cd03ec1d23db89df80d22d5a88e7364ab885" -dependencies = [ - "bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "json-tcp-server" -version = "0.1.0" -source = "git+https://github.com/ethcore/json-tcp-server#c2858522274ae56042472bb5d22845a1b85e5338" -dependencies = [ - "bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "jsonrpc-core" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "4.0.0" +source = "git+https://github.com/ethcore/jsonrpc.git#20c7e55b84d7fd62732f062dc3058e1b71133e4a" dependencies = [ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -875,14 +853,44 @@ dependencies = [ [[package]] name = "jsonrpc-http-server" version = "6.1.1" -source = "git+https://github.com/ethcore/jsonrpc-http-server.git#cd6d4cb37d672cc3057aecd0692876f9e85f3ba5" +source = "git+https://github.com/ethcore/jsonrpc.git#20c7e55b84d7fd62732f062dc3058e1b71133e4a" dependencies = [ - "hyper 0.9.4 (git+https://github.com/ethcore/hyper)", - "jsonrpc-core 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)", + "jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "jsonrpc-ipc-server" +version = "0.2.4" +source = "git+https://github.com/ethcore/jsonrpc.git#20c7e55b84d7fd62732f062dc3058e1b71133e4a" +dependencies = [ + "bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)", + "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "jsonrpc-tcp-server" +version = "0.1.0" +source = "git+https://github.com/ethcore/jsonrpc.git#20c7e55b84d7fd62732f062dc3058e1b71133e4a" +dependencies = [ + "bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)", + "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -1263,7 +1271,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/ethcore/js-precompiled.git#d99369b5010cfa73c3a62eb8c031bf873a7ca709" +source = "git+https://github.com/ethcore/js-precompiled.git#3cf6c68b7d08be71d12ff142e255a42043e50c75" dependencies = [ "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1503,11 +1511,12 @@ dependencies = [ [[package]] name = "rotor" version = "0.6.3" -source = "git+https://github.com/ethcore/rotor#e63d45137b2eb66d1e085a7c6321a5db8b187576" +source = "git+https://github.com/ethcore/rotor#c1a2dd0046c5ea2517a5b637fca8ee2e77021e82" dependencies = [ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.5.1 (git+https://github.com/ethcore/mio?branch=v0.5.x)", + "mio 0.6.1 (git+https://github.com/ethcore/mio)", "quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2008,6 +2017,7 @@ dependencies = [ "checksum clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "5b4fabf979ddf6419a313c1c0ada4a5b95cfd2049c56e8418d622d27b4b6ff32" "checksum clippy_lints 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "ce96ec05bfe018a0d5d43da115e54850ea2217981ff0f2e462780ab9d594651a" "checksum cookie 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90266f45846f14a1e986c77d1e9c2626b8c342ed806fe60241ec38cc8697b245" +"checksum cookie 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d53b80dde876f47f03cda35303e368a79b91c70b0d65ecba5fd5280944a08591" "checksum crossbeam 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "fb974f835e90390c5f9dfac00f05b06dc117299f5ea4e85fbc7bb443af4911cc" "checksum ctrlc 1.1.1 (git+https://github.com/ethcore/rust-ctrlc.git)" = "" "checksum daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "271ec51b7e0bee92f0d04601422c73eb76ececf197026711c97ad25038a010cf" @@ -2018,6 +2028,7 @@ dependencies = [ "checksum env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aba65b63ffcc17ffacd6cf5aa843da7c5a25e3bd4bbe0b7def8b214e411250e5" "checksum eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)" = "" "checksum ethabi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0c53453517f620847be51943db329276ae52f2e210cfc659e81182864be2f" +"checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa" "checksum flate2 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "3eeb481e957304178d2e782f2da1257f1434dfecbae883bafb61ada2a9fea3bb" "checksum gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "91ecd03771effb0c968fd6950b37e89476a578aaf1c70297d8e92b6516ec3312" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" @@ -2025,17 +2036,17 @@ dependencies = [ "checksum heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "abb306abb8d398e053cfb1b3e7b72c2f580be048b85745c52652954f8ad1439c" "checksum hpack 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d2da7d3a34cf6406d9d700111b8eafafe9a251de41ae71d8052748259343b58" "checksum httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "46534074dbb80b070d60a5cb8ecadd8963a00a438ae1a95268850a7ef73b67ae" +"checksum hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)" = "" "checksum hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "eb27e8a3e8f17ac43ffa41bbda9cf5ad3f9f13ef66fa4873409d4902310275f7" -"checksum hyper 0.9.4 (git+https://github.com/ethcore/hyper)" = "" "checksum idna 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1053236e00ce4f668aeca4a769a09b3bf5a682d802abd6f3cb39374f6b162c11" "checksum igd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c8c12b1795b8b168f577c45fa10379b3814dcb11b7ab702406001f0d63f40484" "checksum isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7408a548dc0e406b7912d9f84c261cc533c1866e047644a811c133c56041ac0c" "checksum itertools 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "086e1fa5fe48840b1cfdef3a20c7e3115599f8d5c4c87ef32a794a7cdd184d76" "checksum itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3088ea4baeceb0284ee9eea42f591226e6beaecf65373e41b38d95a1b8e7a1" -"checksum json-ipc-server 0.2.4 (git+https://github.com/ethcore/json-ipc-server.git)" = "" -"checksum json-tcp-server 0.1.0 (git+https://github.com/ethcore/json-tcp-server)" = "" -"checksum jsonrpc-core 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3c5094610b07f28f3edaf3947b732dadb31dbba4941d4d0c1c7a8350208f4414" -"checksum jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc-http-server.git)" = "" +"checksum jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)" = "" +"checksum jsonrpc-http-server 6.1.1 (git+https://github.com/ethcore/jsonrpc.git)" = "" +"checksum jsonrpc-ipc-server 0.2.4 (git+https://github.com/ethcore/jsonrpc.git)" = "" +"checksum jsonrpc-tcp-server 0.1.0 (git+https://github.com/ethcore/jsonrpc.git)" = "" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f" diff --git a/Cargo.toml b/Cargo.toml index 3808cce95..078d2916c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,8 +30,7 @@ serde = "0.8.0" serde_json = "0.8.0" hyper = { version = "0.9", default-features = false } ctrlc = { git = "https://github.com/ethcore/rust-ctrlc.git" } -json-ipc-server = { git = "https://github.com/ethcore/json-ipc-server.git" } -fdlimit = { path = "util/fdlimit" } +fdlimit = "0.1" ethcore = { path = "ethcore" } ethcore-util = { path = "util" } ethsync = { path = "sync" } diff --git a/dapps/Cargo.toml b/dapps/Cargo.toml index 6be30884a..bbab8420e 100644 --- a/dapps/Cargo.toml +++ b/dapps/Cargo.toml @@ -12,8 +12,8 @@ build = "build.rs" rand = "0.3.14" log = "0.3" env_logger = "0.3" -jsonrpc-core = "3.0" -jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc-http-server.git" } +jsonrpc-core = { git = "https://github.com/ethcore/jsonrpc.git" } +jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc.git" } hyper = { default-features = false, git = "https://github.com/ethcore/hyper" } unicase = "1.3" url = "1.0" diff --git a/dapps/src/handlers/content.rs b/dapps/src/handlers/content.rs index 738a9a890..fde5fbcf0 100644 --- a/dapps/src/handlers/content.rs +++ b/dapps/src/handlers/content.rs @@ -16,7 +16,6 @@ //! Simple Content Handler -use std::io::Write; use hyper::{header, server, Decoder, Encoder, Next}; use hyper::net::HttpStream; use hyper::mime::Mime; diff --git a/dapps/src/handlers/mod.rs b/dapps/src/handlers/mod.rs index b575509a5..1299a9c12 100644 --- a/dapps/src/handlers/mod.rs +++ b/dapps/src/handlers/mod.rs @@ -58,7 +58,7 @@ pub fn extract_url(req: &server::Request) -> Option { _ => None, } }, - uri::RequestUri::AbsolutePath(ref path) => { + uri::RequestUri::AbsolutePath { ref path, .. } => { // Attempt to prepend the Host header (mandatory in HTTP/1.1) let url_string = match req.headers().get::() { Some(ref host) => { diff --git a/dapps/src/lib.rs b/dapps/src/lib.rs index 7c7ea0a86..9bb3be4a7 100644 --- a/dapps/src/lib.rs +++ b/dapps/src/lib.rs @@ -266,7 +266,11 @@ impl Server { #[cfg(test)] /// Returns address that this server is bound to. pub fn addr(&self) -> &SocketAddr { - self.server.as_ref().expect("server is always Some at the start; it's consumed only when object is dropped; qed").addr() + self.server.as_ref() + .expect("server is always Some at the start; it's consumed only when object is dropped; qed") + .addrs() + .first() + .expect("You cannot start the server without binding to at least one address; qed") } } diff --git a/dapps/src/page/handler.rs b/dapps/src/page/handler.rs index 74eabf917..1494a04c7 100644 --- a/dapps/src/page/handler.rs +++ b/dapps/src/page/handler.rs @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use std::io::Write; use time::{self, Duration}; use hyper::header; @@ -126,7 +125,7 @@ impl PageHandler { impl server::Handler for PageHandler { fn on_request(&mut self, req: server::Request) -> Next { self.file = match *req.uri() { - RequestUri::AbsolutePath(ref path) => { + RequestUri::AbsolutePath { ref path, .. } => { self.app.file(&self.extract_path(path)) }, RequestUri::AbsoluteUri(ref url) => { diff --git a/dapps/src/rpc.rs b/dapps/src/rpc.rs index 625bfc269..c47777bee 100644 --- a/dapps/src/rpc.rs +++ b/dapps/src/rpc.rs @@ -16,13 +16,14 @@ use std::sync::{Arc, Mutex}; use hyper; -use jsonrpc_core::IoHandler; -use jsonrpc_http_server::{ServerHandler, PanicHandler, AccessControlAllowOrigin}; + +use jsonrpc_core::{IoHandler, ResponseHandler, Request, Response}; +use jsonrpc_http_server::{ServerHandler, PanicHandler, AccessControlAllowOrigin, RpcHandler}; use endpoint::{Endpoint, EndpointPath, Handler}; pub fn rpc(handler: Arc, panic_handler: Arc () + Send>>>>) -> Box { Box::new(RpcEndpoint { - handler: handler, + handler: Arc::new(RpcMiddleware::new(handler)), panic_handler: panic_handler, cors_domain: None, // NOTE [ToDr] We don't need to do any hosts validation here. It's already done in router. @@ -31,7 +32,7 @@ pub fn rpc(handler: Arc, panic_handler: Arc } struct RpcEndpoint { - handler: Arc, + handler: Arc, panic_handler: Arc () + Send>>>>, cors_domain: Option>, allowed_hosts: Option>, @@ -49,3 +50,86 @@ impl Endpoint for RpcEndpoint { )) } } + +const MIDDLEWARE_METHOD: &'static str = "eth_accounts"; + +struct RpcMiddleware { + handler: Arc, +} + +impl RpcMiddleware { + fn new(handler: Arc) -> Self { + RpcMiddleware { + handler: handler, + } + } + + /// Appends additional parameter for specific calls. + fn augment_request(&self, request: &mut Request, meta: Option) { + use jsonrpc_core::{Call, Params, to_value}; + + fn augment_call(call: &mut Call, meta: Option<&Meta>) { + match (call, meta) { + (&mut Call::MethodCall(ref mut method_call), Some(meta)) if &method_call.method == MIDDLEWARE_METHOD => { + let session = to_value(&meta.app_id); + + let params = match method_call.params { + Some(Params::Array(ref vec)) if vec.len() == 0 => Some(Params::Array(vec![session])), + // invalid params otherwise + _ => None, + }; + + method_call.params = params; + }, + _ => {} + } + } + + match *request { + Request::Single(ref mut call) => augment_call(call, meta.as_ref()), + Request::Batch(ref mut vec) => { + for mut call in vec { + augment_call(call, meta.as_ref()) + } + }, + } + } +} + +#[derive(Debug)] +struct Meta { + app_id: String, +} + +impl RpcHandler for RpcMiddleware { + type Metadata = Meta; + + fn read_metadata(&self, request: &hyper::server::Request) -> Option { + request.headers().get::() + .and_then(|referer| hyper::Url::parse(referer).ok()) + .and_then(|url| { + url.path_segments() + .and_then(|mut split| split.next()) + .map(|app_id| Meta { + app_id: app_id.to_owned(), + }) + }) + } + + fn handle_request(&self, request_str: &str, response_handler: H, meta: Option) where + H: ResponseHandler, Option> + 'static + { + let handler = IoHandler::convert_handler(response_handler); + let request = IoHandler::read_request(request_str); + trace!(target: "rpc", "Request metadata: {:?}", meta); + + match request { + Ok(mut request) => { + self.augment_request(&mut request, meta); + self.handler.request_handler().handle_request(request, handler, None) + }, + Err(error) => handler.send(Some(Response::from(error))), + } + } +} + diff --git a/ethcore/res/authority_round.json b/ethcore/res/authority_round.json index 9ab782395..a0f88b85b 100644 --- a/ethcore/res/authority_round.json +++ b/ethcore/res/authority_round.json @@ -21,8 +21,7 @@ "genesis": { "seal": { "generic": { - "fields": 2, - "rlp": "0x200" + "rlp": "0xc28080" } }, "difficulty": "0x20000", diff --git a/ethcore/res/instant_seal.json b/ethcore/res/instant_seal.json index a6b24faf9..fbb650102 100644 --- a/ethcore/res/instant_seal.json +++ b/ethcore/res/instant_seal.json @@ -12,7 +12,6 @@ "genesis": { "seal": { "generic": { - "fields": 0, "rlp": "0x0" } }, diff --git a/ethcore/src/account_provider.rs b/ethcore/src/account_provider/mod.rs similarity index 80% rename from ethcore/src/account_provider.rs rename to ethcore/src/account_provider/mod.rs index 917ae8b8b..24548dda3 100644 --- a/ethcore/src/account_provider.rs +++ b/ethcore/src/account_provider/mod.rs @@ -16,9 +16,12 @@ //! Account management. -use std::{fs, fmt}; +mod stores; + +use self::stores::{AddressBook, DappsSettingsStore}; + +use std::fmt; use std::collections::HashMap; -use std::path::PathBuf; use std::time::{Instant, Duration}; use util::{Mutex, RwLock}; use ethstore::{SecretStore, Error as SSError, SafeAccount, EthStore}; @@ -91,84 +94,16 @@ impl KeyDirectory for NullDir { } } -/// Disk-backed map from Address to String. Uses JSON. -struct AddressBook { - path: PathBuf, - cache: HashMap, - transient: bool, -} - -impl AddressBook { - pub fn new(path: String) -> Self { - trace!(target: "addressbook", "new({})", path); - let mut path: PathBuf = path.into(); - path.push("address_book.json"); - trace!(target: "addressbook", "path={:?}", path); - let mut r = AddressBook { - path: path, - cache: HashMap::new(), - transient: false, - }; - r.revert(); - r - } - - pub fn transient() -> Self { - let mut book = AddressBook::new(Default::default()); - book.transient = true; - book - } - - pub fn get(&self) -> HashMap { - self.cache.clone() - } - - pub fn set_name(&mut self, a: Address, name: String) { - let mut x = self.cache.get(&a) - .cloned() - .unwrap_or_else(|| AccountMeta {name: Default::default(), meta: "{}".to_owned(), uuid: None}); - x.name = name; - self.cache.insert(a, x); - self.save(); - } - - pub fn set_meta(&mut self, a: Address, meta: String) { - let mut x = self.cache.get(&a) - .cloned() - .unwrap_or_else(|| AccountMeta {name: "Anonymous".to_owned(), meta: Default::default(), uuid: None}); - x.meta = meta; - self.cache.insert(a, x); - self.save(); - } - - fn revert(&mut self) { - if self.transient { return; } - trace!(target: "addressbook", "revert"); - let _ = fs::File::open(self.path.clone()) - .map_err(|e| trace!(target: "addressbook", "Couldn't open address book: {}", e)) - .and_then(|f| AccountMeta::read_address_map(&f) - .map_err(|e| warn!(target: "addressbook", "Couldn't read address book: {}", e)) - .and_then(|m| { self.cache = m; Ok(()) }) - ); - } - - fn save(&mut self) { - if self.transient { return; } - trace!(target: "addressbook", "save"); - let _ = fs::File::create(self.path.clone()) - .map_err(|e| warn!(target: "addressbook", "Couldn't open address book for writing: {}", e)) - .and_then(|mut f| AccountMeta::write_address_map(&self.cache, &mut f) - .map_err(|e| warn!(target: "addressbook", "Couldn't write to address book: {}", e)) - ); - } -} +/// Dapp identifier +pub type DappId = String; /// Account management. /// Responsible for unlocking accounts. pub struct AccountProvider { unlocked: Mutex>, sstore: Box, - address_book: Mutex, + address_book: RwLock, + dapps_settings: RwLock, } impl AccountProvider { @@ -176,7 +111,8 @@ impl AccountProvider { pub fn new(sstore: Box) -> Self { AccountProvider { unlocked: Mutex::new(HashMap::new()), - address_book: Mutex::new(AddressBook::new(sstore.local_path().into())), + address_book: RwLock::new(AddressBook::new(sstore.local_path().into())), + dapps_settings: RwLock::new(DappsSettingsStore::new(sstore.local_path().into())), sstore: sstore, } } @@ -185,7 +121,8 @@ impl AccountProvider { pub fn transient_provider() -> Self { AccountProvider { unlocked: Mutex::new(HashMap::new()), - address_book: Mutex::new(AddressBook::transient()), + address_book: RwLock::new(AddressBook::transient()), + dapps_settings: RwLock::new(DappsSettingsStore::transient()), sstore: Box::new(EthStore::open(Box::new(NullDir::default())) .expect("NullDir load always succeeds; qed")) } @@ -230,19 +167,31 @@ impl AccountProvider { Ok(accounts) } + /// Gets addresses visile for dapp. + pub fn dapps_addresses(&self, dapp: DappId) -> Result, Error> { + let accounts = self.dapps_settings.read().get(); + Ok(accounts.get(&dapp).map(|settings| settings.accounts.clone()).unwrap_or_else(Vec::new)) + } + + /// Sets addresses visile for dapp. + pub fn set_dapps_addresses(&self, dapp: DappId, addresses: Vec
) -> Result<(), Error> { + self.dapps_settings.write().set_accounts(dapp, addresses); + Ok(()) + } + /// Returns each address along with metadata. pub fn addresses_info(&self) -> Result, Error> { - Ok(self.address_book.lock().get()) + Ok(self.address_book.read().get()) } /// Returns each address along with metadata. pub fn set_address_name(&self, account: Address, name: String) -> Result<(), Error> { - Ok(self.address_book.lock().set_name(account, name)) + Ok(self.address_book.write().set_name(account, name)) } /// Returns each address along with metadata. pub fn set_address_meta(&self, account: Address, meta: String) -> Result<(), Error> { - Ok(self.address_book.lock().set_meta(account, meta)) + Ok(self.address_book.write().set_meta(account, meta)) } /// Returns each account along with name and meta. @@ -379,23 +328,9 @@ impl AccountProvider { #[cfg(test)] mod tests { - use super::{AccountProvider, AddressBook, Unlock}; - use std::collections::HashMap; + use super::{AccountProvider, Unlock}; use std::time::Instant; - use ethjson::misc::AccountMeta; use ethstore::ethkey::{Generator, Random}; - use devtools::RandomTempPath; - - #[test] - fn should_save_and_reload_address_book() { - let temp = RandomTempPath::create_dir(); - let path = temp.as_str().to_owned(); - let mut b = AddressBook::new(path.clone()); - b.set_name(1.into(), "One".to_owned()); - b.set_meta(1.into(), "{1:1}".to_owned()); - let b = AddressBook::new(path); - assert_eq!(b.get(), hash_map![1.into() => AccountMeta{name: "One".to_owned(), meta: "{1:1}".to_owned(), uuid: None}]); - } #[test] fn unlock_account_temp() { @@ -433,4 +368,17 @@ mod tests { ap.unlocked.lock().get_mut(&kp.address()).unwrap().unlock = Unlock::Timed(Instant::now()); assert!(ap.sign(kp.address(), None, Default::default()).is_err()); } + + #[test] + fn should_set_dapps_addresses() { + // given + let ap = AccountProvider::transient_provider(); + let app = "app1".to_owned(); + + // when + ap.set_dapps_addresses(app.clone(), vec![1.into(), 2.into()]).unwrap(); + + // then + assert_eq!(ap.dapps_addresses(app.clone()).unwrap(), vec![1.into(), 2.into()]); + } } diff --git a/ethcore/src/account_provider/stores.rs b/ethcore/src/account_provider/stores.rs new file mode 100644 index 000000000..cfc81f495 --- /dev/null +++ b/ethcore/src/account_provider/stores.rs @@ -0,0 +1,247 @@ +// Copyright 2015, 2016 Ethcore (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 . + +//! Address Book and Dapps Settings Store + +use std::{fs, fmt, hash, ops}; +use std::collections::HashMap; +use std::path::PathBuf; + +use ethstore::ethkey::Address; +use ethjson::misc::{AccountMeta, DappsSettings as JsonSettings}; +use account_provider::DappId; + +/// Disk-backed map from Address to String. Uses JSON. +pub struct AddressBook { + cache: DiskMap, +} + +impl AddressBook { + /// Creates new address book at given directory. + pub fn new(path: String) -> Self { + let mut r = AddressBook { + cache: DiskMap::new(path, "address_book.json".into()) + }; + r.cache.revert(AccountMeta::read_address_map); + r + } + + /// Creates transient address book (no changes are saved to disk). + pub fn transient() -> Self { + AddressBook { + cache: DiskMap::transient() + } + } + + /// Get the address book. + pub fn get(&self) -> HashMap { + self.cache.clone() + } + + fn save(&self) { + self.cache.save(AccountMeta::write_address_map) + } + + /// Sets new name for given address. + pub fn set_name(&mut self, a: Address, name: String) { + { + let mut x = self.cache.entry(a) + .or_insert_with(|| AccountMeta {name: Default::default(), meta: "{}".to_owned(), uuid: None}); + x.name = name; + } + self.save(); + } + + /// Sets new meta for given address. + pub fn set_meta(&mut self, a: Address, meta: String) { + { + let mut x = self.cache.entry(a) + .or_insert_with(|| AccountMeta {name: "Anonymous".to_owned(), meta: Default::default(), uuid: None}); + x.meta = meta; + } + self.save(); + } +} + +/// Dapps user settings +#[derive(Debug, Default, Clone, Eq, PartialEq)] +pub struct DappsSettings { + /// A list of visible accounts + pub accounts: Vec
, +} + +impl From for DappsSettings { + fn from(s: JsonSettings) -> Self { + DappsSettings { + accounts: s.accounts.into_iter().map(Into::into).collect(), + } + } +} + +impl From for JsonSettings { + fn from(s: DappsSettings) -> Self { + JsonSettings { + accounts: s.accounts.into_iter().map(Into::into).collect(), + } + } +} + +/// Disk-backed map from DappId to Settings. Uses JSON. +pub struct DappsSettingsStore { + cache: DiskMap, +} + +impl DappsSettingsStore { + /// Creates new store at given directory path. + pub fn new(path: String) -> Self { + let mut r = DappsSettingsStore { + cache: DiskMap::new(path, "dapps_accounts.json".into()) + }; + r.cache.revert(JsonSettings::read_dapps_settings); + r + } + + /// Creates transient store (no changes are saved to disk). + pub fn transient() -> Self { + DappsSettingsStore { + cache: DiskMap::transient() + } + } + + /// Get copy of the dapps settings + pub fn get(&self) -> HashMap { + self.cache.clone() + } + + fn save(&self) { + self.cache.save(JsonSettings::write_dapps_settings) + } + + pub fn set_accounts(&mut self, id: DappId, accounts: Vec
) { + { + let mut settings = self.cache.entry(id).or_insert_with(DappsSettings::default); + settings.accounts = accounts; + } + self.save(); + } +} + +/// Disk-serializable HashMap +#[derive(Debug)] +struct DiskMap { + path: PathBuf, + cache: HashMap, + transient: bool, +} + +impl ops::Deref for DiskMap { + type Target = HashMap; + fn deref(&self) -> &Self::Target { + &self.cache + } +} + +impl ops::DerefMut for DiskMap { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.cache + } +} + +impl DiskMap { + pub fn new(path: String, file_name: String) -> Self { + trace!(target: "diskmap", "new({})", path); + let mut path: PathBuf = path.into(); + path.push(file_name); + trace!(target: "diskmap", "path={:?}", path); + DiskMap { + path: path, + cache: HashMap::new(), + transient: false, + } + } + + pub fn transient() -> Self { + let mut map = DiskMap::new(Default::default(), "diskmap.json".into()); + map.transient = true; + map + } + + fn revert(&mut self, read: F) where + F: Fn(fs::File) -> Result, E>, + E: fmt::Display, + { + if self.transient { return; } + trace!(target: "diskmap", "revert {:?}", self.path); + let _ = fs::File::open(self.path.clone()) + .map_err(|e| trace!(target: "diskmap", "Couldn't open disk map: {}", e)) + .and_then(|f| read(f).map_err(|e| warn!(target: "diskmap", "Couldn't read disk map: {}", e))) + .and_then(|m| { + self.cache = m; + Ok(()) + }); + } + + fn save(&self, write: F) where + F: Fn(&HashMap, &mut fs::File) -> Result<(), E>, + E: fmt::Display, + { + if self.transient { return; } + trace!(target: "diskmap", "save {:?}", self.path); + let _ = fs::File::create(self.path.clone()) + .map_err(|e| warn!(target: "diskmap", "Couldn't open disk map for writing: {}", e)) + .and_then(|mut f| { + write(&self.cache, &mut f).map_err(|e| warn!(target: "diskmap", "Couldn't write to disk map: {}", e)) + }); + } +} + +#[cfg(test)] +mod tests { + use super::{AddressBook, DappsSettingsStore, DappsSettings}; + use std::collections::HashMap; + use ethjson::misc::AccountMeta; + use devtools::RandomTempPath; + + #[test] + fn should_save_and_reload_address_book() { + let temp = RandomTempPath::create_dir(); + let path = temp.as_str().to_owned(); + let mut b = AddressBook::new(path.clone()); + b.set_name(1.into(), "One".to_owned()); + b.set_meta(1.into(), "{1:1}".to_owned()); + let b = AddressBook::new(path); + assert_eq!(b.get(), hash_map![1.into() => AccountMeta{name: "One".to_owned(), meta: "{1:1}".to_owned(), uuid: None}]); + } + + #[test] + fn should_save_and_reload_dapps_settings() { + // given + let temp = RandomTempPath::create_dir(); + let path = temp.as_str().to_owned(); + let mut b = DappsSettingsStore::new(path.clone()); + + // when + b.set_accounts("dappOne".into(), vec![1.into(), 2.into()]); + + // then + let b = DappsSettingsStore::new(path); + assert_eq!(b.get(), hash_map![ + "dappOne".into() => DappsSettings { + accounts: vec![1.into(), 2.into()], + } + ]); + } +} diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 68fb40483..0e8e0a271 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -34,6 +34,7 @@ use blockchain::update::ExtrasUpdate; use blockchain::{CacheSize, ImportRoute, Config}; use db::{self, Writable, Readable, CacheUpdatePolicy}; use cache_manager::CacheManager; +use engines::Engine; const LOG_BLOOMS_LEVELS: usize = 3; const LOG_BLOOMS_ELEMENTS_PER_INDEX: usize = 16; @@ -198,6 +199,9 @@ pub struct BlockChain { pending_block_hashes: RwLock>, pending_block_details: RwLock>, pending_transaction_addresses: RwLock>>, + + // Used for block ordering. + engine: Arc, } impl BlockProvider for BlockChain { @@ -415,9 +419,8 @@ impl<'a> Iterator for AncestryIter<'a> { } impl BlockChain { - #[cfg_attr(feature="dev", allow(useless_let_if_seq))] - /// Create new instance of blockchain from given Genesis - pub fn new(config: Config, genesis: &[u8], db: Arc) -> BlockChain { + /// Create new instance of blockchain from given Genesis and block picking rules of Engine. + pub fn new(config: Config, genesis: &[u8], db: Arc, engine: Arc) -> BlockChain { // 400 is the avarage size of the key let cache_man = CacheManager::new(config.pref_cache_size, config.max_cache_size, 400); @@ -442,6 +445,7 @@ impl BlockChain { pending_block_hashes: RwLock::new(HashMap::new()), pending_block_details: RwLock::new(HashMap::new()), pending_transaction_addresses: RwLock::new(HashMap::new()), + engine: engine, }; // load best block @@ -858,13 +862,12 @@ impl BlockChain { let number = header.number(); let parent_hash = header.parent_hash(); let parent_details = self.block_details(&parent_hash).unwrap_or_else(|| panic!("Invalid parent hash: {:?}", parent_hash)); - let total_difficulty = parent_details.total_difficulty + header.difficulty(); - let is_new_best = total_difficulty > self.best_block_total_difficulty(); + let is_new_best = self.engine.is_new_best_block(self.best_block_total_difficulty(), HeaderView::new(&self.best_block_header()), &parent_details, header); BlockInfo { hash: hash, number: number, - total_difficulty: total_difficulty, + total_difficulty: parent_details.total_difficulty + header.difficulty(), location: if is_new_best { // on new best block we need to make sure that all ancestors // are moved to "canon chain" @@ -1319,11 +1322,16 @@ mod tests { use views::BlockView; use transaction::{Transaction, Action}; use log_entry::{LogEntry, LocalizedLogEntry}; + use spec::Spec; fn new_db(path: &str) -> Arc { Arc::new(Database::open(&DatabaseConfig::with_columns(::db::NUM_COLUMNS), path).unwrap()) } + fn new_chain(genesis: &[u8], db: Arc) -> BlockChain { + BlockChain::new(Config::default(), genesis, db, Spec::new_null().engine) + } + #[test] fn should_cache_best_block() { // given @@ -1334,7 +1342,7 @@ mod tests { let temp = RandomTempPath::new(); let db = new_db(temp.as_str()); - let bc = BlockChain::new(Config::default(), &genesis, db.clone()); + let bc = new_chain(&genesis, db.clone()); assert_eq!(bc.best_block_number(), 0); // when @@ -1360,7 +1368,7 @@ mod tests { let temp = RandomTempPath::new(); let db = new_db(temp.as_str()); - let bc = BlockChain::new(Config::default(), &genesis, db.clone()); + let bc = new_chain(&genesis, db.clone()); assert_eq!(bc.genesis_hash(), genesis_hash.clone()); assert_eq!(bc.best_block_hash(), genesis_hash.clone()); @@ -1391,7 +1399,7 @@ mod tests { let temp = RandomTempPath::new(); let db = new_db(temp.as_str()); - let bc = BlockChain::new(Config::default(), &genesis, db.clone()); + let bc = new_chain(&genesis, db.clone()); let mut block_hashes = vec![genesis_hash.clone()]; let mut batch = db.transaction(); @@ -1427,7 +1435,7 @@ mod tests { let temp = RandomTempPath::new(); let db = new_db(temp.as_str()); - let bc = BlockChain::new(Config::default(), &genesis, db.clone()); + let bc = new_chain(&genesis, db.clone()); let mut batch =db.transaction(); for b in &[&b1a, &b1b, &b2a, &b2b, &b3a, &b3b, &b4a, &b4b, &b5a, &b5b] { @@ -1489,7 +1497,7 @@ mod tests { let temp = RandomTempPath::new(); let db = new_db(temp.as_str()); - let bc = BlockChain::new(Config::default(), &genesis, db.clone()); + let bc = new_chain(&genesis, db.clone()); let mut batch = db.transaction(); let _ = bc.insert_block(&mut batch, &b1a, vec![]); @@ -1577,7 +1585,7 @@ mod tests { let temp = RandomTempPath::new(); let db = new_db(temp.as_str()); - let bc = BlockChain::new(Config::default(), &genesis, db.clone()); + let bc = new_chain(&genesis, db.clone()); let mut batch = db.transaction(); let _ = bc.insert_block(&mut batch, &b1a, vec![]); @@ -1639,7 +1647,7 @@ mod tests { let temp = RandomTempPath::new(); let db = new_db(temp.as_str()); - let bc = BlockChain::new(Config::default(), &genesis, db.clone()); + let bc = new_chain(&genesis, db.clone()); let mut batch = db.transaction(); let ir1 = bc.insert_block(&mut batch, &b1, vec![]); @@ -1755,7 +1763,7 @@ mod tests { let temp = RandomTempPath::new(); { let db = new_db(temp.as_str()); - let bc = BlockChain::new(Config::default(), &genesis, db.clone()); + let bc = new_chain(&genesis, db.clone()); assert_eq!(bc.best_block_hash(), genesis_hash); let mut batch =db.transaction(); bc.insert_block(&mut batch, &first, vec![]); @@ -1766,7 +1774,7 @@ mod tests { { let db = new_db(temp.as_str()); - let bc = BlockChain::new(Config::default(), &genesis, db.clone()); + let bc = new_chain(&genesis, db.clone()); assert_eq!(bc.best_block_hash(), first_hash); } @@ -1821,7 +1829,7 @@ mod tests { let temp = RandomTempPath::new(); let db = new_db(temp.as_str()); - let bc = BlockChain::new(Config::default(), &genesis, db.clone()); + let bc = new_chain(&genesis, db.clone()); let mut batch =db.transaction(); bc.insert_block(&mut batch, &b1, vec![]); db.write(batch).unwrap(); @@ -1881,7 +1889,7 @@ mod tests { let temp = RandomTempPath::new(); let db = new_db(temp.as_str()); - let bc = BlockChain::new(Config::default(), &genesis, db.clone()); + let bc = new_chain(&genesis, db.clone()); insert_block(&db, &bc, &b1, vec![Receipt { state_root: H256::default(), gas_used: 10_000.into(), @@ -1985,7 +1993,7 @@ mod tests { let temp = RandomTempPath::new(); let db = new_db(temp.as_str()); - let bc = BlockChain::new(Config::default(), &genesis, db.clone()); + let bc = new_chain(&genesis, db.clone()); let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5); let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5); @@ -2042,7 +2050,7 @@ mod tests { { let db = new_db(temp.as_str()); - let bc = BlockChain::new(Config::default(), &genesis, db.clone()); + let bc = new_chain(&genesis, db.clone()); let uncle = canon_chain.fork(1).generate(&mut finalizer.fork()).unwrap(); let mut batch =db.transaction(); @@ -2061,7 +2069,7 @@ mod tests { // re-loading the blockchain should load the correct best block. let db = new_db(temp.as_str()); - let bc = BlockChain::new(Config::default(), &genesis, db.clone()); + let bc = new_chain(&genesis, db.clone()); assert_eq!(bc.best_block_number(), 5); } @@ -2078,7 +2086,7 @@ mod tests { let temp = RandomTempPath::new(); let db = new_db(temp.as_str()); - let bc = BlockChain::new(Config::default(), &genesis, db.clone()); + let bc = new_chain(&genesis, db.clone()); let mut batch =db.transaction(); bc.insert_block(&mut batch, &first, vec![]); diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 85ec05b03..d2f967e70 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -164,7 +164,7 @@ impl Client { let gb = spec.genesis_block(); let db = Arc::new(try!(Database::open(&db_config, &path.to_str().expect("DB path could not be converted to string.")).map_err(ClientError::Database))); - let chain = Arc::new(BlockChain::new(config.blockchain.clone(), &gb, db.clone())); + let chain = Arc::new(BlockChain::new(config.blockchain.clone(), &gb, db.clone(), spec.engine.clone())); let tracedb = RwLock::new(TraceDB::new(config.tracing.clone(), db.clone(), chain.clone())); let trie_spec = match config.fat_db { @@ -787,7 +787,7 @@ impl snapshot::DatabaseRestore for Client { let cache_size = state_db.cache_size(); *state_db = StateDB::new(journaldb::new(db.clone(), self.pruning, ::db::COL_STATE), cache_size); - *chain = Arc::new(BlockChain::new(self.config.blockchain.clone(), &[], db.clone())); + *chain = Arc::new(BlockChain::new(self.config.blockchain.clone(), &[], db.clone(), self.engine.clone())); *tracedb = TraceDB::new(self.config.tracing.clone(), db.clone(), chain.clone()); Ok(()) } @@ -1272,7 +1272,7 @@ impl BlockChainClient for Client { self.miner.pending_transactions(self.chain.read().best_block_number()) } - fn signing_network_id(&self) -> Option { + fn signing_network_id(&self) -> Option { self.engine.signing_network_id(&self.latest_env_info()) } diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index c03b5920b..8d7e0b715 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -662,7 +662,7 @@ impl BlockChainClient for TestBlockChainClient { self.miner.pending_transactions(self.chain_info().best_block_number) } - fn signing_network_id(&self) -> Option { None } + fn signing_network_id(&self) -> Option { None } fn mode(&self) -> Mode { Mode::Active } diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index 6d774e250..30e47601a 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -237,7 +237,7 @@ pub trait BlockChainClient : Sync + Send { } /// Get the preferred network ID to sign on - fn signing_network_id(&self) -> Option; + fn signing_network_id(&self) -> Option; /// Get the mode. fn mode(&self) -> Mode; diff --git a/ethcore/src/engines/authority_round.rs b/ethcore/src/engines/authority_round.rs index 6c1d0a409..f28a06117 100644 --- a/ethcore/src/engines/authority_round.rs +++ b/ethcore/src/engines/authority_round.rs @@ -21,7 +21,7 @@ use std::sync::Weak; use std::time::{UNIX_EPOCH, Duration}; use util::*; use ethkey::{verify_address, Signature}; -use rlp::{UntrustedRlp, View, encode}; +use rlp::{Rlp, UntrustedRlp, View, encode}; use account_provider::AccountProvider; use block::*; use spec::CommonParams; @@ -35,6 +35,8 @@ use service::ClientIoMessage; use transaction::SignedTransaction; use env_info::EnvInfo; use builtin::Builtin; +use blockchain::extras::BlockDetails; +use views::HeaderView; /// `AuthorityRound` params. #[derive(Debug, PartialEq)] @@ -272,7 +274,6 @@ impl Engine for AuthorityRound { } fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> Result<(), Error> { - // Don't calculate difficulty for genesis blocks. if header.number() == 0 { return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() }))); } @@ -284,10 +285,6 @@ impl Engine for AuthorityRound { try!(Err(BlockError::DoubleVote(header.author().clone()))); } - // Check difficulty is correct given the two timestamps. - if header.difficulty() != parent.difficulty() { - return Err(From::from(BlockError::InvalidDifficulty(Mismatch { expected: *parent.difficulty(), found: *header.difficulty() }))) - } let gas_limit_divisor = self.our_params.gas_limit_bound_divisor; let min_gas = parent.gas_limit().clone() - parent.gas_limit().clone() / gas_limit_divisor; let max_gas = parent.gas_limit().clone() + parent.gas_limit().clone() / gas_limit_divisor; @@ -310,6 +307,19 @@ impl Engine for AuthorityRound { let mut guard = self.message_channel.lock(); *guard = Some(message_channel); } + + fn is_new_best_block(&self, _best_total_difficulty: U256, best_header: HeaderView, _parent_details: &BlockDetails, new_header: &HeaderView) -> bool { + let new_number = new_header.number(); + let best_number = best_header.number(); + if new_number != best_number { + new_number > best_number + } else { + // Take the oldest step at given height. + let new_step: usize = Rlp::new(&new_header.seal()[0]).as_val(); + let best_step: usize = Rlp::new(&best_header.seal()[0]).as_val(); + new_step < best_step + } + } } #[cfg(test)] diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index c70a19de8..d216c88b6 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -38,6 +38,9 @@ use io::IoChannel; use service::ClientIoMessage; use header::Header; use transaction::SignedTransaction; +use ethereum::ethash; +use blockchain::extras::BlockDetails; +use views::HeaderView; /// A consensus mechanism for the chain. Generally either proof-of-work or proof-of-stake-based. /// Provides hooks into each of the major parts of block import. @@ -113,7 +116,7 @@ pub trait Engine : Sync + Send { fn verify_transaction(&self, _t: &SignedTransaction, _header: &Header) -> Result<(), Error> { Ok(()) } /// The network ID that transactions should be signed with. - fn signing_network_id(&self, _env_info: &EnvInfo) -> Option { None } + fn signing_network_id(&self, _env_info: &EnvInfo) -> Option { None } /// Verify the seal of a block. This is an auxilliary method that actually just calls other `verify_` methods /// to get the job done. By default it must pass `verify_basic` and `verify_block_unordered`. If more or fewer @@ -146,5 +149,9 @@ pub trait Engine : Sync + Send { /// Add a channel for communication with Client which can be used for sealing. fn register_message_channel(&self, _message_channel: IoChannel) {} - // TODO: sealing stuff - though might want to leave this for later. + + /// Check if new block should be chosen as the one in chain. + fn is_new_best_block(&self, best_total_difficulty: U256, _best_header: HeaderView, parent_details: &BlockDetails, new_header: &HeaderView) -> bool { + ethash::is_new_best_block(best_total_difficulty, parent_details, new_header) + } } diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index e0906ce22..bd5a4474a 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -38,6 +38,12 @@ impl NullEngine { } } +impl Default for NullEngine { + fn default() -> Self { + Self::new(Default::default(), Default::default()) + } +} + impl Engine for NullEngine { fn name(&self) -> &str { "NullEngine" diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 38a1df525..ae768e5d3 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -21,6 +21,7 @@ use builtin::Builtin; use env_info::EnvInfo; use error::{BlockError, TransactionError, Error}; use header::Header; +use views::HeaderView; use state::CleanupMode; use spec::CommonParams; use transaction::SignedTransaction; @@ -28,6 +29,7 @@ use engines::Engine; use evm::Schedule; use ethjson; use rlp::{self, UntrustedRlp, View}; +use blockchain::extras::BlockDetails; /// Ethash params. #[derive(Debug, PartialEq)] @@ -163,9 +165,9 @@ impl Engine for Ethash { } } - fn signing_network_id(&self, env_info: &EnvInfo) -> Option { - if env_info.number >= self.ethash_params.eip155_transition && self.params().network_id < 127 { - Some(self.params().network_id as u8) + fn signing_network_id(&self, env_info: &EnvInfo) -> Option { + if env_info.number >= self.ethash_params.eip155_transition { + Some(self.params().network_id) } else { None } @@ -314,7 +316,7 @@ impl Engine for Ethash { } if let Some(n) = t.network_id() { - if header.number() < self.ethash_params.eip155_transition || n as usize != self.params().network_id { + if header.number() < self.ethash_params.eip155_transition || n != self.params().network_id { return Err(TransactionError::InvalidNetworkId.into()) } } @@ -325,6 +327,15 @@ impl Engine for Ethash { fn verify_transaction(&self, t: &SignedTransaction, _header: &Header) -> Result<(), Error> { t.sender().map(|_|()) // Perform EC recovery and cache sender } + + fn is_new_best_block(&self, best_total_difficulty: U256, _best_header: HeaderView, parent_details: &BlockDetails, new_header: &HeaderView) -> bool { + is_new_best_block(best_total_difficulty, parent_details, new_header) + } +} + +/// Check if a new block should replace the best blockchain block. +pub fn is_new_best_block(best_total_difficulty: U256, parent_details: &BlockDetails, new_header: &HeaderView) -> bool { + parent_details.total_difficulty + new_header.difficulty() > best_total_difficulty } #[cfg_attr(feature="dev", allow(wrong_self_convention))] diff --git a/ethcore/src/snapshot/service.rs b/ethcore/src/snapshot/service.rs index c0d34a6a9..89ee68de0 100644 --- a/ethcore/src/snapshot/service.rs +++ b/ethcore/src/snapshot/service.rs @@ -81,6 +81,7 @@ struct Restoration { struct RestorationParams<'a> { manifest: ManifestData, // manifest to base restoration on. pruning: Algorithm, // pruning algorithm for the database. + engine: Arc, // consensus engine of the chain. db_path: PathBuf, // database path db_config: &'a DatabaseConfig, // configuration for the database. writer: Option, // writer for recovered snapshot. @@ -99,7 +100,7 @@ impl Restoration { let raw_db = Arc::new(try!(Database::open(params.db_config, &*params.db_path.to_string_lossy()) .map_err(UtilError::SimpleString))); - let chain = BlockChain::new(Default::default(), params.genesis, raw_db.clone()); + let chain = BlockChain::new(Default::default(), params.genesis, raw_db.clone(), params.engine); let blocks = try!(BlockRebuilder::new(chain, raw_db.clone(), &manifest)); let root = manifest.state_root.clone(); @@ -420,6 +421,7 @@ impl Service { let params = RestorationParams { manifest: manifest, pruning: self.pruning, + engine: self.engine.clone(), db_path: self.restoration_db(), db_config: &self.db_config, writer: writer, diff --git a/ethcore/src/snapshot/tests/blocks.rs b/ethcore/src/snapshot/tests/blocks.rs index 18637bad1..3d9390d2e 100644 --- a/ethcore/src/snapshot/tests/blocks.rs +++ b/ethcore/src/snapshot/tests/blocks.rs @@ -37,13 +37,14 @@ fn chunk_and_restore(amount: u64) { let genesis = canon_chain.generate(&mut finalizer).unwrap(); let db_cfg = DatabaseConfig::with_columns(::db::NUM_COLUMNS); + let engine = Arc::new(::engines::NullEngine::default()); let orig_path = RandomTempPath::create_dir(); let new_path = RandomTempPath::create_dir(); let mut snapshot_path = new_path.as_path().to_owned(); snapshot_path.push("SNAP"); let old_db = Arc::new(Database::open(&db_cfg, orig_path.as_str()).unwrap()); - let bc = BlockChain::new(Default::default(), &genesis, old_db.clone()); + let bc = BlockChain::new(Default::default(), &genesis, old_db.clone(), engine.clone()); // build the blockchain. let mut batch = old_db.transaction(); @@ -73,21 +74,20 @@ fn chunk_and_restore(amount: u64) { // restore it. let new_db = Arc::new(Database::open(&db_cfg, new_path.as_str()).unwrap()); - let new_chain = BlockChain::new(Default::default(), &genesis, new_db.clone()); + let new_chain = BlockChain::new(Default::default(), &genesis, new_db.clone(), engine.clone()); let mut rebuilder = BlockRebuilder::new(new_chain, new_db.clone(), &manifest).unwrap(); let reader = PackedReader::new(&snapshot_path).unwrap().unwrap(); - let engine = ::engines::NullEngine::new(Default::default(), Default::default()); let flag = AtomicBool::new(true); for chunk_hash in &reader.manifest().block_hashes { let compressed = reader.chunk(*chunk_hash).unwrap(); let chunk = snappy::decompress(&compressed).unwrap(); - rebuilder.feed(&chunk, &engine, &flag).unwrap(); + rebuilder.feed(&chunk, engine.as_ref(), &flag).unwrap(); } rebuilder.finalize(HashMap::new()).unwrap(); // and test it. - let new_chain = BlockChain::new(Default::default(), &genesis, new_db); + let new_chain = BlockChain::new(Default::default(), &genesis, new_db, engine); assert_eq!(new_chain.best_block_hash(), best_hash); } @@ -121,8 +121,8 @@ fn checks_flag() { let db_cfg = DatabaseConfig::with_columns(::db::NUM_COLUMNS); let db = Arc::new(Database::open(&db_cfg, path.as_str()).unwrap()); - let chain = BlockChain::new(Default::default(), &genesis, db.clone()); - let engine = ::engines::NullEngine::new(Default::default(), Default::default()); + let engine = Arc::new(::engines::NullEngine::default()); + let chain = BlockChain::new(Default::default(), &genesis, db.clone(), engine.clone()); let manifest = ::snapshot::ManifestData { state_hashes: Vec::new(), @@ -134,8 +134,8 @@ fn checks_flag() { let mut rebuilder = BlockRebuilder::new(chain, db.clone(), &manifest).unwrap(); - match rebuilder.feed(&chunk, &engine, &AtomicBool::new(false)) { + match rebuilder.feed(&chunk, engine.as_ref(), &AtomicBool::new(false)) { Err(Error::Snapshot(SnapshotError::RestorationAborted)) => {} _ => panic!("Wrong result on abort flag set") } -} \ No newline at end of file +} diff --git a/ethcore/src/spec/seal.rs b/ethcore/src/spec/seal.rs index e25f174d2..f3e5dca95 100644 --- a/ethcore/src/spec/seal.rs +++ b/ethcore/src/spec/seal.rs @@ -30,11 +30,9 @@ pub struct Ethereum { impl Into for Ethereum { fn into(self) -> Generic { - let mut s = RlpStream::new(); - s.append(&self.mix_hash); - s.append(&self.nonce); + let mut s = RlpStream::new_list(2); + s.append(&self.mix_hash).append(&self.nonce); Generic { - fields: 2, rlp: s.out() } } @@ -42,8 +40,6 @@ impl Into for Ethereum { /// Generic seal. pub struct Generic { - /// Number of seal fields. - pub fields: usize, /// Seal rlp. pub rlp: Vec, } @@ -64,7 +60,6 @@ impl From for Seal { mix_hash: eth.mix_hash.into() }), ethjson::spec::Seal::Generic(g) => Seal::Generic(Generic { - fields: g.fields, rlp: g.rlp.into() }) } diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index 71c15bca2..c9ae087c0 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -30,15 +30,14 @@ use ethjson; use rlp::{Rlp, RlpStream, View, Stream}; /// Parameters common to all engines. -#[derive(Debug, PartialEq, Clone)] -#[cfg_attr(test, derive(Default))] +#[derive(Debug, PartialEq, Clone, Default)] pub struct CommonParams { /// Account start nonce. pub account_start_nonce: U256, /// Maximum size of extra data. pub maximum_extra_data_size: usize, /// Network id. - pub network_id: usize, + pub network_id: u64, /// Main subprotocol name. pub subprotocol_name: String, /// Minimum gas limit. @@ -94,8 +93,6 @@ pub struct Spec { pub receipts_root: H256, /// The genesis block's extra data field. pub extra_data: Bytes, - /// The number of seal fields in the genesis block. - pub seal_fields: usize, /// Each seal field, expressed as RLP, concatenated. pub seal_rlp: Bytes, @@ -127,7 +124,6 @@ impl From for Spec { gas_used: g.gas_used, timestamp: g.timestamp, extra_data: g.extra_data, - seal_fields: seal.fields, seal_rlp: seal.rlp, state_root_memo: RwLock::new(g.state_root), genesis_state: From::from(s.accounts), @@ -167,7 +163,7 @@ impl Spec { pub fn nodes(&self) -> &[String] { &self.nodes } /// Get the configured Network ID. - pub fn network_id(&self) -> usize { self.params.network_id } + pub fn network_id(&self) -> u64 { self.params.network_id } /// Get the configured subprotocol name. pub fn subprotocol_name(&self) -> String { self.params.subprotocol_name.clone() } @@ -192,13 +188,8 @@ impl Spec { header.set_gas_limit(self.gas_limit.clone()); header.set_difficulty(self.difficulty.clone()); header.set_seal({ - let seal = { - let mut s = RlpStream::new_list(self.seal_fields); - s.append_raw(&self.seal_rlp, self.seal_fields); - s.out() - }; - let r = Rlp::new(&seal); - (0..self.seal_fields).map(|i| r.at(i).as_raw().to_vec()).collect() + let r = Rlp::new(&self.seal_rlp); + r.iter().map(|f| f.as_raw().to_vec()).collect() }); trace!(target: "spec", "Header hash is {}", header.hash()); header @@ -227,7 +218,6 @@ impl Spec { self.gas_used = g.gas_used; self.timestamp = g.timestamp; self.extra_data = g.extra_data; - self.seal_fields = seal.fields; self.seal_rlp = seal.rlp; self.state_root_memo = RwLock::new(g.state_root); } diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index db7c318c6..07ac72774 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -790,1107 +790,1107 @@ impl Clone for State { #[cfg(test)] mod tests { -use std::sync::Arc; -use std::str::FromStr; -use rustc_serialize::hex::FromHex; -use super::*; -use util::{U256, H256, FixedHash, Address, Hashable}; -use tests::helpers::*; -use devtools::*; -use env_info::EnvInfo; -use spec::*; -use transaction::*; -use util::log::init_log; -use trace::{FlatTrace, TraceError, trace}; -use types::executed::CallType; + use std::sync::Arc; + use std::str::FromStr; + use rustc_serialize::hex::FromHex; + use super::*; + use util::{U256, H256, FixedHash, Address, Hashable}; + use tests::helpers::*; + use devtools::*; + use env_info::EnvInfo; + use spec::*; + use transaction::*; + use util::log::init_log; + use trace::{FlatTrace, TraceError, trace}; + use types::executed::CallType; -#[test] -fn should_apply_create_transaction() { - init_log(); + #[test] + fn should_apply_create_transaction() { + init_log(); - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Create, - value: 100.into(), - data: FromHex::from_hex("601080600c6000396000f3006000355415600957005b60203560003555").unwrap(), - }.sign(&"".sha3(), None); - - state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - subtraces: 0, - action: trace::Action::Create(trace::Create { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - value: 100.into(), - gas: 77412.into(), - init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], - }), - result: trace::Res::Create(trace::CreateResult { - gas_used: U256::from(3224), - address: Address::from_str("8988167e088c87cd314df6d3c2b83da5acb93ace").unwrap(), - code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53] - }), - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_work_when_cloned() { - init_log(); - - let a = Address::zero(); - - let temp = RandomTempPath::new(); - let mut state = { + let temp = RandomTempPath::new(); let mut state = get_temp_state_in(temp.as_path()); - assert_eq!(state.exists(&a), false); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Create, + value: 100.into(), + data: FromHex::from_hex("601080600c6000396000f3006000355415600957005b60203560003555").unwrap(), + }.sign(&"".sha3(), None); + + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + subtraces: 0, + action: trace::Action::Create(trace::Create { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + value: 100.into(), + gas: 77412.into(), + init: vec![96, 16, 128, 96, 12, 96, 0, 57, 96, 0, 243, 0, 96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53, 85], + }), + result: trace::Res::Create(trace::CreateResult { + gas_used: U256::from(3224), + address: Address::from_str("8988167e088c87cd314df6d3c2b83da5acb93ace").unwrap(), + code: vec![96, 0, 53, 84, 21, 96, 9, 87, 0, 91, 96, 32, 53, 96, 0, 53] + }), + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_work_when_cloned() { + init_log(); + + let a = Address::zero(); + + let temp = RandomTempPath::new(); + let mut state = { + let mut state = get_temp_state_in(temp.as_path()); + assert_eq!(state.exists(&a), false); + state.inc_nonce(&a); + state.commit().unwrap(); + state.clone() + }; + state.inc_nonce(&a); state.commit().unwrap(); - state.clone() - }; + } - state.inc_nonce(&a); - state.commit().unwrap(); -} + #[test] + fn should_trace_failed_create_transaction() { + init_log(); -#[test] -fn should_trace_failed_create_transaction() { - init_log(); + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Create, - value: 100.into(), - data: FromHex::from_hex("5b600056").unwrap(), - }.sign(&"".sha3(), None); - - state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - action: trace::Action::Create(trace::Create { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Create, value: 100.into(), - gas: 78792.into(), - init: vec![91, 96, 0, 86], - }), - result: trace::Res::FailedCreate(TraceError::OutOfGas), - subtraces: 0 - }]; + data: FromHex::from_hex("5b600056").unwrap(), + }.sign(&"".sha3(), None); - assert_eq!(result.trace, expected_trace); -} + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + action: trace::Action::Create(trace::Create { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + value: 100.into(), + gas: 78792.into(), + init: vec![91, 96, 0, 86], + }), + result: trace::Res::FailedCreate(TraceError::OutOfGas), + subtraces: 0 + }]; -#[test] -fn should_trace_call_transaction() { - init_log(); + assert_eq!(result.trace, expected_trace); + } - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); + #[test] + fn should_trace_call_transaction() { + init_log(); - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 100.into(), - data: vec![], - }.sign(&"".sha3(), None); + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); - state.init_code(&0xa.into(), FromHex::from_hex("6000").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), value: 100.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(3), - output: vec![] - }), - subtraces: 0, - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_trace_basic_call_transaction() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 100.into(), - data: vec![], - }.sign(&"".sha3(), None); - - state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 100.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(0), - output: vec![] - }), - subtraces: 0, - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_trace_call_transaction_to_builtin() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = &*Spec::new_test().engine; - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0x1.into()), - value: 0.into(), - data: vec![], - }.sign(&"".sha3(), None); - - let result = state.apply(&info, engine, &t, true).unwrap(); - - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: "0000000000000000000000000000000000000001".into(), - value: 0.into(), - gas: 79_000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(3000), - output: vec![] - }), - subtraces: 0, - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_not_trace_subcall_transaction_to_builtin() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = &*Spec::new_test().engine; - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 0.into(), - data: vec![], - }.sign(&"".sha3(), None); - - state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060006001610be0f1").unwrap()); - let result = state.apply(&info, engine, &t, true).unwrap(); - - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 0.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(28_061), - output: vec![] - }), - subtraces: 0, - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_not_trace_callcode() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = &*Spec::new_test().engine; - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 0.into(), - data: vec![], - }.sign(&"".sha3(), None); - - state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b611000f2").unwrap()); - state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); - let result = state.apply(&info, engine, &t, true).unwrap(); - - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - subtraces: 1, - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 0.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: 64.into(), - output: vec![] - }), - }, FlatTrace { - trace_address: vec![0].into_iter().collect(), - subtraces: 0, - action: trace::Action::Call(trace::Call { - from: 0xa.into(), - to: 0xa.into(), - value: 0.into(), - gas: 4096.into(), - input: vec![], - call_type: CallType::CallCode, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: 3.into(), - output: vec![], - }), - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_not_trace_delegatecall() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - info.number = 0x789b0; - let engine = &*Spec::new_test().engine; - - println!("schedule.have_delegate_call: {:?}", engine.schedule(&info).have_delegate_call); - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 0.into(), - data: vec![], - }.sign(&"".sha3(), None); - - state.init_code(&0xa.into(), FromHex::from_hex("6000600060006000600b618000f4").unwrap()); - state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); - let result = state.apply(&info, engine, &t, true).unwrap(); - - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - subtraces: 1, - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 0.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(61), - output: vec![] - }), - }, FlatTrace { - trace_address: vec![0].into_iter().collect(), - subtraces: 0, - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 0.into(), - gas: 32768.into(), - input: vec![], - call_type: CallType::DelegateCall, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: 3.into(), - output: vec![], - }), - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_trace_failed_call_transaction() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 100.into(), - data: vec![], - }.sign(&"".sha3(), None); - - state.init_code(&0xa.into(), FromHex::from_hex("5b600056").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 100.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::FailedCall(TraceError::OutOfGas), - subtraces: 0, - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_trace_call_with_subcall_transaction() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 100.into(), - data: vec![], - }.sign(&"".sha3(), None); - - state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); - state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - subtraces: 1, - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 100.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(69), - output: vec![] - }), - }, FlatTrace { - trace_address: vec![0].into_iter().collect(), - subtraces: 0, - action: trace::Action::Call(trace::Call { - from: 0xa.into(), - to: 0xb.into(), - value: 0.into(), - gas: 78934.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(3), - output: vec![] - }), - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_trace_call_with_basic_subcall_transaction() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 100.into(), - data: vec![], - }.sign(&"".sha3(), None); - - state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006045600b6000f1").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - subtraces: 1, - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 100.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(31761), - output: vec![] - }), - }, FlatTrace { - trace_address: vec![0].into_iter().collect(), - subtraces: 0, - action: trace::Action::Call(trace::Call { - from: 0xa.into(), - to: 0xb.into(), - value: 69.into(), - gas: 2300.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult::default()), - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_not_trace_call_with_invalid_basic_subcall_transaction() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 100.into(), - data: vec![], - }.sign(&"".sha3(), None); - - state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060ff600b6000f1").unwrap()); // not enough funds. - state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - subtraces: 0, - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 100.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(31761), - output: vec![] - }), - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_trace_failed_subcall_transaction() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 100.into(), - data: vec![],//600480600b6000396000f35b600056 - }.sign(&"".sha3(), None); - - state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); - state.init_code(&0xb.into(), FromHex::from_hex("5b600056").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - subtraces: 1, - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 100.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(79_000), - output: vec![] - }), - }, FlatTrace { - trace_address: vec![0].into_iter().collect(), - subtraces: 0, - action: trace::Action::Call(trace::Call { - from: 0xa.into(), - to: 0xb.into(), - value: 0.into(), - gas: 78934.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::FailedCall(TraceError::OutOfGas), - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_trace_call_with_subcall_with_subcall_transaction() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 100.into(), - data: vec![], - }.sign(&"".sha3(), None); - - state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); - state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1").unwrap()); - state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - subtraces: 1, - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 100.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(135), - output: vec![] - }), - }, FlatTrace { - trace_address: vec![0].into_iter().collect(), - subtraces: 1, - action: trace::Action::Call(trace::Call { - from: 0xa.into(), - to: 0xb.into(), - value: 0.into(), - gas: 78934.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(69), - output: vec![] - }), - }, FlatTrace { - trace_address: vec![0, 0].into_iter().collect(), - subtraces: 0, - action: trace::Action::Call(trace::Call { - from: 0xb.into(), - to: 0xc.into(), - value: 0.into(), - gas: 78868.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(3), - output: vec![] - }), - }]; - - assert_eq!(result.trace, expected_trace); -} - -#[test] -fn should_trace_failed_subcall_with_subcall_transaction() { - init_log(); - - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); - - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); - - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 100.into(), - data: vec![],//600480600b6000396000f35b600056 - }.sign(&"".sha3(), None); - - state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); - state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1505b601256").unwrap()); - state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap()); - state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - subtraces: 1, - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), - value: 100.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(79_000), - output: vec![] - }) - }, FlatTrace { - trace_address: vec![0].into_iter().collect(), - subtraces: 1, + data: vec![], + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("6000").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), action: trace::Action::Call(trace::Call { - from: 0xa.into(), - to: 0xb.into(), - value: 0.into(), - gas: 78934.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::FailedCall(TraceError::OutOfGas), - }, FlatTrace { - trace_address: vec![0, 0].into_iter().collect(), - subtraces: 0, - action: trace::Action::Call(trace::Call { - from: 0xb.into(), - to: 0xc.into(), - value: 0.into(), - gas: 78868.into(), - call_type: CallType::Call, - input: vec![], - }), - result: trace::Res::Call(trace::CallResult { - gas_used: U256::from(3), - output: vec![] - }), - }]; + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(3), + output: vec![] + }), + subtraces: 0, + }]; - assert_eq!(result.trace, expected_trace); -} + assert_eq!(result.trace, expected_trace); + } -#[test] -fn should_trace_suicide() { - init_log(); + #[test] + fn should_trace_basic_call_transaction() { + init_log(); - let temp = RandomTempPath::new(); - let mut state = get_temp_state_in(temp.as_path()); + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); - let mut info = EnvInfo::default(); - info.gas_limit = 1_000_000.into(); - let engine = TestEngine::new(5); + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); - let t = Transaction { - nonce: 0.into(), - gas_price: 0.into(), - gas: 100_000.into(), - action: Action::Call(0xa.into()), - value: 100.into(), - data: vec![], - }.sign(&"".sha3(), None); - - state.init_code(&0xa.into(), FromHex::from_hex("73000000000000000000000000000000000000000bff").unwrap()); - state.add_balance(&0xa.into(), &50.into(), CleanupMode::NoEmpty); - state.add_balance(t.sender().as_ref().unwrap(), &100.into(), CleanupMode::NoEmpty); - let result = state.apply(&info, &engine, &t, true).unwrap(); - let expected_trace = vec![FlatTrace { - trace_address: Default::default(), - subtraces: 1, - action: trace::Action::Call(trace::Call { - from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), - to: 0xa.into(), + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), value: 100.into(), - gas: 79000.into(), - input: vec![], - call_type: CallType::Call, - }), - result: trace::Res::Call(trace::CallResult { - gas_used: 3.into(), - output: vec![] - }), - }, FlatTrace { - trace_address: vec![0].into_iter().collect(), - subtraces: 0, - action: trace::Action::Suicide(trace::Suicide { - address: 0xa.into(), - refund_address: 0xb.into(), - balance: 150.into(), - }), - result: trace::Res::None, - }]; + data: vec![], + }.sign(&"".sha3(), None); - assert_eq!(result.trace, expected_trace); -} + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(0), + output: vec![] + }), + subtraces: 0, + }]; -#[test] -fn code_from_database() { - let a = Address::zero(); - let temp = RandomTempPath::new(); - let (root, db) = { + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_trace_call_transaction_to_builtin() { + init_log(); + + let temp = RandomTempPath::new(); let mut state = get_temp_state_in(temp.as_path()); - state.require_or_from(&a, false, ||Account::new_contract(42.into(), 0.into()), |_|{}); - state.init_code(&a, vec![1, 2, 3]); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = &*Spec::new_test().engine; + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0x1.into()), + value: 0.into(), + data: vec![], + }.sign(&"".sha3(), None); + + let result = state.apply(&info, engine, &t, true).unwrap(); + + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: "0000000000000000000000000000000000000001".into(), + value: 0.into(), + gas: 79_000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(3000), + output: vec![] + }), + subtraces: 0, + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_not_trace_subcall_transaction_to_builtin() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = &*Spec::new_test().engine; + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 0.into(), + data: vec![], + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060006001610be0f1").unwrap()); + let result = state.apply(&info, engine, &t, true).unwrap(); + + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 0.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(28_061), + output: vec![] + }), + subtraces: 0, + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_not_trace_callcode() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = &*Spec::new_test().engine; + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 0.into(), + data: vec![], + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b611000f2").unwrap()); + state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); + let result = state.apply(&info, engine, &t, true).unwrap(); + + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + subtraces: 1, + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 0.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: 64.into(), + output: vec![] + }), + }, FlatTrace { + trace_address: vec![0].into_iter().collect(), + subtraces: 0, + action: trace::Action::Call(trace::Call { + from: 0xa.into(), + to: 0xa.into(), + value: 0.into(), + gas: 4096.into(), + input: vec![], + call_type: CallType::CallCode, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: 3.into(), + output: vec![], + }), + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_not_trace_delegatecall() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + info.number = 0x789b0; + let engine = &*Spec::new_test().engine; + + println!("schedule.have_delegate_call: {:?}", engine.schedule(&info).have_delegate_call); + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 0.into(), + data: vec![], + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("6000600060006000600b618000f4").unwrap()); + state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); + let result = state.apply(&info, engine, &t, true).unwrap(); + + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + subtraces: 1, + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 0.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(61), + output: vec![] + }), + }, FlatTrace { + trace_address: vec![0].into_iter().collect(), + subtraces: 0, + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 0.into(), + gas: 32768.into(), + input: vec![], + call_type: CallType::DelegateCall, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: 3.into(), + output: vec![], + }), + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_trace_failed_call_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), + data: vec![], + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("5b600056").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::FailedCall(TraceError::OutOfGas), + subtraces: 0, + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_trace_call_with_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), + data: vec![], + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + subtraces: 1, + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(69), + output: vec![] + }), + }, FlatTrace { + trace_address: vec![0].into_iter().collect(), + subtraces: 0, + action: trace::Action::Call(trace::Call { + from: 0xa.into(), + to: 0xb.into(), + value: 0.into(), + gas: 78934.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(3), + output: vec![] + }), + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_trace_call_with_basic_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), + data: vec![], + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006045600b6000f1").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + subtraces: 1, + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(31761), + output: vec![] + }), + }, FlatTrace { + trace_address: vec![0].into_iter().collect(), + subtraces: 0, + action: trace::Action::Call(trace::Call { + from: 0xa.into(), + to: 0xb.into(), + value: 69.into(), + gas: 2300.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult::default()), + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_not_trace_call_with_invalid_basic_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), + data: vec![], + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060ff600b6000f1").unwrap()); // not enough funds. + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + subtraces: 0, + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(31761), + output: vec![] + }), + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_trace_failed_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), + data: vec![],//600480600b6000396000f35b600056 + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&0xb.into(), FromHex::from_hex("5b600056").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + subtraces: 1, + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(79_000), + output: vec![] + }), + }, FlatTrace { + trace_address: vec![0].into_iter().collect(), + subtraces: 0, + action: trace::Action::Call(trace::Call { + from: 0xa.into(), + to: 0xb.into(), + value: 0.into(), + gas: 78934.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::FailedCall(TraceError::OutOfGas), + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_trace_call_with_subcall_with_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), + data: vec![], + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1").unwrap()); + state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + subtraces: 1, + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(135), + output: vec![] + }), + }, FlatTrace { + trace_address: vec![0].into_iter().collect(), + subtraces: 1, + action: trace::Action::Call(trace::Call { + from: 0xa.into(), + to: 0xb.into(), + value: 0.into(), + gas: 78934.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(69), + output: vec![] + }), + }, FlatTrace { + trace_address: vec![0, 0].into_iter().collect(), + subtraces: 0, + action: trace::Action::Call(trace::Call { + from: 0xb.into(), + to: 0xc.into(), + value: 0.into(), + gas: 78868.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(3), + output: vec![] + }), + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_trace_failed_subcall_with_subcall_transaction() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), + data: vec![],//600480600b6000396000f35b600056 + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); + state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1505b601256").unwrap()); + state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap()); + state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + subtraces: 1, + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(79_000), + output: vec![] + }) + }, FlatTrace { + trace_address: vec![0].into_iter().collect(), + subtraces: 1, + action: trace::Action::Call(trace::Call { + from: 0xa.into(), + to: 0xb.into(), + value: 0.into(), + gas: 78934.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::FailedCall(TraceError::OutOfGas), + }, FlatTrace { + trace_address: vec![0, 0].into_iter().collect(), + subtraces: 0, + action: trace::Action::Call(trace::Call { + from: 0xb.into(), + to: 0xc.into(), + value: 0.into(), + gas: 78868.into(), + call_type: CallType::Call, + input: vec![], + }), + result: trace::Res::Call(trace::CallResult { + gas_used: U256::from(3), + output: vec![] + }), + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn should_trace_suicide() { + init_log(); + + let temp = RandomTempPath::new(); + let mut state = get_temp_state_in(temp.as_path()); + + let mut info = EnvInfo::default(); + info.gas_limit = 1_000_000.into(); + let engine = TestEngine::new(5); + + let t = Transaction { + nonce: 0.into(), + gas_price: 0.into(), + gas: 100_000.into(), + action: Action::Call(0xa.into()), + value: 100.into(), + data: vec![], + }.sign(&"".sha3(), None); + + state.init_code(&0xa.into(), FromHex::from_hex("73000000000000000000000000000000000000000bff").unwrap()); + state.add_balance(&0xa.into(), &50.into(), CleanupMode::NoEmpty); + state.add_balance(t.sender().as_ref().unwrap(), &100.into(), CleanupMode::NoEmpty); + let result = state.apply(&info, &engine, &t, true).unwrap(); + let expected_trace = vec![FlatTrace { + trace_address: Default::default(), + subtraces: 1, + action: trace::Action::Call(trace::Call { + from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(), + to: 0xa.into(), + value: 100.into(), + gas: 79000.into(), + input: vec![], + call_type: CallType::Call, + }), + result: trace::Res::Call(trace::CallResult { + gas_used: 3.into(), + output: vec![] + }), + }, FlatTrace { + trace_address: vec![0].into_iter().collect(), + subtraces: 0, + action: trace::Action::Suicide(trace::Suicide { + address: 0xa.into(), + refund_address: 0xb.into(), + balance: 150.into(), + }), + result: trace::Res::None, + }]; + + assert_eq!(result.trace, expected_trace); + } + + #[test] + fn code_from_database() { + let a = Address::zero(); + let temp = RandomTempPath::new(); + let (root, db) = { + let mut state = get_temp_state_in(temp.as_path()); + state.require_or_from(&a, false, ||Account::new_contract(42.into(), 0.into()), |_|{}); + state.init_code(&a, vec![1, 2, 3]); + assert_eq!(state.code(&a), Some(Arc::new([1u8, 2, 3].to_vec()))); + state.commit().unwrap(); + assert_eq!(state.code(&a), Some(Arc::new([1u8, 2, 3].to_vec()))); + state.drop() + }; + + let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); assert_eq!(state.code(&a), Some(Arc::new([1u8, 2, 3].to_vec()))); - state.commit().unwrap(); - assert_eq!(state.code(&a), Some(Arc::new([1u8, 2, 3].to_vec()))); - state.drop() - }; + } - let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); - assert_eq!(state.code(&a), Some(Arc::new([1u8, 2, 3].to_vec()))); -} + #[test] + fn storage_at_from_database() { + let a = Address::zero(); + let temp = RandomTempPath::new(); + let (root, db) = { + let mut state = get_temp_state_in(temp.as_path()); + state.set_storage(&a, H256::from(&U256::from(1u64)), H256::from(&U256::from(69u64))); + state.commit().unwrap(); + state.drop() + }; -#[test] -fn storage_at_from_database() { - let a = Address::zero(); - let temp = RandomTempPath::new(); - let (root, db) = { - let mut state = get_temp_state_in(temp.as_path()); - state.set_storage(&a, H256::from(&U256::from(1u64)), H256::from(&U256::from(69u64))); - state.commit().unwrap(); - state.drop() - }; + let s = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); + assert_eq!(s.storage_at(&a, &H256::from(&U256::from(1u64))), H256::from(&U256::from(69u64))); + } - let s = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); - assert_eq!(s.storage_at(&a, &H256::from(&U256::from(1u64))), H256::from(&U256::from(69u64))); -} + #[test] + fn get_from_database() { + let a = Address::zero(); + let temp = RandomTempPath::new(); + let (root, db) = { + let mut state = get_temp_state_in(temp.as_path()); + state.inc_nonce(&a); + state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty); + state.commit().unwrap(); + assert_eq!(state.balance(&a), U256::from(69u64)); + state.drop() + }; -#[test] -fn get_from_database() { - let a = Address::zero(); - let temp = RandomTempPath::new(); - let (root, db) = { - let mut state = get_temp_state_in(temp.as_path()); - state.inc_nonce(&a); - state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty); - state.commit().unwrap(); + let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); assert_eq!(state.balance(&a), U256::from(69u64)); - state.drop() - }; - - let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); - assert_eq!(state.balance(&a), U256::from(69u64)); - assert_eq!(state.nonce(&a), U256::from(1u64)); -} - -#[test] -fn remove() { - let a = Address::zero(); - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); - assert_eq!(state.exists(&a), false); - assert_eq!(state.exists_and_not_null(&a), false); - state.inc_nonce(&a); - assert_eq!(state.exists(&a), true); - assert_eq!(state.exists_and_not_null(&a), true); - assert_eq!(state.nonce(&a), U256::from(1u64)); - state.kill_account(&a); - assert_eq!(state.exists(&a), false); - assert_eq!(state.exists_and_not_null(&a), false); - assert_eq!(state.nonce(&a), U256::from(0u64)); -} - -#[test] -fn empty_account_is_not_created() { - let a = Address::zero(); - let path = RandomTempPath::new(); - let db = get_temp_state_db_in(path.as_path()); - let (root, db) = { - let mut state = State::new(db, U256::from(0), Default::default()); - state.add_balance(&a, &U256::default(), CleanupMode::NoEmpty); // create an empty account - state.commit().unwrap(); - state.drop() - }; - let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); - assert!(!state.exists(&a)); - assert!(!state.exists_and_not_null(&a)); -} - -#[test] -fn empty_account_exists_when_creation_forced() { - let a = Address::zero(); - let path = RandomTempPath::new(); - let db = get_temp_state_db_in(path.as_path()); - let (root, db) = { - let mut state = State::new(db, U256::from(0), Default::default()); - state.add_balance(&a, &U256::default(), CleanupMode::ForceCreate); // create an empty account - state.commit().unwrap(); - state.drop() - }; - let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); - assert!(state.exists(&a)); - assert!(!state.exists_and_not_null(&a)); -} - -#[test] -fn remove_from_database() { - let a = Address::zero(); - let temp = RandomTempPath::new(); - let (root, db) = { - let mut state = get_temp_state_in(temp.as_path()); - state.inc_nonce(&a); - state.commit().unwrap(); - assert_eq!(state.exists(&a), true); assert_eq!(state.nonce(&a), U256::from(1u64)); - state.drop() - }; + } - let (root, db) = { - let mut state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); + #[test] + fn remove() { + let a = Address::zero(); + let mut state_result = get_temp_state(); + let mut state = state_result.reference_mut(); + assert_eq!(state.exists(&a), false); + assert_eq!(state.exists_and_not_null(&a), false); + state.inc_nonce(&a); assert_eq!(state.exists(&a), true); + assert_eq!(state.exists_and_not_null(&a), true); assert_eq!(state.nonce(&a), U256::from(1u64)); state.kill_account(&a); - state.commit().unwrap(); + assert_eq!(state.exists(&a), false); + assert_eq!(state.exists_and_not_null(&a), false); + assert_eq!(state.nonce(&a), U256::from(0u64)); + } + + #[test] + fn empty_account_is_not_created() { + let a = Address::zero(); + let path = RandomTempPath::new(); + let db = get_temp_state_db_in(path.as_path()); + let (root, db) = { + let mut state = State::new(db, U256::from(0), Default::default()); + state.add_balance(&a, &U256::default(), CleanupMode::NoEmpty); // create an empty account + state.commit().unwrap(); + state.drop() + }; + let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); + assert!(!state.exists(&a)); + assert!(!state.exists_and_not_null(&a)); + } + + #[test] + fn empty_account_exists_when_creation_forced() { + let a = Address::zero(); + let path = RandomTempPath::new(); + let db = get_temp_state_db_in(path.as_path()); + let (root, db) = { + let mut state = State::new(db, U256::from(0), Default::default()); + state.add_balance(&a, &U256::default(), CleanupMode::ForceCreate); // create an empty account + state.commit().unwrap(); + state.drop() + }; + let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); + assert!(state.exists(&a)); + assert!(!state.exists_and_not_null(&a)); + } + + #[test] + fn remove_from_database() { + let a = Address::zero(); + let temp = RandomTempPath::new(); + let (root, db) = { + let mut state = get_temp_state_in(temp.as_path()); + state.inc_nonce(&a); + state.commit().unwrap(); + assert_eq!(state.exists(&a), true); + assert_eq!(state.nonce(&a), U256::from(1u64)); + state.drop() + }; + + let (root, db) = { + let mut state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); + assert_eq!(state.exists(&a), true); + assert_eq!(state.nonce(&a), U256::from(1u64)); + state.kill_account(&a); + state.commit().unwrap(); + assert_eq!(state.exists(&a), false); + assert_eq!(state.nonce(&a), U256::from(0u64)); + state.drop() + }; + + let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); assert_eq!(state.exists(&a), false); assert_eq!(state.nonce(&a), U256::from(0u64)); - state.drop() - }; + } - let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); - assert_eq!(state.exists(&a), false); - assert_eq!(state.nonce(&a), U256::from(0u64)); -} + #[test] + fn alter_balance() { + let mut state_result = get_temp_state(); + let mut state = state_result.reference_mut(); + let a = Address::zero(); + let b = 1u64.into(); + state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty); + assert_eq!(state.balance(&a), U256::from(69u64)); + state.commit().unwrap(); + assert_eq!(state.balance(&a), U256::from(69u64)); + state.sub_balance(&a, &U256::from(42u64)); + assert_eq!(state.balance(&a), U256::from(27u64)); + state.commit().unwrap(); + assert_eq!(state.balance(&a), U256::from(27u64)); + state.transfer_balance(&a, &b, &U256::from(18u64), CleanupMode::NoEmpty); + assert_eq!(state.balance(&a), U256::from(9u64)); + assert_eq!(state.balance(&b), U256::from(18u64)); + state.commit().unwrap(); + assert_eq!(state.balance(&a), U256::from(9u64)); + assert_eq!(state.balance(&b), U256::from(18u64)); + } -#[test] -fn alter_balance() { - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); - let a = Address::zero(); - let b = 1u64.into(); - state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty); - assert_eq!(state.balance(&a), U256::from(69u64)); - state.commit().unwrap(); - assert_eq!(state.balance(&a), U256::from(69u64)); - state.sub_balance(&a, &U256::from(42u64)); - assert_eq!(state.balance(&a), U256::from(27u64)); - state.commit().unwrap(); - assert_eq!(state.balance(&a), U256::from(27u64)); - state.transfer_balance(&a, &b, &U256::from(18u64), CleanupMode::NoEmpty); - assert_eq!(state.balance(&a), U256::from(9u64)); - assert_eq!(state.balance(&b), U256::from(18u64)); - state.commit().unwrap(); - assert_eq!(state.balance(&a), U256::from(9u64)); - assert_eq!(state.balance(&b), U256::from(18u64)); -} + #[test] + fn alter_nonce() { + let mut state_result = get_temp_state(); + let mut state = state_result.reference_mut(); + let a = Address::zero(); + state.inc_nonce(&a); + assert_eq!(state.nonce(&a), U256::from(1u64)); + state.inc_nonce(&a); + assert_eq!(state.nonce(&a), U256::from(2u64)); + state.commit().unwrap(); + assert_eq!(state.nonce(&a), U256::from(2u64)); + state.inc_nonce(&a); + assert_eq!(state.nonce(&a), U256::from(3u64)); + state.commit().unwrap(); + assert_eq!(state.nonce(&a), U256::from(3u64)); + } -#[test] -fn alter_nonce() { - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); - let a = Address::zero(); - state.inc_nonce(&a); - assert_eq!(state.nonce(&a), U256::from(1u64)); - state.inc_nonce(&a); - assert_eq!(state.nonce(&a), U256::from(2u64)); - state.commit().unwrap(); - assert_eq!(state.nonce(&a), U256::from(2u64)); - state.inc_nonce(&a); - assert_eq!(state.nonce(&a), U256::from(3u64)); - state.commit().unwrap(); - assert_eq!(state.nonce(&a), U256::from(3u64)); -} + #[test] + fn balance_nonce() { + let mut state_result = get_temp_state(); + let mut state = state_result.reference_mut(); + let a = Address::zero(); + assert_eq!(state.balance(&a), U256::from(0u64)); + assert_eq!(state.nonce(&a), U256::from(0u64)); + state.commit().unwrap(); + assert_eq!(state.balance(&a), U256::from(0u64)); + assert_eq!(state.nonce(&a), U256::from(0u64)); + } -#[test] -fn balance_nonce() { - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); - let a = Address::zero(); - assert_eq!(state.balance(&a), U256::from(0u64)); - assert_eq!(state.nonce(&a), U256::from(0u64)); - state.commit().unwrap(); - assert_eq!(state.balance(&a), U256::from(0u64)); - assert_eq!(state.nonce(&a), U256::from(0u64)); -} + #[test] + fn ensure_cached() { + let mut state_result = get_temp_state(); + let mut state = state_result.reference_mut(); + let a = Address::zero(); + state.require(&a, false); + state.commit().unwrap(); + assert_eq!(state.root().hex(), "0ce23f3c809de377b008a4a3ee94a0834aac8bec1f86e28ffe4fdb5a15b0c785"); + } -#[test] -fn ensure_cached() { - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); - let a = Address::zero(); - state.require(&a, false); - state.commit().unwrap(); - assert_eq!(state.root().hex(), "0ce23f3c809de377b008a4a3ee94a0834aac8bec1f86e28ffe4fdb5a15b0c785"); -} + #[test] + fn checkpoint_basic() { + let mut state_result = get_temp_state(); + let mut state = state_result.reference_mut(); + let a = Address::zero(); + state.checkpoint(); + state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty); + assert_eq!(state.balance(&a), U256::from(69u64)); + state.discard_checkpoint(); + assert_eq!(state.balance(&a), U256::from(69u64)); + state.checkpoint(); + state.add_balance(&a, &U256::from(1u64), CleanupMode::NoEmpty); + assert_eq!(state.balance(&a), U256::from(70u64)); + state.revert_to_checkpoint(); + assert_eq!(state.balance(&a), U256::from(69u64)); + } -#[test] -fn checkpoint_basic() { - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); - let a = Address::zero(); - state.checkpoint(); - state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty); - assert_eq!(state.balance(&a), U256::from(69u64)); - state.discard_checkpoint(); - assert_eq!(state.balance(&a), U256::from(69u64)); - state.checkpoint(); - state.add_balance(&a, &U256::from(1u64), CleanupMode::NoEmpty); - assert_eq!(state.balance(&a), U256::from(70u64)); - state.revert_to_checkpoint(); - assert_eq!(state.balance(&a), U256::from(69u64)); -} + #[test] + fn checkpoint_nested() { + let mut state_result = get_temp_state(); + let mut state = state_result.reference_mut(); + let a = Address::zero(); + state.checkpoint(); + state.checkpoint(); + state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty); + assert_eq!(state.balance(&a), U256::from(69u64)); + state.discard_checkpoint(); + assert_eq!(state.balance(&a), U256::from(69u64)); + state.revert_to_checkpoint(); + assert_eq!(state.balance(&a), U256::from(0)); + } -#[test] -fn checkpoint_nested() { - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); - let a = Address::zero(); - state.checkpoint(); - state.checkpoint(); - state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty); - assert_eq!(state.balance(&a), U256::from(69u64)); - state.discard_checkpoint(); - assert_eq!(state.balance(&a), U256::from(69u64)); - state.revert_to_checkpoint(); - assert_eq!(state.balance(&a), U256::from(0)); -} + #[test] + fn create_empty() { + let mut state_result = get_temp_state(); + let mut state = state_result.reference_mut(); + state.commit().unwrap(); + assert_eq!(state.root().hex(), "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); + } -#[test] -fn create_empty() { - let mut state_result = get_temp_state(); - let mut state = state_result.reference_mut(); - state.commit().unwrap(); - assert_eq!(state.root().hex(), "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); -} + #[test] + fn should_not_panic_on_state_diff_with_storage() { + let state = get_temp_state(); + let mut state = state.reference().clone(); -#[test] -fn should_not_panic_on_state_diff_with_storage() { - let state = get_temp_state(); - let mut state = state.reference().clone(); + let a: Address = 0xa.into(); + state.init_code(&a, b"abcdefg".to_vec()); + state.add_balance(&a, &256.into(), CleanupMode::NoEmpty); + state.set_storage(&a, 0xb.into(), 0xc.into()); - let a: Address = 0xa.into(); - state.init_code(&a, b"abcdefg".to_vec()); - state.add_balance(&a, &256.into(), CleanupMode::NoEmpty); - state.set_storage(&a, 0xb.into(), 0xc.into()); + let mut new_state = state.clone(); + new_state.set_storage(&a, 0xb.into(), 0xd.into()); - let mut new_state = state.clone(); - new_state.set_storage(&a, 0xb.into(), 0xd.into()); - - new_state.diff_from(state); -} + new_state.diff_from(state); + } } diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 77a6f117a..e952fe27a 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -286,7 +286,7 @@ fn new_db(path: &str) -> Arc { pub fn generate_dummy_blockchain(block_number: u32) -> GuardedTempResult { let temp = RandomTempPath::new(); let db = new_db(temp.as_str()); - let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), db.clone()); + let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), db.clone(), Spec::new_null().engine); let mut batch = db.transaction(); for block_order in 1..block_number { @@ -304,7 +304,7 @@ pub fn generate_dummy_blockchain(block_number: u32) -> GuardedTempResult GuardedTempResult { let temp = RandomTempPath::new(); let db = new_db(temp.as_str()); - let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), db.clone()); + let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), db.clone(), Spec::new_null().engine); let mut batch = db.transaction(); @@ -323,7 +323,7 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> GuardedTempRes pub fn generate_dummy_empty_blockchain() -> GuardedTempResult { let temp = RandomTempPath::new(); let db = new_db(temp.as_str()); - let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), db.clone()); + let bc = BlockChain::new(BlockChainConfig::default(), &create_unverifiable_block(0, H256::zero()), db.clone(), Spec::new_null().engine); GuardedTempResult:: { _temp: temp, diff --git a/ethcore/src/types/transaction.rs b/ethcore/src/types/transaction.rs index 91a4ac836..2cc25a745 100644 --- a/ethcore/src/types/transaction.rs +++ b/ethcore/src/types/transaction.rs @@ -72,7 +72,7 @@ pub struct Transaction { impl Transaction { /// Append object with a without signature into RLP stream - pub fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream, network_id: Option) { + pub fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream, network_id: Option) { s.begin_list(if network_id.is_none() { 6 } else { 9 }); s.append(&self.nonce); s.append(&self.gas_price); @@ -140,26 +140,26 @@ impl From for SignedTransaction { impl Transaction { /// The message hash of the transaction. - pub fn hash(&self, network_id: Option) -> H256 { + pub fn hash(&self, network_id: Option) -> H256 { let mut stream = RlpStream::new(); self.rlp_append_unsigned_transaction(&mut stream, network_id); stream.out().sha3() } /// Signs the transaction as coming from `sender`. - pub fn sign(self, secret: &Secret, network_id: Option) -> SignedTransaction { + pub fn sign(self, secret: &Secret, network_id: Option) -> SignedTransaction { let sig = ::ethkey::sign(secret, &self.hash(network_id)) .expect("data is valid and context has signing capabilities; qed"); self.with_signature(sig, network_id) } /// Signs the transaction with signature. - pub fn with_signature(self, sig: Signature, network_id: Option) -> SignedTransaction { + pub fn with_signature(self, sig: Signature, network_id: Option) -> SignedTransaction { SignedTransaction { unsigned: self, r: sig.r().into(), s: sig.s().into(), - v: sig.v() + if let Some(n) = network_id { 35 + n * 2 } else { 27 }, + v: sig.v() as u64 + if let Some(n) = network_id { 35 + n * 2 } else { 27 }, hash: Cell::new(None), sender: Cell::new(None), } @@ -211,7 +211,7 @@ pub struct SignedTransaction { unsigned: Transaction, /// The V field of the signature; the LS bit described which half of the curve our point falls /// in. The MS bits describe which network this transaction is for. If 27/28, its for all networks. - v: u8, + v: u64, /// The R field of the signature; helps describe the point on the curve. r: U256, /// The S field of the signature; helps describe the point on the curve. @@ -302,13 +302,13 @@ impl SignedTransaction { } /// 0 if `v` would have been 27 under "Electrum" notation, 1 if 28 or 4 if invalid. - pub fn standard_v(&self) -> u8 { match self.v { v if v == 27 || v == 28 || v > 36 => (v - 1) % 2, _ => 4 } } + pub fn standard_v(&self) -> u8 { match self.v { v if v == 27 || v == 28 || v > 36 => ((v - 1) % 2) as u8, _ => 4 } } /// The `v` value that appears in the RLP. pub fn original_v(&self) -> u8 { self.v } - /// The network ID, or `None` if this is a global transaction. - pub fn network_id(&self) -> Option { + /// The network ID, or `None` if this is a global transaction. + pub fn network_id(&self) -> Option { match self.v { v if v > 36 => Some((v - 35) / 2), _ => None, diff --git a/ethcore/src/verification/queue/mod.rs b/ethcore/src/verification/queue/mod.rs index 686a1d093..14df0819c 100644 --- a/ethcore/src/verification/queue/mod.rs +++ b/ethcore/src/verification/queue/mod.rs @@ -17,7 +17,7 @@ //! A queue of blocks. Sits between network or other I/O and the `BlockChain`. //! Sorts them ready for blockchain insertion. -use std::thread::{JoinHandle, self}; +use std::thread::{self, JoinHandle}; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering as AtomicOrdering}; use std::sync::{Condvar as SCondvar, Mutex as SMutex}; use util::*; @@ -64,35 +64,11 @@ impl Default for Config { } } -struct VerifierHandle { - deleting: Arc, - sleep: Arc, - thread: JoinHandle<()>, -} - -impl VerifierHandle { - // signal to the verifier thread that it should sleep. - fn sleep(&self) { - self.sleep.store(true, AtomicOrdering::SeqCst); - } - - // signal to the verifier thread that it should wake up. - fn wake_up(&self) { - self.sleep.store(false, AtomicOrdering::SeqCst); - self.thread.thread().unpark(); - } - - // signal to the verifier thread that it should conclude its - // operations. - fn conclude(&self) { - self.wake_up(); - self.deleting.store(true, AtomicOrdering::Release); - } - - // join the verifier thread. - fn join(self) { - self.thread.join().expect("Verifier thread panicked"); - } +// pool states +enum State { + // all threads with id < inner value are to work. + Work(usize), + Exit, } /// An item which is in the process of being verified. @@ -131,7 +107,6 @@ pub struct VerificationQueue { engine: Arc, more_to_verify: Arc, verification: Arc>, - verifiers: Mutex<(Vec, usize)>, deleting: Arc, ready_signal: Arc, empty: Arc, @@ -139,6 +114,8 @@ pub struct VerificationQueue { ticks_since_adjustment: AtomicUsize, max_queue_size: usize, max_mem_use: usize, + verifier_handles: Vec>, + state: Arc<(Mutex, Condvar)>, } struct QueueSignal { @@ -224,40 +201,39 @@ impl VerificationQueue { let max_verifiers = min(::num_cpus::get(), MAX_VERIFIERS); let default_amount = max(::num_cpus::get(), 3) - 2; - let mut verifiers = Vec::with_capacity(max_verifiers); + let state = Arc::new((Mutex::new(State::Work(default_amount)), Condvar::new())); + let mut verifier_handles = Vec::with_capacity(max_verifiers); debug!(target: "verification", "Allocating {} verifiers, {} initially active", max_verifiers, default_amount); for i in 0..max_verifiers { debug!(target: "verification", "Adding verification thread #{}", i); - let deleting = deleting.clone(); let panic_handler = panic_handler.clone(); let verification = verification.clone(); let engine = engine.clone(); let wait = more_to_verify.clone(); let ready = ready_signal.clone(); let empty = empty.clone(); + let state = state.clone(); - // enable only the first few verifiers. - let sleep = if i < default_amount { - Arc::new(AtomicBool::new(false)) - } else { - Arc::new(AtomicBool::new(true)) - }; - - verifiers.push(VerifierHandle { - deleting: deleting.clone(), - sleep: sleep.clone(), - thread: thread::Builder::new() - .name(format!("Verifier #{}", i)) - .spawn(move || { - panic_handler.catch_panic(move || { - VerificationQueue::verify(verification, engine, wait, ready, deleting, empty, sleep) - }).unwrap() - }) - .expect("Failed to create verifier thread.") - }); + let handle = thread::Builder::new() + .name(format!("Verifier #{}", i)) + .spawn(move || { + panic_handler.catch_panic(move || { + VerificationQueue::verify( + verification, + engine, + wait, + ready, + empty, + state, + i, + ) + }).unwrap() + }) + .expect("Failed to create verifier thread."); + verifier_handles.push(handle); } VerificationQueue { @@ -266,13 +242,14 @@ impl VerificationQueue { ready_signal: ready_signal, more_to_verify: more_to_verify, verification: verification, - verifiers: Mutex::new((verifiers, default_amount)), deleting: deleting, processing: RwLock::new(HashSet::new()), empty: empty, ticks_since_adjustment: AtomicUsize::new(0), max_queue_size: max(config.max_queue_size, MIN_QUEUE_LIMIT), max_mem_use: max(config.max_mem_use, MIN_MEM_LIMIT), + verifier_handles: verifier_handles, + state: state, } } @@ -281,23 +258,30 @@ impl VerificationQueue { engine: Arc, wait: Arc, ready: Arc, - deleting: Arc, empty: Arc, - sleep: Arc, + state: Arc<(Mutex, Condvar)>, + id: usize, ) { - while !deleting.load(AtomicOrdering::Acquire) { + loop { + // check current state. { - while sleep.load(AtomicOrdering::SeqCst) { - trace!(target: "verification", "Verifier sleeping"); - ::std::thread::park(); - trace!(target: "verification", "Verifier waking up"); + let mut cur_state = state.0.lock(); + while let State::Work(x) = *cur_state { + // sleep until this thread is required. + if id < x { break } - if deleting.load(AtomicOrdering::Acquire) { - return; - } + debug!(target: "verification", "verifier {} sleeping", id); + state.1.wait(&mut cur_state); + debug!(target: "verification", "verifier {} waking up", id); + } + + if let State::Exit = *cur_state { + debug!(target: "verification", "verifier {} exiting", id); + break; } } + // wait for work if empty. { let mut more_to_verify = verification.more_to_verify.lock().unwrap(); @@ -305,15 +289,22 @@ impl VerificationQueue { empty.notify_all(); } - while verification.unverified.lock().is_empty() && !deleting.load(AtomicOrdering::Acquire) { + while verification.unverified.lock().is_empty() { + if let State::Exit = *state.0.lock() { + debug!(target: "verification", "verifier {} exiting", id); + return; + } + more_to_verify = wait.wait(more_to_verify).unwrap(); } - if deleting.load(AtomicOrdering::Acquire) { + if let State::Exit = *state.0.lock() { + debug!(target: "verification", "verifier {} exiting", id); return; } } + // do work. let item = { // acquire these locks before getting the item to verify. let mut unverified = verification.unverified.lock(); @@ -568,6 +559,14 @@ impl VerificationQueue { } } + /// Get the current number of working verifiers. + pub fn num_verifiers(&self) -> usize { + match *self.state.0.lock() { + State::Work(x) => x, + State::Exit => panic!("state only set to exit on drop; queue live now; qed"), + } + } + /// Optimise memory footprint of the heap fields, and adjust the number of threads /// to better suit the workload. pub fn collect_garbage(&self) { @@ -604,7 +603,7 @@ impl VerificationQueue { return; } - let current = self.verifiers.lock().1; + let current = self.num_verifiers(); let diff = (v_len - u_len).abs(); let total = v_len + u_len; @@ -626,27 +625,14 @@ impl VerificationQueue { // possible, never going over the amount of initially allocated threads // or below 1. fn scale_verifiers(&self, target: usize) { - let mut verifiers = self.verifiers.lock(); - let &mut (ref mut verifiers, ref mut verifier_count) = &mut *verifiers; - - let target = min(verifiers.len(), target); + let current = self.num_verifiers(); + let target = min(self.verifier_handles.len(), target); let target = max(1, target); - debug!(target: "verification", "Scaling from {} to {} verifiers", verifier_count, target); + debug!(target: "verification", "Scaling from {} to {} verifiers", current, target); - // scaling up - for i in *verifier_count..target { - debug!(target: "verification", "Waking up verifier {}", i); - verifiers[i].wake_up(); - } - - // scaling down. - for i in target..*verifier_count { - debug!(target: "verification", "Putting verifier {} to sleep", i); - verifiers[i].sleep(); - } - - *verifier_count = target; + *self.state.0.lock() = State::Work(target); + self.state.1.notify_all(); } } @@ -660,22 +646,18 @@ impl Drop for VerificationQueue { fn drop(&mut self) { trace!(target: "shutdown", "[VerificationQueue] Closing..."); self.clear(); - self.deleting.store(true, AtomicOrdering::Release); + self.deleting.store(true, AtomicOrdering::SeqCst); - let mut verifiers = self.verifiers.get_mut(); - let mut verifiers = &mut verifiers.0; - - // first pass to signal conclusion. must be done before - // notify or deadlock possible. - for handle in verifiers.iter() { - handle.conclude(); - } + // set exit state; should be done before `more_to_verify` notification. + *self.state.0.lock() = State::Exit; + self.state.1.notify_all(); + // wake up all threads waiting for more work. self.more_to_verify.notify_all(); - // second pass to join. - for handle in verifiers.drain(..) { - handle.join(); + // wait for all verifier threads to join. + for thread in self.verifier_handles.drain(..) { + thread.join().expect("Propagating verifier thread panic on shutdown"); } trace!(target: "shutdown", "[VerificationQueue] Closed."); @@ -687,7 +669,7 @@ mod tests { use util::*; use io::*; use spec::*; - use super::{BlockQueue, Config}; + use super::{BlockQueue, Config, State}; use super::kind::blocks::Unverified; use tests::helpers::*; use error::*; @@ -784,11 +766,11 @@ mod tests { let queue = get_test_queue(); queue.scale_verifiers(MAX_VERIFIERS + 1); - assert!(queue.verifiers.lock().1 < MAX_VERIFIERS + 1); + assert!(queue.num_verifiers() < MAX_VERIFIERS + 1); queue.scale_verifiers(0); - assert!(queue.verifiers.lock().1 == 1); + assert!(queue.num_verifiers() == 1); } #[test] @@ -797,14 +779,7 @@ mod tests { // put all the verifiers to sleep to ensure // the test isn't timing sensitive. - let num_verifiers = { - let verifiers = queue.verifiers.lock(); - for i in 0..verifiers.1 { - verifiers.0[i].sleep(); - } - - verifiers.1 - }; + *queue.state.0.lock() = State::Work(0); for block in get_good_dummy_block_seq(5000) { queue.import(Unverified::new(block)).expect("Block good by definition; qed"); @@ -812,20 +787,12 @@ mod tests { // almost all unverified == bump verifier count. queue.collect_garbage(); - assert_eq!(queue.verifiers.lock().1, num_verifiers + 1); - - // wake them up again and verify everything. - { - let verifiers = queue.verifiers.lock(); - for i in 0..verifiers.1 { - verifiers.0[i].wake_up(); - } - } + assert_eq!(queue.num_verifiers(), 1); queue.flush(); // nothing to verify == use minimum number of verifiers. queue.collect_garbage(); - assert_eq!(queue.verifiers.lock().1, 1); + assert_eq!(queue.num_verifiers(), 1); } } diff --git a/js/.npmrc b/js/.npmrc index 3f7b4cf25..a00908d4f 100644 --- a/js/.npmrc +++ b/js/.npmrc @@ -1 +1 @@ -save-prefix='~' +save-prefix='' diff --git a/js/package.json b/js/package.json index 4957c7f19..42836bb7c 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "0.2.82", + "version": "0.2.92", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", @@ -47,133 +47,127 @@ "prepush": "npm run lint:cached" }, "devDependencies": { - "babel-cli": "~6.18.0", - "babel-core": "~6.18.2", - "babel-eslint": "~7.1.0", - "babel-loader": "~6.2.3", - "babel-plugin-lodash": "~3.2.2", - "babel-plugin-transform-class-properties": "~6.19.0", - "babel-plugin-transform-decorators-legacy": "~1.3.4", - "babel-plugin-transform-react-remove-prop-types": "~0.2.9", - "babel-plugin-transform-runtime": "~6.15.0", - "babel-polyfill": "~6.16.0", - "babel-preset-es2015": "~6.18.0", - "babel-preset-es2015-rollup": "~1.2.0", - "babel-preset-es2016": "~6.16.0", - "babel-preset-es2017": "~6.16.0", - "babel-preset-react": "~6.16.0", - "babel-preset-stage-0": "~6.16.0", + "babel-cli": "6.18.0", + "babel-core": "6.18.2", + "babel-eslint": "7.1.1", + "babel-loader": "6.2.8", + "babel-plugin-lodash": "3.2.10", + "babel-plugin-transform-class-properties": "6.19.0", + "babel-plugin-transform-decorators-legacy": "1.3.4", + "babel-plugin-transform-react-remove-prop-types": "0.2.11", + "babel-plugin-transform-runtime": "6.15.0", + "babel-polyfill": "6.16.0", + "babel-preset-es2015": "6.18.0", + "babel-preset-es2015-rollup": "1.2.0", + "babel-preset-es2016": "6.16.0", + "babel-preset-es2017": "6.16.0", + "babel-preset-react": "6.16.0", + "babel-preset-stage-0": "6.16.0", "babel-register": "6.18.0", - "babel-runtime": "~6.18.0", - "chai": "~3.5.0", - "chai-enzyme": "0.4.2", - "cheerio": "0.20.0", - "copy-webpack-plugin": "~4.0.0", - "core-js": "~2.4.1", - "coveralls": "~2.11.11", - "css-loader": "~0.26.0", - "ejs-loader": "~0.3.0", - "enzyme": "2.3.0", - "eslint": "~3.10.2", - "eslint-config-semistandard": "~7.0.0", - "eslint-config-standard": "~6.2.1", - "eslint-config-standard-react": "~4.2.0", - "eslint-plugin-promise": "~3.4.0", - "eslint-plugin-react": "~6.7.1", - "eslint-plugin-standard": "~2.0.0", - "express": "~4.14.0", + "babel-runtime": "6.18.0", + "chai": "3.5.0", + "chai-enzyme": "0.6.1", + "copy-webpack-plugin": "4.0.1", + "core-js": "2.4.1", + "coveralls": "2.11.15", + "css-loader": "0.26.1", + "ejs-loader": "0.3.0", + "enzyme": "2.6.0", + "eslint": "3.11.1", + "eslint-config-semistandard": "7.0.0", + "eslint-config-standard": "6.2.1", + "eslint-config-standard-react": "4.2.0", + "eslint-plugin-promise": "3.4.0", + "eslint-plugin-react": "6.7.1", + "eslint-plugin-standard": "2.0.1", + "express": "4.14.0", "extract-loader": "0.1.0", - "extract-text-webpack-plugin": "~2.0.0-beta.4", - "file-loader": "~0.9.0", - "fs-extra": "~0.30.0", - "happypack": "~3.0.0", - "history": "~2.0.0", - "html-loader": "~0.4.4", - "html-webpack-plugin": "~2.24.1", - "http-proxy-middleware": "~0.17.2", - "husky": "~0.11.9", - "ignore-styles": "2.0.0", - "image-webpack-loader": "~3.0.0", - "istanbul": "~1.0.0-alpha.2", - "jsdom": "9.2.1", - "json-loader": "~0.5.4", - "mocha": "~3.0.0-1", + "extract-text-webpack-plugin": "2.0.0-beta.4", + "file-loader": "0.9.0", + "happypack": "3.0.0", + "html-loader": "0.4.4", + "html-webpack-plugin": "2.24.1", + "http-proxy-middleware": "0.17.2", + "husky": "0.11.9", + "ignore-styles": "5.0.1", + "image-webpack-loader": "3.0.0", + "istanbul": "1.0.0-alpha.2", + "jsdom": "9.8.3", + "json-loader": "0.5.4", + "mocha": "3.2.0", "mock-local-storage": "1.0.2", - "mock-socket": "~3.0.1", - "nock": "~8.0.0", + "mock-socket": "6.0.3", + "nock": "9.0.2", "postcss-import": "8.1.0", - "postcss-loader": "~1.1.1", - "postcss-nested": "~1.0.0", - "postcss-simple-vars": "~3.0.0", - "progress": "~1.1.8", - "raw-loader": "~0.5.1", - "react-addons-perf": "~15.3.2", - "react-addons-test-utils": "~15.3.2", - "react-dom": "~15.3.2", - "react-hot-loader": "~3.0.0-beta.6", - "rucksack-css": "~0.8.6", - "sinon": "~1.17.4", - "sinon-as-promised": "~4.0.2", - "sinon-chai": "~2.8.0", - "style-loader": "~0.13.0", - "url-loader": "~0.5.7", - "webpack": "~2.1.0-beta.27", - "webpack-dev-middleware": "~1.8.4", + "postcss-loader": "1.1.1", + "postcss-nested": "1.0.0", + "postcss-simple-vars": "3.0.0", + "progress": "1.1.8", + "raw-loader": "0.5.1", + "react-addons-perf": "15.4.1", + "react-addons-test-utils": "15.4.1", + "react-hot-loader": "3.0.0-beta.6", + "rucksack-css": "0.9.1", + "sinon": "1.17.6", + "sinon-as-promised": "4.0.2", + "sinon-chai": "2.8.0", + "style-loader": "0.13.1", + "url-loader": "0.5.7", + "webpack": "2.1.0-beta.27", + "webpack-dev-middleware": "1.8.4", "webpack-error-notification": "0.1.6", - "webpack-hot-middleware": "~2.13.2", - "websocket": "~1.0.23" + "webpack-hot-middleware": "2.13.2", + "websocket": "1.0.23" }, "dependencies": { - "bignumber.js": "~2.3.0", + "bignumber.js": "3.0.1", "blockies": "0.0.2", - "brace": "~0.9.0", - "bytes": "~2.4.0", - "chart.js": "~2.3.0", - "es6-error": "~4.0.0", - "es6-promise": "~3.2.1", - "ethereumjs-tx": "~1.1.2", - "eventemitter3": "~2.0.2", - "file-saver": "~1.3.3", - "format-json": "~1.0.3", - "format-number": "~2.0.1", - "geopattern": "~1.2.3", - "isomorphic-fetch": "~2.2.1", - "js-sha3": "~0.5.2", - "lodash": "~4.11.1", - "marked": "~0.3.6", - "material-ui": "0.16.1", - "material-ui-chip-input": "~0.8.0", - "mobx": "~2.6.1", - "mobx-react": "~3.5.8", - "mobx-react-devtools": "~4.2.9", - "moment": "~2.14.1", - "phoneformat.js": "~1.0.3", - "qs": "~6.3.0", - "react": "~15.3.2", - "react-ace": "~4.0.0", - "react-addons-css-transition-group": "~15.3.2", - "react-chartjs-2": "~1.5.0", - "react-copy-to-clipboard": "~4.2.3", - "react-dom": "~15.3.2", - "react-dropzone": "~3.7.3", - "react-redux": "~4.4.5", - "react-router": "~2.6.1", - "react-router-redux": "~4.0.5", - "react-tap-event-plugin": "~1.0.0", - "react-tooltip": "~2.0.3", - "recharts": "~0.15.2", - "redux": "~3.5.2", - "redux-actions": "~0.10.1", - "redux-thunk": "~2.1.0", - "rlp": "~2.0.0", - "scryptsy": "~2.0.0", + "brace": "0.9.0", + "bytes": "2.4.0", + "es6-error": "4.0.0", + "es6-promise": "4.0.5", + "ethereumjs-tx": "1.1.4", + "eventemitter3": "2.0.2", + "file-saver": "1.3.3", + "format-json": "1.0.3", + "format-number": "2.0.1", + "geopattern": "1.2.3", + "isomorphic-fetch": "2.2.1", + "js-sha3": "0.5.5", + "lodash": "4.17.2", + "marked": "0.3.6", + "material-ui": "0.16.4", + "material-ui-chip-input": "0.11.1", + "mobx": "2.6.4", + "mobx-react": "4.0.3", + "mobx-react-devtools": "4.2.10", + "moment": "2.17.0", + "phoneformat.js": "1.0.3", + "qs": "6.3.0", + "react": "15.4.1", + "react-ace": "4.1.0", + "react-addons-css-transition-group": "15.4.1", + "react-copy-to-clipboard": "4.2.3", + "react-dom": "15.4.1", + "react-dropzone": "3.7.3", + "react-redux": "4.4.6", + "react-router": "3.0.0", + "react-router-redux": "4.0.7", + "react-tap-event-plugin": "2.0.1", + "react-tooltip": "3.2.2", + "recharts": "0.15.2", + "redux": "3.6.0", + "redux-actions": "1.1.0", + "redux-thunk": "2.1.0", + "rlp": "2.0.0", + "scryptsy": "2.0.0", "solc": "ngotchac/solc-js", - "store": "~1.3.20", - "utf8": "~2.1.1", - "valid-url": "~1.0.9", - "validator": "~5.7.0", - "web3": "~0.17.0-beta", - "whatwg-fetch": "~1.0.0", - "worker-loader": "~0.7.1" + "store": "1.3.20", + "utf8": "2.1.2", + "valid-url": "1.0.9", + "validator": "6.2.0", + "web3": "0.17.0-beta", + "whatwg-fetch": "2.0.1", + "worker-loader": "0.7.1" } } diff --git a/js/src/abi/util/slice.js b/js/src/abi/util/slice.js index 417efea54..f4bdf38e2 100644 --- a/js/src/abi/util/slice.js +++ b/js/src/abi/util/slice.js @@ -27,9 +27,5 @@ export function sliceData (_data) { data = padAddress(''); } - if (data.length % 64) { - throw new Error(`Invalid data length (not mod 64) passed to sliceData, ${data}, % 64 == ${data.length % 64}`); - } - return data.match(/.{1,64}/g); } diff --git a/js/src/abi/util/slice.spec.js b/js/src/abi/util/slice.spec.js index 92608c590..d653c6901 100644 --- a/js/src/abi/util/slice.spec.js +++ b/js/src/abi/util/slice.spec.js @@ -21,10 +21,6 @@ describe('abi/util/slice', () => { const slice1 = '131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b'; const slice2 = '2124768576358735263578356373526387638357635873563586353756358763'; - it('throws an error on mod 64 != 0', () => { - expect(() => sliceData('123')).to.throw(/sliceData/); - }); - it('returns an empty array when length === 0', () => { expect(sliceData('')).to.deep.equal([]); }); diff --git a/js/src/api/contract/contract.js b/js/src/api/contract/contract.js index c1ba8498d..28bad8a3b 100644 --- a/js/src/api/contract/contract.js +++ b/js/src/api/contract/contract.js @@ -240,9 +240,29 @@ export default class Contract { return this.unsubscribe(subscriptionId); }; + event.getAllLogs = (options = {}) => { + return this.getAllLogs(event); + }; + return event; } + getAllLogs (event, _options) { + // Options as first parameter + if (!_options && event && event.topics) { + return this.getAllLogs(null, event); + } + + const options = this._getFilterOptions(event, _options); + return this._api.eth + .getLogs({ + fromBlock: 0, + toBlock: 'latest', + ...options + }) + .then((logs) => this.parseEventLogs(logs)); + } + _findEvent (eventName = null) { const event = eventName ? this._events.find((evt) => evt.name === eventName) @@ -256,7 +276,7 @@ export default class Contract { return event; } - _createEthFilter (event = null, _options) { + _getFilterOptions (event = null, _options = {}) { const optionTopics = _options.topics || []; const signature = event && event.signature || null; @@ -271,6 +291,11 @@ export default class Contract { topics }); + return options; + } + + _createEthFilter (event = null, _options) { + const options = this._getFilterOptions(event, _options); return this._api.eth.newFilter(options); } diff --git a/js/src/api/rpc/eth/eth.js b/js/src/api/rpc/eth/eth.js index 43f8025e1..8148f9385 100644 --- a/js/src/api/rpc/eth/eth.js +++ b/js/src/api/rpc/eth/eth.js @@ -146,7 +146,8 @@ export default class Eth { getLogs (options) { return this._transport - .execute('eth_getLogs', inFilter(options)); + .execute('eth_getLogs', inFilter(options)) + .then((logs) => logs.map(outLog)); } getLogsEx (options) { diff --git a/js/src/api/util/format.js b/js/src/api/util/format.js index 7f60357cd..d8cf74a8f 100644 --- a/js/src/api/util/format.js +++ b/js/src/api/util/format.js @@ -32,6 +32,10 @@ export function hex2Ascii (_hex) { return str; } +export function bytesToAscii (bytes) { + return bytes.map((b) => String.fromCharCode(b % 512)).join(''); +} + export function asciiToHex (string) { return '0x' + string.split('').map((s) => s.charCodeAt(0).toString(16)).join(''); } diff --git a/js/src/contracts/badgereg.js b/js/src/contracts/badgereg.js index f8dbefa78..45760b277 100644 --- a/js/src/contracts/badgereg.js +++ b/js/src/contracts/badgereg.js @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -import { bytesToHex, hex2Ascii } from '../api/util/format'; +import { bytesToHex, hex2Ascii } from '~/api/util/format'; import ABI from './abi/certifier.json'; diff --git a/js/src/dapps/basiccoin.js b/js/src/dapps/basiccoin.js index a64afa0b9..eb3213c79 100644 --- a/js/src/dapps/basiccoin.js +++ b/js/src/dapps/basiccoin.js @@ -16,8 +16,7 @@ import ReactDOM from 'react-dom'; import React from 'react'; -import { createHashHistory } from 'history'; -import { Redirect, Router, Route, useRouterHistory } from 'react-router'; +import { Redirect, Router, Route, hashHistory } from 'react-router'; import injectTapEventPlugin from 'react-tap-event-plugin'; injectTapEventPlugin(); @@ -27,14 +26,12 @@ import Application from './basiccoin/Application'; import Overview from './basiccoin/Overview'; import Transfer from './basiccoin/Transfer'; -const routerHistory = useRouterHistory(createHashHistory)({}); - import '../../assets/fonts/Roboto/font.css'; import '../../assets/fonts/RobotoMono/font.css'; import './style.css'; ReactDOM.render( - + diff --git a/js/src/dapps/basiccoin/Transfer/Send/send.js b/js/src/dapps/basiccoin/Transfer/Send/send.js index a9c05a228..f10807b2e 100644 --- a/js/src/dapps/basiccoin/Transfer/Send/send.js +++ b/js/src/dapps/basiccoin/Transfer/Send/send.js @@ -17,7 +17,7 @@ import BigNumber from 'bignumber.js'; import React, { Component, PropTypes } from 'react'; -import { eip20 } from '../../../../contracts/abi'; +import { eip20 } from '~/contracts/abi'; import { api } from '../../parity'; import { loadBalances } from '../../services'; diff --git a/js/src/dapps/basiccoin/services.js b/js/src/dapps/basiccoin/services.js index 3dd5202a7..f76b7fb61 100644 --- a/js/src/dapps/basiccoin/services.js +++ b/js/src/dapps/basiccoin/services.js @@ -16,7 +16,7 @@ import BigNumber from 'bignumber.js'; -import * as abis from '../../contracts/abi'; +import * as abis from '~/contracts/abi'; import { api } from './parity'; let managerInstance; diff --git a/js/src/dapps/dappreg/dappsStore.js b/js/src/dapps/dappreg/dappsStore.js index 4baf7337c..382f5cdc4 100644 --- a/js/src/dapps/dappreg/dappsStore.js +++ b/js/src/dapps/dappreg/dappsStore.js @@ -17,8 +17,8 @@ import BigNumber from 'bignumber.js'; import { action, computed, observable, transaction } from 'mobx'; -import * as abis from '../../contracts/abi'; -import builtins from '../../views/Dapps/builtin.json'; +import * as abis from '~/contracts/abi'; +import builtins from '~/views/Dapps/builtin.json'; import { api } from './parity'; diff --git a/js/src/dapps/githubhint/services.js b/js/src/dapps/githubhint/services.js index d4f7fc6b2..fc889b7f6 100644 --- a/js/src/dapps/githubhint/services.js +++ b/js/src/dapps/githubhint/services.js @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -import * as abis from '../../contracts/abi'; +import * as abis from '~/contracts/abi'; import { api } from './parity'; export function attachInterface () { diff --git a/js/src/dapps/index.ejs b/js/src/dapps/index.ejs index fa65c78bf..aab652fa6 100644 --- a/js/src/dapps/index.ejs +++ b/js/src/dapps/index.ejs @@ -8,7 +8,7 @@