Merge branch 'master' into auth-round

This commit is contained in:
keorn 2016-11-04 11:35:17 +00:00
commit 255ec0c139
97 changed files with 1127 additions and 550 deletions

2
.gitignore vendored
View File

@ -30,3 +30,5 @@
# Build artifacts # Build artifacts
out/ out/
.vscode

View File

@ -1,4 +1,6 @@
stages: stages:
- test
- js-build
- build - build
variables: variables:
GIT_DEPTH: "3" GIT_DEPTH: "3"
@ -7,13 +9,13 @@ variables:
RUSTFLAGS: "" RUSTFLAGS: ""
CARGOFLAGS: "" CARGOFLAGS: ""
cache: cache:
key: "$CI_BUILD_NAME/$CI_BUILD_REF_NAME" key: "$CI_BUILD_REF_NAME"
untracked: true untracked: true
linux-stable: linux-stable:
stage: build stage: build
image: ethcore/rust:stable image: ethcore/rust:stable
only: only:
- master - $NIGHTLY
- beta - beta
- tags - tags
- stable - stable
@ -43,7 +45,7 @@ linux-stable-14.04:
stage: build stage: build
image: ethcore/rust-14.04:latest image: ethcore/rust-14.04:latest
only: only:
- master - $NIGHTLY
- beta - beta
- tags - tags
- stable - stable
@ -73,7 +75,7 @@ linux-beta:
stage: build stage: build
image: ethcore/rust:beta image: ethcore/rust:beta
only: only:
- master - $NIGHTLY
- beta - beta
- tags - tags
- stable - stable
@ -92,7 +94,7 @@ linux-nightly:
stage: build stage: build
image: ethcore/rust:nightly image: ethcore/rust:nightly
only: only:
- master - $NIGHTLY
- beta - beta
- tags - tags
- stable - stable
@ -111,7 +113,7 @@ linux-centos:
stage: build stage: build
image: ethcore/rust-centos:latest image: ethcore/rust-centos:latest
only: only:
- master - $NIGHTLY
- beta - beta
- tags - tags
- stable - stable
@ -136,6 +138,7 @@ linux-armv7:
stage: build stage: build
image: ethcore/rust-armv7:latest image: ethcore/rust-armv7:latest
only: only:
- $NIGHTLY
- beta - beta
- tags - tags
- stable - stable
@ -175,6 +178,7 @@ linux-arm:
stage: build stage: build
image: ethcore/rust-arm:latest image: ethcore/rust-arm:latest
only: only:
- $NIGHTLY
- beta - beta
- tags - tags
- stable - stable
@ -214,6 +218,7 @@ linux-armv6:
stage: build stage: build
image: ethcore/rust-armv6:latest image: ethcore/rust-armv6:latest
only: only:
- $NIGHTLY
- beta - beta
- tags - tags
- stable - stable
@ -246,6 +251,7 @@ linux-aarch64:
stage: build stage: build
image: ethcore/rust-aarch64:latest image: ethcore/rust-aarch64:latest
only: only:
- $NIGHTLY
- beta - beta
- tags - tags
- stable - stable
@ -284,6 +290,7 @@ linux-aarch64:
darwin: darwin:
stage: build stage: build
only: only:
- $NIGHTLY
- beta - beta
- tags - tags
- stable - stable
@ -304,6 +311,7 @@ darwin:
windows: windows:
stage: build stage: build
only: only:
- $NIGHTLY
- beta - beta
- tags - tags
- stable - stable
@ -350,49 +358,51 @@ windows:
- target/release/parity.pdb - target/release/parity.pdb
- nsis/InstallParity.exe - nsis/InstallParity.exe
name: "x86_64-pc-windows-msvc_parity" name: "x86_64-pc-windows-msvc_parity"
#test-darwin: test-darwin:
# stage: build stage: test
# before_script: only:
# - git submodule update --init --recursive - beta
# script: - tags
# - export RUST_BACKTRACE=1 - stable
# - ./test.sh $CARGOFLAGS --no-release
# tags:
# - osx
#test-windows:
# stage: build
# before_script:
# - git submodule update --init --recursive
# script:
# - set RUST_BACKTRACE=1
# - cargo test --features json-tests -p rlp -p ethash -p ethcore -p ethcore-bigint -p ethcore-dapps -p ethcore-rpc -p ethcore-signer -p ethcore-util -p ethcore-network -p ethcore-io -p ethkey -p ethstore -p ethsync -p ethcore-ipc -p ethcore-ipc-tests -p ethcore-ipc-nano -p parity %CARGOFLAGS% --verbose --release
# tags:
# - rust-windows
# allow_failure: true
test-linux:
stage: build
before_script: before_script:
- git submodule update --init --recursive - git submodule update --init --recursive
script: script:
- export RUST_BACKTRACE=1 - export RUST_BACKTRACE=1
- ./test.sh $CARGOFLAGS --no-release - ./test.sh $CARGOFLAGS --no-release
tags: tags:
- rust-test - osx
js-release: test-windows:
stage: build stage: test
image: ethcore/javascript:latest
only: only:
- master - beta
- tags
- stable
before_script: before_script:
- ./js/scripts/install-deps.sh - git submodule update --init --recursive
script: script:
- ./js/scripts/build.sh - set RUST_BACKTRACE=1
- ./js/scripts/release.sh - cargo test --features json-tests -p rlp -p ethash -p ethcore -p ethcore-bigint -p ethcore-dapps -p ethcore-rpc -p ethcore-signer -p ethcore-util -p ethcore-network -p ethcore-io -p ethkey -p ethstore -p ethsync -p ethcore-ipc -p ethcore-ipc-tests -p ethcore-ipc-nano -p parity %CARGOFLAGS% --verbose --release
tags: tags:
- javascript - rust-windows
allow_failure: true
test-rust-stable:
stage: test
image: ethcore/rust:stable
before_script:
- git submodule update --init --recursive
- export JS_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF_NAME $(git merge-base $CI_BUILD_REF_NAME master) | grep \.js | wc -l)
- echo $JS_FILES_MODIFIED
- if [ -z $JS_FILES_MODIFIED ]; then echo "skip js test"; fi
script:
- export RUST_BACKTRACE=1
- echo $JS_FILES_MODIFIED
- if [ -z $JS_FILES_MODIFIED ]; then echo "skip js test"; else ./test.sh $CARGOFLAGS --no-release; fi
tags:
- rust
- rust-stable
js-tests: js-tests:
stage: build stage: test
image: ethcore/javascript:latest image: ethcore/rust:stable
before_script: before_script:
- ./js/scripts/install-deps.sh - ./js/scripts/install-deps.sh
script: script:
@ -401,3 +411,18 @@ js-tests:
- ./js/scripts/build.sh - ./js/scripts/build.sh
tags: tags:
- javascript-test - javascript-test
js-release:
stage: js-build
only:
- master
- beta
- stable
- tags
image: ethcore/rust:stable
before_script:
- ./js/scripts/install-deps.sh
script:
- ./js/scripts/build.sh
- ./js/scripts/release.sh
tags:
- javascript

12
Cargo.lock generated
View File

@ -312,7 +312,7 @@ dependencies = [
[[package]] [[package]]
name = "ethcore-bigint" name = "ethcore-bigint"
version = "0.1.1" version = "0.1.2"
dependencies = [ dependencies = [
"heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 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)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
@ -549,7 +549,7 @@ dependencies = [
"elastic-array 0.6.0 (git+https://github.com/ethcore/elastic-array)", "elastic-array 0.6.0 (git+https://github.com/ethcore/elastic-array)",
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)", "eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)",
"ethcore-bigint 0.1.1", "ethcore-bigint 0.1.2",
"ethcore-bloom-journal 0.1.0", "ethcore-bloom-journal 0.1.0",
"ethcore-devtools 1.4.0", "ethcore-devtools 1.4.0",
"heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -580,7 +580,7 @@ name = "ethcrypto"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)", "eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)",
"ethcore-bigint 0.1.1", "ethcore-bigint 0.1.2",
"ethkey 0.2.0", "ethkey 0.2.0",
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -603,7 +603,7 @@ version = "0.2.0"
dependencies = [ dependencies = [
"docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.6.80 (registry+https://github.com/rust-lang/crates.io-index)",
"eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)", "eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)",
"ethcore-bigint 0.1.1", "ethcore-bigint 0.1.2",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1249,7 +1249,7 @@ dependencies = [
[[package]] [[package]]
name = "parity-ui-precompiled" name = "parity-ui-precompiled"
version = "1.4.0" version = "1.4.0"
source = "git+https://github.com/ethcore/js-precompiled.git#f8bd7fa67e91daea3ac698ebcc447fae494802cb" source = "git+https://github.com/ethcore/js-precompiled.git#3a77750a2d29e2babb52bc4dfa5c40b2e26b97ce"
dependencies = [ dependencies = [
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1463,7 +1463,7 @@ name = "rlp"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"elastic-array 0.6.0 (git+https://github.com/ethcore/elastic-array)", "elastic-array 0.6.0 (git+https://github.com/ethcore/elastic-array)",
"ethcore-bigint 0.1.1", "ethcore-bigint 0.1.2",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
] ]

View File

@ -3,7 +3,7 @@
[![Join the chat at https://gitter.im/ethcore/parity.js](https://badges.gitter.im/ethcore/parity.js.svg)](https://gitter.im/ethcore/parity.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the chat at https://gitter.im/ethcore/parity.js](https://badges.gitter.im/ethcore/parity.js.svg)](https://gitter.im/ethcore/parity.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status][travis-image]][travis-url] [![Coverage Status][coveralls-image]][coveralls-url] [![Join the chat at https://gitter.im/ethcore/parity][gitter-image]][gitter-url] [![GPLv3][license-image]][license-url] [![Build Status][travis-image]][travis-url] [![build status](https://gitlab.ethcore.io/Mirrors/ethcore-parity/badges/master/build.svg)](https://gitlab.ethcore.io/Mirrors/ethcore-parity/commits/master) [![Coverage Status][coveralls-image]][coveralls-url] [![Join the chat at https://gitter.im/ethcore/parity][gitter-image]][gitter-url] [![GPLv3][license-image]][license-url]
[Internal Documentation][doc-url] [Internal Documentation][doc-url]
@ -57,6 +57,13 @@ We recommend installing Rust through [rustup](https://www.rustup.rs/). If you do
$ curl https://sh.rustup.rs -sSf | sh $ curl https://sh.rustup.rs -sSf | sh
``` ```
Parity also requires `gcc`, `g++` and `make` packages to be installed.
- OSX:
```bash
$ curl https://sh.rustup.rs -sSf | sh
```
`clang` and `make` are required. These come with Xcode command line tools or can be installed with homebrew.
- Windows - Windows
Make sure you have Visual Studio 2015 with C++ support installed. Next, download and run the rustup installer from Make sure you have Visual Studio 2015 with C++ support installed. Next, download and run the rustup installer from

View File

@ -11,7 +11,11 @@
"blockReward": "0x4563918244F40000", "blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"homesteadTransition": "0x118c30", "homesteadTransition": "0x118c30",
"eip150Transition": "0x2625a0" "eip150Transition": "0x2625a0",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
} }
} }
}, },

View File

@ -10,7 +10,11 @@
"blockReward": "0x4563918244F40000", "blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"homesteadTransition": "0x0", "homesteadTransition": "0x0",
"eip150Transition": "0x0" "eip150Transition": "0x0",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
} }
} }
}, },

View File

@ -0,0 +1,47 @@
{
"name": "Homestead (Test)",
"engine": {
"Ethash": {
"params": {
"gasLimitBoundDivisor": "0x0400",
"minimumDifficulty": "0x020000",
"difficultyBoundDivisor": "0x0800",
"durationLimit": "0x0d",
"blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"homesteadTransition": "0x0",
"eip150Transition": "0x0",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x0",
"eip161abcTransition": "0x0",
"eip161dTransition": "0x0"
}
}
},
"params": {
"accountStartNonce": "0x00",
"maximumExtraDataSize": "0x20",
"minGasLimit": "0x1388",
"networkID" : "0x1"
},
"genesis": {
"seal": {
"ethereum": {
"nonce": "0x0000000000000042",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty": "0x400000000",
"author": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"gasLimit": "0x1388"
},
"accounts": {
"0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
"0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
"0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }
}
}

View File

@ -15,7 +15,11 @@
"difficultyHardforkTransition": "0x59d9", "difficultyHardforkTransition": "0x59d9",
"difficultyHardforkBoundDivisor": "0x0200", "difficultyHardforkBoundDivisor": "0x0200",
"bombDefuseTransition": "0x30d40", "bombDefuseTransition": "0x30d40",
"eip150Transition": "0x7fffffffffffffff" "eip150Transition": "0x7fffffffffffffff",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
} }
} }
}, },

View File

@ -130,7 +130,11 @@
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413", "0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a" "0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
], ],
"eip150Transition": "0x259518" "eip150Transition": "0x259518",
"eip155Transition": 2642462,
"eip160Transition": 2642462,
"eip161abcTransition": 2642462,
"eip161dTransition": 2642462
} }
} }
}, },

View File

@ -130,7 +130,11 @@
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413", "0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a" "0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
], ],
"eip150Transition": "0x7fffffffffffffff" "eip150Transition": "0x7fffffffffffffff",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
} }
} }
}, },

View File

@ -10,7 +10,11 @@
"blockReward": "0x4563918244F40000", "blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"homesteadTransition": "0x7fffffffffffffff", "homesteadTransition": "0x7fffffffffffffff",
"eip150Transition": "0x7fffffffffffffff" "eip150Transition": "0x7fffffffffffffff",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
} }
} }
}, },

View File

@ -10,7 +10,11 @@
"blockReward": "0x4563918244F40000", "blockReward": "0x4563918244F40000",
"registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b", "registrar" : "0xc6d9d2cd449a754c494264e1809c50e34d64562b",
"homesteadTransition": "0x0", "homesteadTransition": "0x0",
"eip150Transition": "0x7fffffffffffffff" "eip150Transition": "0x7fffffffffffffff",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
} }
} }
}, },

View File

@ -10,7 +10,11 @@
"blockReward": "0x4563918244F40000", "blockReward": "0x4563918244F40000",
"registrar": "0x52dff57a8a1532e6afb3dc07e2af58bb9eb05b3d", "registrar": "0x52dff57a8a1532e6afb3dc07e2af58bb9eb05b3d",
"homesteadTransition": "0x789b0", "homesteadTransition": "0x789b0",
"eip150Transition": "0x1b34d8" "eip150Transition": "0x1b34d8",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
} }
} }
}, },

View File

@ -10,7 +10,11 @@
"blockReward": "0x14D1120D7B160000", "blockReward": "0x14D1120D7B160000",
"registrar": "5e70c0bbcd5636e0f9f9316e9f8633feb64d4050", "registrar": "5e70c0bbcd5636e0f9f9316e9f8633feb64d4050",
"homesteadTransition": "0x7fffffffffffffff", "homesteadTransition": "0x7fffffffffffffff",
"eip150Transition": "0x7fffffffffffffff" "eip150Transition": "0x7fffffffffffffff",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
} }
} }
}, },

@ -1 +1 @@
Subproject commit 97066e40ccd061f727deb5cd860e4d9135aa2551 Subproject commit 853333e7da312775fb8f32f2c2771b8578cd0d79

View File

@ -130,7 +130,11 @@
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413", "0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a" "0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
], ],
"eip150Transition": "0xa" "eip150Transition": "0xa",
"eip155Transition": "0x7fffffffffffffff",
"eip160Transition": "0x7fffffffffffffff",
"eip161abcTransition": "0x7fffffffffffffff",
"eip161dTransition": "0x7fffffffffffffff"
} }
} }
}, },

View File

@ -1468,7 +1468,7 @@ mod tests {
action: Action::Create, action: Action::Create,
value: 100.into(), value: 100.into(),
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(), data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
let b1a = canon_chain let b1a = canon_chain
@ -1532,7 +1532,7 @@ mod tests {
action: Action::Create, action: Action::Create,
value: 100.into(), value: 100.into(),
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(), data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
let t2 = Transaction { let t2 = Transaction {
nonce: 1.into(), nonce: 1.into(),
@ -1541,7 +1541,7 @@ mod tests {
action: Action::Create, action: Action::Create,
value: 100.into(), value: 100.into(),
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(), data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
let t3 = Transaction { let t3 = Transaction {
nonce: 2.into(), nonce: 2.into(),
@ -1550,7 +1550,7 @@ mod tests {
action: Action::Create, action: Action::Create,
value: 100.into(), value: 100.into(),
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(), data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
let b1a = canon_chain let b1a = canon_chain
.with_transaction(t1.clone()) .with_transaction(t1.clone())
@ -1856,7 +1856,7 @@ mod tests {
action: Action::Create, action: Action::Create,
value: 101.into(), value: 101.into(),
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(), data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
let t2 = Transaction { let t2 = Transaction {
nonce: 0.into(), nonce: 0.into(),
gas_price: 0.into(), gas_price: 0.into(),
@ -1864,7 +1864,7 @@ mod tests {
action: Action::Create, action: Action::Create,
value: 102.into(), value: 102.into(),
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(), data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
let t3 = Transaction { let t3 = Transaction {
nonce: 0.into(), nonce: 0.into(),
gas_price: 0.into(), gas_price: 0.into(),
@ -1872,7 +1872,7 @@ mod tests {
action: Action::Create, action: Action::Create,
value: 103.into(), value: 103.into(),
data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(), data: "601080600c6000396000f3006000355415600957005b60203560003555".from_hex().unwrap(),
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
let tx_hash1 = t1.hash(); let tx_hash1 = t1.hash();
let tx_hash2 = t2.hash(); let tx_hash2 = t2.hash();
let tx_hash3 = t3.hash(); let tx_hash3 = t3.hash();

View File

@ -33,7 +33,7 @@ use io::*;
use views::{HeaderView, BodyView, BlockView}; use views::{HeaderView, BodyView, BlockView};
use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError}; use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult, Error as EthcoreError};
use header::BlockNumber; use header::BlockNumber;
use state::State; use state::{State, CleanupMode};
use spec::Spec; use spec::Spec;
use basic_types::Seal; use basic_types::Seal;
use engines::Engine; use engines::Engine;
@ -268,6 +268,22 @@ impl Client {
} }
} }
/// The env info as of the best block.
fn latest_env_info(&self) -> EnvInfo {
let header_data = self.best_block_header();
let view = HeaderView::new(&header_data);
EnvInfo {
number: view.number(),
author: view.author(),
timestamp: view.timestamp(),
difficulty: view.difficulty(),
last_hashes: self.build_last_hashes(view.hash()),
gas_used: U256::default(),
gas_limit: view.gas_limit(),
}
}
fn build_last_hashes(&self, parent_hash: H256) -> Arc<LastHashes> { fn build_last_hashes(&self, parent_hash: H256) -> Arc<LastHashes> {
{ {
let hashes = self.last_hashes.read(); let hashes = self.last_hashes.read();
@ -796,7 +812,7 @@ impl BlockChainClient for Client {
let needed_balance = t.value + t.gas * t.gas_price; let needed_balance = t.value + t.gas * t.gas_price;
if balance < needed_balance { if balance < needed_balance {
// give the sender a sufficient balance // give the sender a sufficient balance
state.add_balance(&sender, &(needed_balance - balance)); state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty);
} }
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false }; let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
let mut ret = try!(Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm).transact(t, options)); let mut ret = try!(Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm).transact(t, options));
@ -1014,7 +1030,9 @@ impl BlockChainClient for Client {
transaction_hash: transaction_hash.clone(), transaction_hash: transaction_hash.clone(),
transaction_index: transaction_index, transaction_index: transaction_index,
log_index: i log_index: i
}).collect() }).collect(),
log_bloom: receipt.log_bloom,
state_root: receipt.state_root,
}) })
}, },
_ => None _ => None
@ -1175,24 +1193,16 @@ impl BlockChainClient for Client {
fn pending_transactions(&self) -> Vec<SignedTransaction> { fn pending_transactions(&self) -> Vec<SignedTransaction> {
self.miner.pending_transactions(self.chain.read().best_block_number()) self.miner.pending_transactions(self.chain.read().best_block_number())
} }
fn signing_network_id(&self) -> Option<u8> {
self.engine.signing_network_id(&self.latest_env_info())
}
} }
impl MiningBlockChainClient for Client { impl MiningBlockChainClient for Client {
fn latest_schedule(&self) -> Schedule { fn latest_schedule(&self) -> Schedule {
let header_data = self.best_block_header(); self.engine.schedule(&self.latest_env_info())
let view = HeaderView::new(&header_data);
let env_info = EnvInfo {
number: view.number(),
author: view.author(),
timestamp: view.timestamp(),
difficulty: view.difficulty(),
last_hashes: self.build_last_hashes(view.hash()),
gas_used: U256::default(),
gas_limit: view.gas_limit(),
};
self.engine.schedule(&env_info)
} }
fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock { fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock {

View File

@ -237,7 +237,7 @@ impl TestBlockChainClient {
gas_price: U256::one(), gas_price: U256::one(),
nonce: U256::zero() nonce: U256::zero()
}; };
let signed_tx = tx.sign(keypair.secret()); let signed_tx = tx.sign(keypair.secret(), None);
txs.append(&signed_tx); txs.append(&signed_tx);
txs.out() txs.out()
}, },
@ -303,7 +303,7 @@ impl TestBlockChainClient {
gas_price: U256::one(), gas_price: U256::one(),
nonce: U256::zero() nonce: U256::zero()
}; };
let signed_tx = tx.sign(keypair.secret()); let signed_tx = tx.sign(keypair.secret(), None);
self.set_balance(signed_tx.sender().unwrap(), 10_000_000.into()); self.set_balance(signed_tx.sender().unwrap(), 10_000_000.into());
let res = self.miner.import_external_transactions(self, vec![signed_tx]); let res = self.miner.import_external_transactions(self, vec![signed_tx]);
let res = res.into_iter().next().unwrap().expect("Successful import"); let res = res.into_iter().next().unwrap().expect("Successful import");
@ -324,7 +324,7 @@ pub fn get_temp_state_db() -> GuardedTempResult<StateDB> {
impl MiningBlockChainClient for TestBlockChainClient { impl MiningBlockChainClient for TestBlockChainClient {
fn latest_schedule(&self) -> Schedule { fn latest_schedule(&self) -> Schedule {
Schedule::new_homestead_gas_fix() Schedule::new_post_eip150(true, true, true)
} }
fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock { fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock {
@ -643,6 +643,8 @@ impl BlockChainClient for TestBlockChainClient {
self.miner.pending_transactions(self.chain_info().best_block_number) self.miner.pending_transactions(self.chain_info().best_block_number)
} }
fn signing_network_id(&self) -> Option<u8> { None }
fn mode(&self) -> Mode { Mode::Active } fn mode(&self) -> Mode { Mode::Active }
fn set_mode(&self, _: Mode) { unimplemented!(); } fn set_mode(&self, _: Mode) { unimplemented!(); }

View File

@ -227,8 +227,13 @@ pub trait BlockChainClient : Sync + Send {
Histogram::new(corpus, bucket_number) Histogram::new(corpus, bucket_number)
} }
/// Get the preferred network ID to sign on
fn signing_network_id(&self) -> Option<u8>;
/// Get the mode.
fn mode(&self) -> Mode; fn mode(&self) -> Mode;
/// Set the mode.
fn set_mode(&self, mode: Mode); fn set_mode(&self, mode: Mode);
} }

View File

@ -112,6 +112,9 @@ pub trait Engine : Sync + Send {
/// Verify a particular transaction is valid. /// Verify a particular transaction is valid.
fn verify_transaction(&self, _t: &SignedTransaction, _header: &Header) -> Result<(), Error> { Ok(()) } 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<u8> { None }
/// Verify the seal of a block. This is an auxilliary method that actually just calls other `verify_` methods /// 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 /// to get the job done. By default it must pass `verify_basic` and `verify_block_unordered`. If more or fewer
/// methods are needed for an Engine, this may be overridden. /// methods are needed for an Engine, this may be overridden.

View File

@ -76,6 +76,8 @@ pub enum TransactionError {
RecipientBanned, RecipientBanned,
/// Contract creation code is banned. /// Contract creation code is banned.
CodeBanned, CodeBanned,
/// Invalid network ID given.
InvalidNetworkId,
} }
impl fmt::Display for TransactionError { impl fmt::Display for TransactionError {
@ -99,6 +101,7 @@ impl fmt::Display for TransactionError {
SenderBanned => "Sender is temporarily banned.".into(), SenderBanned => "Sender is temporarily banned.".into(),
RecipientBanned => "Recipient is temporarily banned.".into(), RecipientBanned => "Recipient is temporarily banned.".into(),
CodeBanned => "Contract code is temporarily banned.".into(), CodeBanned => "Contract code is temporarily banned.".into(),
InvalidNetworkId => "Transaction of this network ID is not allowed on this chain.".into(),
}; };
f.write_fmt(format_args!("Transaction error ({})", msg)) f.write_fmt(format_args!("Transaction error ({})", msg))

View File

@ -19,8 +19,9 @@ use util::*;
use block::*; use block::*;
use builtin::Builtin; use builtin::Builtin;
use env_info::EnvInfo; use env_info::EnvInfo;
use error::{BlockError, Error}; use error::{BlockError, TransactionError, Error};
use header::Header; use header::Header;
use state::CleanupMode;
use spec::CommonParams; use spec::CommonParams;
use transaction::SignedTransaction; use transaction::SignedTransaction;
use engines::Engine; use engines::Engine;
@ -59,8 +60,16 @@ pub struct EthashParams {
pub difficulty_hardfork_bound_divisor: U256, pub difficulty_hardfork_bound_divisor: U256,
/// Block on which there is no additional difficulty from the exponential bomb. /// Block on which there is no additional difficulty from the exponential bomb.
pub bomb_defuse_transition: u64, pub bomb_defuse_transition: u64,
/// Bad gas transition block number. /// Number of first block where EIP-150 rules begin.
pub eip150_transition: u64, pub eip150_transition: u64,
/// Number of first block where EIP-155 rules begin.
pub eip155_transition: u64,
/// Number of first block where EIP-160 rules begin.
pub eip160_transition: u64,
/// Number of first block where EIP-161.abc begin.
pub eip161abc_transition: u64,
/// Number of first block where EIP-161.d begins.
pub eip161d_transition: u64,
} }
impl From<ethjson::spec::EthashParams> for EthashParams { impl From<ethjson::spec::EthashParams> for EthashParams {
@ -81,6 +90,10 @@ impl From<ethjson::spec::EthashParams> for EthashParams {
difficulty_hardfork_bound_divisor: p.difficulty_hardfork_bound_divisor.map_or(p.difficulty_bound_divisor.into(), Into::into), difficulty_hardfork_bound_divisor: p.difficulty_hardfork_bound_divisor.map_or(p.difficulty_bound_divisor.into(), Into::into),
bomb_defuse_transition: p.bomb_defuse_transition.map_or(0x7fffffffffffffff, Into::into), bomb_defuse_transition: p.bomb_defuse_transition.map_or(0x7fffffffffffffff, Into::into),
eip150_transition: p.eip150_transition.map_or(0, Into::into), eip150_transition: p.eip150_transition.map_or(0, Into::into),
eip155_transition: p.eip155_transition.map_or(0, Into::into),
eip160_transition: p.eip160_transition.map_or(0, Into::into),
eip161abc_transition: p.eip161abc_transition.map_or(0, Into::into),
eip161d_transition: p.eip161d_transition.map_or(0x7fffffffffffffff, Into::into),
} }
} }
} }
@ -132,7 +145,19 @@ impl Engine for Ethash {
} else if env_info.number < self.ethash_params.eip150_transition { } else if env_info.number < self.ethash_params.eip150_transition {
Schedule::new_homestead() Schedule::new_homestead()
} else { } else {
Schedule::new_homestead_gas_fix() Schedule::new_post_eip150(
env_info.number >= self.ethash_params.eip160_transition,
env_info.number >= self.ethash_params.eip161abc_transition,
env_info.number >= self.ethash_params.eip161d_transition
)
}
}
fn signing_network_id(&self, env_info: &EnvInfo) -> Option<u8> {
if env_info.number >= self.ethash_params.eip155_transition && self.params().network_id < 127 {
Some(self.params().network_id as u8)
} else {
None
} }
} }
@ -169,7 +194,7 @@ impl Engine for Ethash {
let mut state = block.fields_mut().state; let mut state = block.fields_mut().state;
for child in &self.ethash_params.dao_hardfork_accounts { for child in &self.ethash_params.dao_hardfork_accounts {
let b = state.balance(child); let b = state.balance(child);
state.transfer_balance(child, &self.ethash_params.dao_hardfork_beneficiary, &b); state.transfer_balance(child, &self.ethash_params.dao_hardfork_beneficiary, &b, CleanupMode::NoEmpty);
} }
// } // }
} }
@ -182,12 +207,12 @@ impl Engine for Ethash {
let fields = block.fields_mut(); let fields = block.fields_mut();
// Bestow block reward // Bestow block reward
fields.state.add_balance(fields.header.author(), &(reward + reward / U256::from(32) * U256::from(fields.uncles.len()))); fields.state.add_balance(fields.header.author(), &(reward + reward / U256::from(32) * U256::from(fields.uncles.len())), CleanupMode::NoEmpty);
// Bestow uncle rewards // Bestow uncle rewards
let current_number = fields.header.number(); let current_number = fields.header.number();
for u in fields.uncles.iter() { for u in fields.uncles.iter() {
fields.state.add_balance(u.author(), &(reward * U256::from(8 + u.number() - current_number) / U256::from(8))); fields.state.add_balance(u.author(), &(reward * U256::from(8 + u.number() - current_number) / U256::from(8)), CleanupMode::NoEmpty);
} }
// Commit state so that we can actually figure out the state root. // Commit state so that we can actually figure out the state root.
@ -277,6 +302,13 @@ impl Engine for Ethash {
if header.number() >= self.ethash_params.homestead_transition { if header.number() >= self.ethash_params.homestead_transition {
try!(t.check_low_s()); try!(t.check_low_s());
} }
if let Some(n) = t.network_id() {
if header.number() < self.ethash_params.eip155_transition || n as usize != self.params().network_id {
return Err(TransactionError::InvalidNetworkId.into())
}
}
Ok(()) Ok(())
} }

View File

@ -54,6 +54,9 @@ pub fn new_homestead_test() -> Spec { load(include_bytes!("../../res/ethereum/ho
/// Create a new Homestead-EIP150 chain spec as though it never changed from Homestead/Frontier. /// Create a new Homestead-EIP150 chain spec as though it never changed from Homestead/Frontier.
pub fn new_eip150_test() -> Spec { load(include_bytes!("../../res/ethereum/eip150_test.json")) } pub fn new_eip150_test() -> Spec { load(include_bytes!("../../res/ethereum/eip150_test.json")) }
/// Create a new Homestead-EIP150 chain spec as though it never changed from Homestead/Frontier.
pub fn new_eip161_test() -> Spec { load(include_bytes!("../../res/ethereum/eip161_test.json")) }
/// Create a new Frontier/Homestead/DAO chain spec with transition points at #5 and #8. /// Create a new Frontier/Homestead/DAO chain spec with transition points at #5 and #8.
pub fn new_transition_test() -> Spec { load(include_bytes!("../../res/ethereum/transition_test.json")) } pub fn new_transition_test() -> Spec { load(include_bytes!("../../res/ethereum/transition_test.json")) }

View File

@ -52,6 +52,12 @@ pub trait Ext {
/// Determine whether an account exists. /// Determine whether an account exists.
fn exists(&self, address: &Address) -> bool; fn exists(&self, address: &Address) -> bool;
/// Determine whether an account exists and is not null (zero balance/nonce, no code).
fn exists_and_not_null(&self, address: &Address) -> bool;
/// Balance of the origin account.
fn origin_balance(&self) -> U256;
/// Returns address balance. /// Returns address balance.
fn balance(&self, address: &Address) -> U256; fn balance(&self, address: &Address) -> U256;

View File

@ -146,8 +146,13 @@ impl<Gas: CostType> Gasometer<Gas> {
instructions::SUICIDE => { instructions::SUICIDE => {
let mut gas = Gas::from(schedule.suicide_gas); let mut gas = Gas::from(schedule.suicide_gas);
let is_value_transfer = !ext.origin_balance().is_zero();
let address = u256_to_address(stack.peek(0)); let address = u256_to_address(stack.peek(0));
if !ext.exists(&address) { if (
!schedule.no_empty && !ext.exists(&address)
) || (
schedule.no_empty && is_value_transfer && !ext.exists_and_not_null(&address)
) {
gas = overflowing!(gas.overflow_add(schedule.suicide_to_new_account_cost.into())); gas = overflowing!(gas.overflow_add(schedule.suicide_to_new_account_cost.into()));
} }
@ -190,12 +195,19 @@ impl<Gas: CostType> Gasometer<Gas> {
); );
let address = u256_to_address(stack.peek(1)); let address = u256_to_address(stack.peek(1));
let is_value_transfer = !stack.peek(2).is_zero();
if instruction == instructions::CALL && !ext.exists(&address) { if instruction == instructions::CALL {
if (
!schedule.no_empty && !ext.exists(&address)
) || (
schedule.no_empty && is_value_transfer && !ext.exists_and_not_null(&address)
) {
gas = overflowing!(gas.overflow_add(schedule.call_new_account_gas.into())); gas = overflowing!(gas.overflow_add(schedule.call_new_account_gas.into()));
}
}; };
if !stack.peek(2).is_zero() { if is_value_transfer {
gas = overflowing!(gas.overflow_add(schedule.call_value_transfer_gas.into())); gas = overflowing!(gas.overflow_add(schedule.call_value_transfer_gas.into()));
}; };

View File

@ -93,6 +93,10 @@ pub struct Schedule {
/// If Some(x): let limit = GAS * (x - 1) / x; let CALL's gas = min(requested, limit). let CREATE's gas = limit. /// If Some(x): let limit = GAS * (x - 1) / x; let CALL's gas = min(requested, limit). let CREATE's gas = limit.
/// If None: let CALL's gas = (requested > GAS ? [OOG] : GAS). let CREATE's gas = GAS /// If None: let CALL's gas = (requested > GAS ? [OOG] : GAS). let CREATE's gas = GAS
pub sub_gas_cap_divisor: Option<usize>, pub sub_gas_cap_divisor: Option<usize>,
/// Don't ever make empty accounts; contracts start with nonce=1. Also, don't charge 25k when sending/suicide zero-value.
pub no_empty: bool,
/// Kill empty accounts if touched.
pub kill_empty: bool,
} }
impl Schedule { impl Schedule {
@ -106,8 +110,8 @@ impl Schedule {
Self::new(true, true, 53000) Self::new(true, true, 53000)
} }
/// Schedule for the Homestead-era of the Ethereum main net. /// Schedule for the post-EIP-150-era of the Ethereum main net.
pub fn new_homestead_gas_fix() -> Schedule { pub fn new_post_eip150(fix_exp: bool, no_empty: bool, kill_empty: bool) -> Schedule {
Schedule { Schedule {
exceptional_failed_code_deposit: true, exceptional_failed_code_deposit: true,
have_delegate_call: true, have_delegate_call: true,
@ -115,7 +119,7 @@ impl Schedule {
max_depth: 1024, max_depth: 1024,
tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0], tier_step_gas: [0, 2, 3, 5, 8, 10, 20, 0],
exp_gas: 10, exp_gas: 10,
exp_byte_gas: 10, exp_byte_gas: if fix_exp {50} else {10},
sha3_gas: 30, sha3_gas: 30,
sha3_word_gas: 6, sha3_word_gas: 6,
sload_gas: 200, sload_gas: 200,
@ -146,6 +150,8 @@ impl Schedule {
suicide_gas: 5000, suicide_gas: 5000,
suicide_to_new_account_cost: 25000, suicide_to_new_account_cost: 25000,
sub_gas_cap_divisor: Some(64), sub_gas_cap_divisor: Some(64),
no_empty: no_empty,
kill_empty: kill_empty,
} }
} }
@ -188,6 +194,8 @@ impl Schedule {
suicide_gas: 0, suicide_gas: 0,
suicide_to_new_account_cost: 0, suicide_to_new_account_cost: 0,
sub_gas_cap_divisor: None, sub_gas_cap_divisor: None,
no_empty: false,
kill_empty: false,
} }
} }
} }

View File

@ -94,6 +94,14 @@ impl Ext for FakeExt {
self.balances.contains_key(address) self.balances.contains_key(address)
} }
fn exists_and_not_null(&self, address: &Address) -> bool {
self.balances.get(address).map_or(false, |b| !b.is_zero())
}
fn origin_balance(&self) -> U256 {
unimplemented!()
}
fn balance(&self, address: &Address) -> U256 { fn balance(&self, address: &Address) -> U256 {
*self.balances.get(address).unwrap() *self.balances.get(address).unwrap()
} }

View File

@ -17,7 +17,7 @@
//! Transaction Execution environment. //! Transaction Execution environment.
use util::*; use util::*;
use action_params::{ActionParams, ActionValue}; use action_params::{ActionParams, ActionValue};
use state::{State, Substate}; use state::{State, Substate, CleanupMode};
use engines::Engine; use engines::Engine;
use types::executed::CallType; use types::executed::CallType;
use env_info::EnvInfo; use env_info::EnvInfo;
@ -256,9 +256,11 @@ impl<'a> Executive<'a> {
// backup used in case of running out of gas // backup used in case of running out of gas
self.state.checkpoint(); self.state.checkpoint();
let schedule = self.engine.schedule(self.info);
// at first, transfer value to destination // at first, transfer value to destination
if let ActionValue::Transfer(val) = params.value { if let ActionValue::Transfer(val) = params.value {
self.state.transfer_balance(&params.sender, &params.address, &val); self.state.transfer_balance(&params.sender, &params.address, &val, substate.to_cleanup_mode(&schedule));
} }
trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info); trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info);
@ -364,12 +366,14 @@ impl<'a> Executive<'a> {
let mut unconfirmed_substate = Substate::new(); let mut unconfirmed_substate = Substate::new();
// create contract and transfer value to it if necessary // create contract and transfer value to it if necessary
let schedule = self.engine.schedule(self.info);
let nonce_offset = if schedule.no_empty {1} else {0}.into();
let prev_bal = self.state.balance(&params.address); let prev_bal = self.state.balance(&params.address);
if let ActionValue::Transfer(val) = params.value { if let ActionValue::Transfer(val) = params.value {
self.state.sub_balance(&params.sender, &val); self.state.sub_balance(&params.sender, &val);
self.state.new_contract(&params.address, val + prev_bal); self.state.new_contract(&params.address, val + prev_bal, nonce_offset);
} else { } else {
self.state.new_contract(&params.address, prev_bal); self.state.new_contract(&params.address, prev_bal, nonce_offset);
} }
let trace_info = tracer.prepare_trace_create(&params); let trace_info = tracer.prepare_trace_create(&params);
@ -405,7 +409,7 @@ impl<'a> Executive<'a> {
fn finalize( fn finalize(
&mut self, &mut self,
t: &SignedTransaction, t: &SignedTransaction,
substate: Substate, mut substate: Substate,
result: evm::Result<U256>, result: evm::Result<U256>,
output: Bytes, output: Bytes,
trace: Vec<FlatTrace>, trace: Vec<FlatTrace>,
@ -440,15 +444,23 @@ impl<'a> Executive<'a> {
}; };
trace!("exec::finalize: Refunding refund_value={}, sender={}\n", refund_value, sender); trace!("exec::finalize: Refunding refund_value={}, sender={}\n", refund_value, sender);
self.state.add_balance(&sender, &refund_value); // Below: NoEmpty is safe since the sender must already be non-null to have sent this transaction
self.state.add_balance(&sender, &refund_value, CleanupMode::NoEmpty);
trace!("exec::finalize: Compensating author: fees_value={}, author={}\n", fees_value, &self.info.author); trace!("exec::finalize: Compensating author: fees_value={}, author={}\n", fees_value, &self.info.author);
self.state.add_balance(&self.info.author, &fees_value); self.state.add_balance(&self.info.author, &fees_value, substate.to_cleanup_mode(&schedule));
// perform suicides // perform suicides
for address in &substate.suicides { for address in &substate.suicides {
self.state.kill_account(address); self.state.kill_account(address);
} }
// perform garbage-collection
for address in &substate.garbage {
if self.state.exists(address) && !self.state.exists_and_not_null(address) {
self.state.kill_account(address);
}
}
match result { match result {
Err(evm::Error::Internal) => Err(ExecutionError::Internal), Err(evm::Error::Internal) => Err(ExecutionError::Internal),
Err(_) => { Err(_) => {
@ -509,7 +521,7 @@ mod tests {
use env_info::EnvInfo; use env_info::EnvInfo;
use evm::{Factory, VMType}; use evm::{Factory, VMType};
use error::ExecutionError; use error::ExecutionError;
use state::Substate; use state::{Substate, CleanupMode};
use tests::helpers::*; use tests::helpers::*;
use trace::trace; use trace::trace;
use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer}; use trace::{FlatTrace, Tracer, NoopTracer, ExecutiveTracer};
@ -538,7 +550,7 @@ mod tests {
params.value = ActionValue::Transfer(U256::from(0x7)); params.value = ActionValue::Transfer(U256::from(0x7));
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from(0x100u64)); state.add_balance(&sender, &U256::from(0x100u64), CleanupMode::NoEmpty);
let info = EnvInfo::default(); let info = EnvInfo::default();
let engine = TestEngine::new(0); let engine = TestEngine::new(0);
let mut substate = Substate::new(); let mut substate = Substate::new();
@ -597,7 +609,7 @@ mod tests {
params.value = ActionValue::Transfer(U256::from(100)); params.value = ActionValue::Transfer(U256::from(100));
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from(100)); state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty);
let info = EnvInfo::default(); let info = EnvInfo::default();
let engine = TestEngine::new(0); let engine = TestEngine::new(0);
let mut substate = Substate::new(); let mut substate = Substate::new();
@ -656,7 +668,7 @@ mod tests {
params.call_type = CallType::Call; params.call_type = CallType::Call;
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from(100)); state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty);
let info = EnvInfo::default(); let info = EnvInfo::default();
let engine = TestEngine::new(5); let engine = TestEngine::new(5);
let mut substate = Substate::new(); let mut substate = Substate::new();
@ -767,7 +779,7 @@ mod tests {
params.value = ActionValue::Transfer(100.into()); params.value = ActionValue::Transfer(100.into());
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from(100)); state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty);
let info = EnvInfo::default(); let info = EnvInfo::default();
let engine = TestEngine::new(5); let engine = TestEngine::new(5);
let mut substate = Substate::new(); let mut substate = Substate::new();
@ -855,7 +867,7 @@ mod tests {
params.value = ActionValue::Transfer(U256::from(100)); params.value = ActionValue::Transfer(U256::from(100));
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from(100)); state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty);
let info = EnvInfo::default(); let info = EnvInfo::default();
let engine = TestEngine::new(0); let engine = TestEngine::new(0);
let mut substate = Substate::new(); let mut substate = Substate::new();
@ -907,7 +919,7 @@ mod tests {
params.value = ActionValue::Transfer(U256::from(100)); params.value = ActionValue::Transfer(U256::from(100));
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from(100)); state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty);
let info = EnvInfo::default(); let info = EnvInfo::default();
let engine = TestEngine::new(1024); let engine = TestEngine::new(1024);
let mut substate = Substate::new(); let mut substate = Substate::new();
@ -967,7 +979,7 @@ mod tests {
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
state.init_code(&address_a, code_a.clone()); state.init_code(&address_a, code_a.clone());
state.init_code(&address_b, code_b.clone()); state.init_code(&address_b, code_b.clone());
state.add_balance(&sender, &U256::from(100_000)); state.add_balance(&sender, &U256::from(100_000), CleanupMode::NoEmpty);
let info = EnvInfo::default(); let info = EnvInfo::default();
let engine = TestEngine::new(0); let engine = TestEngine::new(0);
@ -1040,13 +1052,13 @@ mod tests {
gas: U256::from(100_000), gas: U256::from(100_000),
gas_price: U256::zero(), gas_price: U256::zero(),
nonce: U256::zero() nonce: U256::zero()
}.sign(keypair.secret()); }.sign(keypair.secret(), None);
let sender = t.sender().unwrap(); let sender = t.sender().unwrap();
let contract = contract_address(&sender, &U256::zero()); let contract = contract_address(&sender, &U256::zero());
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from(18)); state.add_balance(&sender, &U256::from(18), CleanupMode::NoEmpty);
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_limit = U256::from(100_000); info.gas_limit = U256::from(100_000);
let engine = TestEngine::new(0); let engine = TestEngine::new(0);
@ -1107,12 +1119,12 @@ mod tests {
gas: U256::from(100_000), gas: U256::from(100_000),
gas_price: U256::zero(), gas_price: U256::zero(),
nonce: U256::one() nonce: U256::one()
}.sign(keypair.secret()); }.sign(keypair.secret(), None);
let sender = t.sender().unwrap(); let sender = t.sender().unwrap();
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from(17)); state.add_balance(&sender, &U256::from(17), CleanupMode::NoEmpty);
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_limit = U256::from(100_000); info.gas_limit = U256::from(100_000);
let engine = TestEngine::new(0); let engine = TestEngine::new(0);
@ -1140,12 +1152,12 @@ mod tests {
gas: U256::from(80_001), gas: U256::from(80_001),
gas_price: U256::zero(), gas_price: U256::zero(),
nonce: U256::zero() nonce: U256::zero()
}.sign(keypair.secret()); }.sign(keypair.secret(), None);
let sender = t.sender().unwrap(); let sender = t.sender().unwrap();
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from(17)); state.add_balance(&sender, &U256::from(17), CleanupMode::NoEmpty);
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_used = U256::from(20_000); info.gas_used = U256::from(20_000);
info.gas_limit = U256::from(100_000); info.gas_limit = U256::from(100_000);
@ -1175,12 +1187,12 @@ mod tests {
gas: U256::from(100_000), gas: U256::from(100_000),
gas_price: U256::one(), gas_price: U256::one(),
nonce: U256::zero() nonce: U256::zero()
}.sign(keypair.secret()); }.sign(keypair.secret(), None);
let sender = t.sender().unwrap(); let sender = t.sender().unwrap();
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from(100_017)); state.add_balance(&sender, &U256::from(100_017), CleanupMode::NoEmpty);
let mut info = EnvInfo::default(); let mut info = EnvInfo::default();
info.gas_limit = U256::from(100_000); info.gas_limit = U256::from(100_000);
let engine = TestEngine::new(0); let engine = TestEngine::new(0);
@ -1215,7 +1227,7 @@ mod tests {
params.value = ActionValue::Transfer(U256::from_str("0de0b6b3a7640000").unwrap()); params.value = ActionValue::Transfer(U256::from_str("0de0b6b3a7640000").unwrap());
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap()); state.add_balance(&sender, &U256::from_str("152d02c7e14af6800000").unwrap(), CleanupMode::NoEmpty);
let info = EnvInfo::default(); let info = EnvInfo::default();
let engine = TestEngine::new(0); let engine = TestEngine::new(0);
let mut substate = Substate::new(); let mut substate = Substate::new();

View File

@ -114,6 +114,12 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
self.state.exists(address) self.state.exists(address)
} }
fn exists_and_not_null(&self, address: &Address) -> bool {
self.state.exists_and_not_null(address)
}
fn origin_balance(&self) -> U256 { self.balance(&self.origin_info.address) }
fn balance(&self, address: &Address) -> U256 { fn balance(&self, address: &Address) -> U256 {
self.state.balance(address) self.state.balance(address)
} }
@ -269,11 +275,11 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
let address = self.origin_info.address.clone(); let address = self.origin_info.address.clone();
let balance = self.balance(&address); let balance = self.balance(&address);
if &address == refund_address { if &address == refund_address {
// TODO [todr] To be consisted with CPP client we set balance to 0 in that case. // TODO [todr] To be consistent with CPP client we set balance to 0 in that case.
self.state.sub_balance(&address, &balance); self.state.sub_balance(&address, &balance);
} else { } else {
trace!("Suiciding {} -> {} (xfer: {})", address, refund_address, balance); trace!(target: "ext", "Suiciding {} -> {} (xfer: {})", address, refund_address, balance);
self.state.transfer_balance(&address, refund_address, &balance); self.state.transfer_balance(&address, refund_address, &balance, self.substate.to_cleanup_mode(&self.schedule));
} }
self.tracer.trace_suicide(address, balance, refund_address.clone()); self.tracer.trace_suicide(address, balance, refund_address.clone());

View File

@ -49,6 +49,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
ChainEra::Frontier => ethereum::new_frontier_test(), ChainEra::Frontier => ethereum::new_frontier_test(),
ChainEra::Homestead => ethereum::new_homestead_test(), ChainEra::Homestead => ethereum::new_homestead_test(),
ChainEra::Eip150 => ethereum::new_eip150_test(), ChainEra::Eip150 => ethereum::new_eip150_test(),
ChainEra::Eip161 => ethereum::new_eip161_test(),
ChainEra::TransitionTest => ethereum::new_transition_test(), ChainEra::TransitionTest => ethereum::new_transition_test(),
}; };
spec.set_genesis_state(state); spec.set_genesis_state(state);

View File

@ -0,0 +1,51 @@
// 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 <http://www.gnu.org/licenses/>.
use super::test_common::*;
use tests::helpers::*;
use super::state::json_chain_test;
fn do_json_test(json_data: &[u8]) -> Vec<String> {
json_chain_test(json_data, ChainEra::Eip161)
}
declare_test!{StateTests_EIP158_stEIP158SpecificTest, "StateTests/EIP158/stEIP158SpecificTest"}
declare_test!{StateTests_EIP158_stNonZeroCallsTest, "StateTests/EIP158/stNonZeroCallsTest"}
declare_test!{StateTests_EIP158_stZeroCallsTest, "StateTests/EIP158/stZeroCallsTest"}
declare_test!{StateTests_EIP158_EIP150_stMemExpandingEIPCalls, "StateTests/EIP158/EIP150/stMemExpandingEIPCalls"}
declare_test!{StateTests_EIP158_EIP150_stEIPSpecificTest, "StateTests/EIP158/EIP150/stEIPSpecificTest"}
declare_test!{StateTests_EIP158_EIP150_stEIPsingleCodeGasPrices, "StateTests/EIP158/EIP150/stEIPsingleCodeGasPrices"}
declare_test!{StateTests_EIP158_EIP150_stChangedTests, "StateTests/EIP158/EIP150/stChangedTests"}
declare_test!{StateTests_EIP158_Homestead_stBoundsTest, "StateTests/EIP158/Homestead/stBoundsTest"}
declare_test!{StateTests_EIP158_Homestead_stCallCodes, "StateTests/EIP158/Homestead/stCallCodes"}
declare_test!{StateTests_EIP158_Homestead_stCallCreateCallCodeTest, "StateTests/EIP158/Homestead/stCallCreateCallCodeTest"}
declare_test!{StateTests_EIP158_Homestead_stCallDelegateCodes, "StateTests/EIP158/Homestead/stCallDelegateCodes"}
declare_test!{StateTests_EIP158_Homestead_stCallDelegateCodesCallCode, "StateTests/EIP158/Homestead/stCallDelegateCodesCallCode"}
declare_test!{StateTests_EIP158_Homestead_stDelegatecallTest, "StateTests/EIP158/Homestead/stDelegatecallTest"}
declare_test!{StateTests_EIP158_Homestead_stHomeSteadSpecific, "StateTests/EIP158/Homestead/stHomeSteadSpecific"}
declare_test!{StateTests_EIP158_Homestead_stInitCodeTest, "StateTests/EIP158/Homestead/stInitCodeTest"}
declare_test!{StateTests_EIP158_Homestead_stLogTests, "StateTests/EIP158/Homestead/stLogTests"}
declare_test!{heavy => StateTests_EIP158_Homestead_stMemoryTest, "StateTests/EIP158/Homestead/stMemoryTest"}
declare_test!{StateTests_EIP158_Homestead_stPreCompiledContracts, "StateTests/EIP158/Homestead/stPreCompiledContracts"}
declare_test!{heavy => StateTests_EIP158_Homestead_stQuadraticComplexityTest, "StateTests/EIP158/Homestead/stQuadraticComplexityTest"}
declare_test!{StateTests_EIP158_Homestead_stRecursiveCreate, "StateTests/EIP158/Homestead/stRecursiveCreate"}
declare_test!{StateTests_EIP158_Homestead_stRefundTest, "StateTests/EIP158/Homestead/stRefundTest"}
declare_test!{StateTests_EIP158_Homestead_stSpecialTest, "StateTests/EIP158/Homestead/stSpecialTest"}
declare_test!{StateTests_EIP158_Homestead_stSystemOperationsTest, "StateTests/EIP158/Homestead/stSystemOperationsTest"}
declare_test!{StateTests_EIP158_Homestead_stTransactionTest, "StateTests/EIP158/Homestead/stTransactionTest"}
declare_test!{StateTests_EIP158_Homestead_stWalletTest, "StateTests/EIP158/Homestead/stWalletTest"}

View File

@ -92,10 +92,18 @@ impl<'a, T, V> Ext for TestExt<'a, T, V> where T: Tracer, V: VMTracer {
self.ext.exists(address) self.ext.exists(address)
} }
fn exists_and_not_null(&self, address: &Address) -> bool {
self.ext.exists_and_not_null(address)
}
fn balance(&self, address: &Address) -> U256 { fn balance(&self, address: &Address) -> U256 {
self.ext.balance(address) self.ext.balance(address)
} }
fn origin_balance(&self) -> U256 {
self.ext.origin_balance()
}
fn blockhash(&self, number: &U256) -> H256 { fn blockhash(&self, number: &U256) -> H256 {
self.ext.blockhash(number) self.ext.blockhash(number)
} }

View File

@ -24,4 +24,5 @@ mod chain;
mod homestead_state; mod homestead_state;
mod homestead_chain; mod homestead_chain;
mod eip150_state; mod eip150_state;
mod eip161_state;
mod trie; mod trie;

View File

@ -29,6 +29,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
ChainEra::Frontier => ethereum::new_mainnet_like().engine, ChainEra::Frontier => ethereum::new_mainnet_like().engine,
ChainEra::Homestead => ethereum::new_homestead_test().engine, ChainEra::Homestead => ethereum::new_homestead_test().engine,
ChainEra::Eip150 => ethereum::new_eip150_test().engine, ChainEra::Eip150 => ethereum::new_eip150_test().engine,
ChainEra::Eip161 => ethereum::new_eip161_test().engine,
ChainEra::TransitionTest => ethereum::new_transition_test().engine, ChainEra::TransitionTest => ethereum::new_transition_test().engine,
}; };

View File

@ -35,17 +35,24 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
Some(x) if x < 1_150_000 => &old_schedule, Some(x) if x < 1_150_000 => &old_schedule,
Some(_) => &new_schedule Some(_) => &new_schedule
}; };
let allow_network_id_of_one = number.map_or(false, |n| n > 2600000);
let rlp: Vec<u8> = test.rlp.into(); let rlp: Vec<u8> = test.rlp.into();
let res = UntrustedRlp::new(&rlp) let res = UntrustedRlp::new(&rlp)
.as_val() .as_val()
.map_err(From::from) .map_err(From::from)
.and_then(|t: SignedTransaction| t.validate(schedule, schedule.have_delegate_call)); .and_then(|t: SignedTransaction| t.validate(schedule, schedule.have_delegate_call, allow_network_id_of_one));
fail_unless(test.transaction.is_none() == res.is_err()); fail_unless(test.transaction.is_none() == res.is_err());
if let (Some(tx), Some(sender)) = (test.transaction, test.sender) { if let (Some(tx), Some(sender)) = (test.transaction, test.sender) {
let t = res.unwrap(); let t = res.unwrap();
fail_unless(t.sender().unwrap() == sender.into()); fail_unless(t.sender().unwrap() == sender.into());
let is_acceptable_network_id = match t.network_id() {
None => true,
Some(1) if allow_network_id_of_one => true,
_ => false,
};
fail_unless(is_acceptable_network_id);
let data: Vec<u8> = tx.data.into(); let data: Vec<u8> = tx.data.into();
fail_unless(t.data == data); fail_unless(t.data == data);
fail_unless(t.gas_price == tx.gas_price.into()); fail_unless(t.gas_price == tx.gas_price.into());

View File

@ -245,7 +245,7 @@ mod tests {
gas: U256::from(100_000), gas: U256::from(100_000),
gas_price: U256::from(10), gas_price: U256::from(10),
nonce: U256::from(0), nonce: U256::from(0),
}.sign(keypair.secret()) }.sign(keypair.secret(), None)
} }
fn unwrap_err(res: Result<TransactionImportResult, Error>) -> TransactionError { fn unwrap_err(res: Result<TransactionImportResult, Error>) -> TransactionError {

View File

@ -21,7 +21,7 @@ use util::*;
use util::using_queue::{UsingQueue, GetAction}; use util::using_queue::{UsingQueue, GetAction};
use account_provider::AccountProvider; use account_provider::AccountProvider;
use views::{BlockView, HeaderView}; use views::{BlockView, HeaderView};
use state::State; use state::{State, CleanupMode};
use client::{MiningBlockChainClient, Executive, Executed, EnvInfo, TransactOptions, BlockID, CallAnalytics}; use client::{MiningBlockChainClient, Executive, Executed, EnvInfo, TransactOptions, BlockID, CallAnalytics};
use executive::contract_address; use executive::contract_address;
use block::{ClosedBlock, SealedBlock, IsBlock, Block}; use block::{ClosedBlock, SealedBlock, IsBlock, Block};
@ -657,7 +657,7 @@ impl MinerService for Miner {
let needed_balance = t.value + t.gas * t.gas_price; let needed_balance = t.value + t.gas * t.gas_price;
if balance < needed_balance { if balance < needed_balance {
// give the sender a sufficient balance // give the sender a sufficient balance
state.add_balance(&sender, &(needed_balance - balance)); state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty);
} }
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false }; let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
let mut ret = try!(Executive::new(&mut state, &env_info, &*self.engine, chain.vm_factory()).transact(t, options)); let mut ret = try!(Executive::new(&mut state, &env_info, &*self.engine, chain.vm_factory()).transact(t, options));
@ -942,6 +942,8 @@ impl MinerService for Miner {
} }
}, },
logs: receipt.logs.clone(), logs: receipt.logs.clone(),
log_bloom: receipt.log_bloom,
state_root: receipt.state_root,
} }
}) })
} }
@ -1180,7 +1182,7 @@ mod tests {
gas: U256::from(100_000), gas: U256::from(100_000),
gas_price: U256::zero(), gas_price: U256::zero(),
nonce: U256::zero(), nonce: U256::zero(),
}.sign(keypair.secret()) }.sign(keypair.secret(), None)
} }
#[test] #[test]

View File

@ -42,8 +42,8 @@
//! let t2 = Transaction { action: Action::Create, value: U256::from(100), data: "3331600055".from_hex().unwrap(), //! let t2 = Transaction { action: Action::Create, value: U256::from(100), data: "3331600055".from_hex().unwrap(),
//! gas: U256::from(100_000), gas_price: U256::one(), nonce: U256::from(11) }; //! gas: U256::from(100_000), gas_price: U256::one(), nonce: U256::from(11) };
//! //!
//! let st1 = t1.sign(&key.secret()); //! let st1 = t1.sign(&key.secret(), None);
//! let st2 = t2.sign(&key.secret()); //! let st2 = t2.sign(&key.secret(), None);
//! let default_account_details = |_a: &Address| AccountDetails { //! let default_account_details = |_a: &Address| AccountDetails {
//! nonce: U256::from(10), //! nonce: U256::from(10),
//! balance: U256::from(1_000_000), //! balance: U256::from(1_000_000),
@ -1104,12 +1104,12 @@ mod test {
fn new_tx(nonce: U256, gas_price: U256) -> SignedTransaction { fn new_tx(nonce: U256, gas_price: U256) -> SignedTransaction {
let keypair = Random.generate().unwrap(); let keypair = Random.generate().unwrap();
new_unsigned_tx(nonce, default_gas_val(), gas_price).sign(keypair.secret()) new_unsigned_tx(nonce, default_gas_val(), gas_price).sign(keypair.secret(), None)
} }
fn new_tx_with_gas(gas: U256, gas_price: U256) -> SignedTransaction { fn new_tx_with_gas(gas: U256, gas_price: U256) -> SignedTransaction {
let keypair = Random.generate().unwrap(); let keypair = Random.generate().unwrap();
new_unsigned_tx(default_nonce(), gas, gas_price).sign(keypair.secret()) new_unsigned_tx(default_nonce(), gas, gas_price).sign(keypair.secret(), None)
} }
fn new_tx_default() -> SignedTransaction { fn new_tx_default() -> SignedTransaction {
@ -1133,7 +1133,7 @@ mod test {
let keypair = Random.generate().unwrap(); let keypair = Random.generate().unwrap();
let secret = &keypair.secret(); let secret = &keypair.secret();
(tx1.sign(secret), tx2.sign(secret)) (tx1.sign(secret, None), tx2.sign(secret, None))
} }
/// Returns two consecutive transactions, both with increased gas price /// Returns two consecutive transactions, both with increased gas price
@ -1144,7 +1144,7 @@ mod test {
let keypair = Random.generate().unwrap(); let keypair = Random.generate().unwrap();
let secret = &keypair.secret(); let secret = &keypair.secret();
(tx1.sign(secret), tx2.sign(secret)) (tx1.sign(secret, None), tx2.sign(secret, None))
} }
fn new_tx_pair_default(nonce_increment: U256, gas_price_increment: U256) -> (SignedTransaction, SignedTransaction) { fn new_tx_pair_default(nonce_increment: U256, gas_price_increment: U256) -> (SignedTransaction, SignedTransaction) {
@ -1798,9 +1798,9 @@ mod test {
let mut txq = TransactionQueue::default(); let mut txq = TransactionQueue::default();
let kp = Random.generate().unwrap(); let kp = Random.generate().unwrap();
let secret = kp.secret(); let secret = kp.secret();
let tx = new_unsigned_tx(123.into(), default_gas_val(), 1.into()).sign(secret); let tx = new_unsigned_tx(123.into(), default_gas_val(), 1.into()).sign(secret, None);
let tx1 = new_unsigned_tx(124.into(), default_gas_val(), 1.into()).sign(secret); let tx1 = new_unsigned_tx(124.into(), default_gas_val(), 1.into()).sign(secret, None);
let tx2 = new_unsigned_tx(125.into(), default_gas_val(), 1.into()).sign(secret); let tx2 = new_unsigned_tx(125.into(), default_gas_val(), 1.into()).sign(secret, None);
txq.add(tx, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap(); txq.add(tx, TransactionOrigin::External, &default_account_details, &gas_estimator).unwrap();
assert_eq!(txq.status().pending, 1); assert_eq!(txq.status().pending, 1);
@ -2038,11 +2038,11 @@ mod test {
// given // given
let mut txq = TransactionQueue::default(); let mut txq = TransactionQueue::default();
let keypair = Random.generate().unwrap(); let keypair = Random.generate().unwrap();
let tx = new_unsigned_tx(123.into(), default_gas_val(), 1.into()).sign(keypair.secret()); let tx = new_unsigned_tx(123.into(), default_gas_val(), 1.into()).sign(keypair.secret(), None);
let tx2 = { let tx2 = {
let mut tx2 = (*tx).clone(); let mut tx2 = (*tx).clone();
tx2.gas_price = U256::from(200); tx2.gas_price = U256::from(200);
tx2.sign(keypair.secret()) tx2.sign(keypair.secret(), None)
}; };
// when // when
@ -2061,16 +2061,16 @@ mod test {
// given // given
let mut txq = TransactionQueue::default(); let mut txq = TransactionQueue::default();
let keypair = Random.generate().unwrap(); let keypair = Random.generate().unwrap();
let tx0 = new_unsigned_tx(123.into(), default_gas_val(), 1.into()).sign(keypair.secret()); let tx0 = new_unsigned_tx(123.into(), default_gas_val(), 1.into()).sign(keypair.secret(), None);
let tx1 = { let tx1 = {
let mut tx1 = (*tx0).clone(); let mut tx1 = (*tx0).clone();
tx1.nonce = U256::from(124); tx1.nonce = U256::from(124);
tx1.sign(keypair.secret()) tx1.sign(keypair.secret(), None)
}; };
let tx2 = { let tx2 = {
let mut tx2 = (*tx1).clone(); let mut tx2 = (*tx1).clone();
tx2.gas_price = U256::from(200); tx2.gas_price = U256::from(200);
tx2.sign(keypair.secret()) tx2.sign(keypair.secret(), None)
}; };
// when // when
@ -2223,7 +2223,7 @@ mod test {
let tx3 = new_unsigned_tx(nonce + 2.into(), gas, 1.into()); let tx3 = new_unsigned_tx(nonce + 2.into(), gas, 1.into());
(tx.sign(secret), tx2.sign(secret), tx2_2.sign(secret), tx3.sign(secret)) (tx.sign(secret, None), tx2.sign(secret, None), tx2_2.sign(secret, None), tx3.sign(secret, None))
}; };
let sender = tx1.sender().unwrap(); let sender = tx1.sender().unwrap();
txq.add(tx1, TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap(); txq.add(tx1, TransactionOrigin::Local, &default_account_details, &gas_estimator).unwrap();

View File

@ -38,7 +38,7 @@ pub struct CommonParams {
/// Maximum size of extra data. /// Maximum size of extra data.
pub maximum_extra_data_size: usize, pub maximum_extra_data_size: usize,
/// Network id. /// Network id.
pub network_id: U256, pub network_id: usize,
/// Main subprotocol name. /// Main subprotocol name.
pub subprotocol_name: String, pub subprotocol_name: String,
/// Minimum gas limit. /// Minimum gas limit.
@ -161,7 +161,7 @@ impl Spec {
pub fn nodes(&self) -> &[String] { &self.nodes } pub fn nodes(&self) -> &[String] { &self.nodes }
/// Get the configured Network ID. /// Get the configured Network ID.
pub fn network_id(&self) -> U256 { self.params.network_id } pub fn network_id(&self) -> usize { self.params.network_id }
/// Get the configured Network ID. /// Get the configured Network ID.
pub fn subprotocol_name(&self) -> String { self.params.subprotocol_name.clone() } pub fn subprotocol_name(&self) -> String { self.params.subprotocol_name.clone() }
@ -251,7 +251,7 @@ impl Spec {
} }
trace!(target: "spec", "ensure_db_good: Populated sec trie; root is {}", root); trace!(target: "spec", "ensure_db_good: Populated sec trie; root is {}", root);
for (address, account) in self.genesis_state.get().iter() { for (address, account) in self.genesis_state.get().iter() {
db.note_account_bloom(address); db.note_non_null_account(address);
account.insert_additional(&mut AccountDBMut::new(db.as_hashdb_mut(), address)); account.insert_additional(&mut AccountDBMut::new(db.as_hashdb_mut(), address));
} }
assert!(db.as_hashdb().contains(&self.state_root())); assert!(db.as_hashdb().contains(&self.state_root()));

View File

@ -300,11 +300,17 @@ impl Account {
pub fn storage_is_clean(&self) -> bool { self.storage_changes.is_empty() } pub fn storage_is_clean(&self) -> bool { self.storage_changes.is_empty() }
/// Check if account has zero nonce, balance, no code and no storage. /// Check if account has zero nonce, balance, no code and no storage.
///
/// NOTE: Will panic if `!self.storage_is_clean()`
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.storage_changes.is_empty() && assert!(self.storage_is_clean(), "Account::is_empty() may only legally be called when storage is clean.");
self.is_null() && self.storage_root == SHA3_NULL_RLP
}
/// Check if account has zero nonce, balance, no code.
pub fn is_null(&self) -> bool {
self.balance.is_zero() && self.balance.is_zero() &&
self.nonce.is_zero() && self.nonce.is_zero() &&
self.storage_root == SHA3_NULL_RLP &&
self.code_hash == SHA3_EMPTY self.code_hash == SHA3_EMPTY
} }

View File

@ -199,6 +199,13 @@ enum RequireCache {
Code, Code,
} }
#[derive(PartialEq)]
pub enum CleanupMode<'a> {
ForceCreate,
NoEmpty,
KillEmpty(&'a mut HashSet<Address>),
}
const SEC_TRIE_DB_UNWRAP_STR: &'static str = "A state can only be created with valid root. Creating a SecTrieDB with a valid root will not fail. \ const SEC_TRIE_DB_UNWRAP_STR: &'static str = "A state can only be created with valid root. Creating a SecTrieDB with a valid root will not fail. \
Therefore creating a SecTrieDB with this state's root will not fail."; Therefore creating a SecTrieDB with this state's root will not fail.";
@ -329,8 +336,8 @@ impl State {
/// Create a new contract at address `contract`. If there is already an account at the address /// Create a new contract at address `contract`. If there is already an account at the address
/// it will have its code reset, ready for `init_code()`. /// it will have its code reset, ready for `init_code()`.
pub fn new_contract(&mut self, contract: &Address, balance: U256) { pub fn new_contract(&mut self, contract: &Address, balance: U256, nonce_offset: U256) {
self.insert_cache(contract, AccountEntry::new_dirty(Some(Account::new_contract(balance, self.account_start_nonce)))); self.insert_cache(contract, AccountEntry::new_dirty(Some(Account::new_contract(balance, self.account_start_nonce + nonce_offset))));
} }
/// Remove an existing account. /// Remove an existing account.
@ -341,10 +348,15 @@ impl State {
/// Determine whether an account exists. /// Determine whether an account exists.
pub fn exists(&self, a: &Address) -> bool { pub fn exists(&self, a: &Address) -> bool {
// Bloom filter does not contain empty accounts, so it is important here to // Bloom filter does not contain empty accounts, so it is important here to
// check if account exists in the database directly before EIP-158 is in effect. // check if account exists in the database directly before EIP-161 is in effect.
self.ensure_cached(a, RequireCache::None, false, |a| a.is_some()) self.ensure_cached(a, RequireCache::None, false, |a| a.is_some())
} }
/// Determine whether an account exists and if not empty.
pub fn exists_and_not_null(&self, a: &Address) -> bool {
self.ensure_cached(a, RequireCache::None, false, |a| a.map_or(false, |a| !a.is_null()))
}
/// Get the balance of account `a`. /// Get the balance of account `a`.
pub fn balance(&self, a: &Address) -> U256 { pub fn balance(&self, a: &Address) -> U256 {
self.ensure_cached(a, RequireCache::None, true, self.ensure_cached(a, RequireCache::None, true,
@ -399,7 +411,7 @@ impl State {
} }
// check bloom before any requests to trie // check bloom before any requests to trie
if !self.db.check_account_bloom(address) { return H256::zero() } if !self.db.check_non_null_bloom(address) { return H256::zero() }
// account is not found in the global cache, get from the DB and insert into local // account is not found in the global cache, get from the DB and insert into local
let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
@ -433,10 +445,18 @@ impl State {
} }
/// Add `incr` to the balance of account `a`. /// Add `incr` to the balance of account `a`.
pub fn add_balance(&mut self, a: &Address, incr: &U256) { pub fn add_balance(&mut self, a: &Address, incr: &U256, cleanup_mode: CleanupMode) {
trace!(target: "state", "add_balance({}, {}): {}", a, incr, self.balance(a)); trace!(target: "state", "add_balance({}, {}): {}", a, incr, self.balance(a));
if !incr.is_zero() || !self.exists(a) { let is_value_transfer = !incr.is_zero();
if is_value_transfer || (cleanup_mode == CleanupMode::ForceCreate && !self.exists(a)) {
self.require(a, false).add_balance(incr); self.require(a, false).add_balance(incr);
} else {
match cleanup_mode {
CleanupMode::KillEmpty(set) => if !is_value_transfer && self.exists(a) && !self.exists_and_not_null(a) {
set.insert(a.clone());
},
_ => {}
}
} }
} }
@ -449,9 +469,9 @@ impl State {
} }
/// Subtracts `by` from the balance of `from` and adds it to that of `to`. /// Subtracts `by` from the balance of `from` and adds it to that of `to`.
pub fn transfer_balance(&mut self, from: &Address, to: &Address, by: &U256) { pub fn transfer_balance(&mut self, from: &Address, to: &Address, by: &U256, cleanup_mode: CleanupMode) {
self.sub_balance(from, by); self.sub_balance(from, by);
self.add_balance(to, by); self.add_balance(to, by, cleanup_mode);
} }
/// Increment the nonce of account `a` by 1. /// Increment the nonce of account `a` by 1.
@ -507,14 +527,16 @@ impl State {
// first, commit the sub trees. // first, commit the sub trees.
for (address, ref mut a) in accounts.iter_mut().filter(|&(_, ref a)| a.is_dirty()) { for (address, ref mut a) in accounts.iter_mut().filter(|&(_, ref a)| a.is_dirty()) {
if let Some(ref mut account) = a.account { if let Some(ref mut account) = a.account {
if !account.is_empty() {
db.note_account_bloom(address);
}
let addr_hash = account.address_hash(address); let addr_hash = account.address_hash(address);
{
let mut account_db = factories.accountdb.create(db.as_hashdb_mut(), addr_hash); let mut account_db = factories.accountdb.create(db.as_hashdb_mut(), addr_hash);
account.commit_storage(&factories.trie, account_db.as_hashdb_mut()); account.commit_storage(&factories.trie, account_db.as_hashdb_mut());
account.commit_code(account_db.as_hashdb_mut()); account.commit_code(account_db.as_hashdb_mut());
} }
if !account.is_empty() {
db.note_non_null_account(address);
}
}
} }
{ {
@ -653,7 +675,7 @@ impl State {
Some(r) => r, Some(r) => r,
None => { None => {
// first check bloom if it is not in database for sure // first check bloom if it is not in database for sure
if check_bloom && !self.db.check_account_bloom(a) { return f(None); } if check_bloom && !self.db.check_non_null_bloom(a) { return f(None); }
// not found in the global cache, get from the DB and insert into local // not found in the global cache, get from the DB and insert into local
let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
@ -687,7 +709,7 @@ impl State {
match self.db.get_cached_account(a) { match self.db.get_cached_account(a) {
Some(acc) => self.insert_cache(a, AccountEntry::new_clean_cached(acc)), Some(acc) => self.insert_cache(a, AccountEntry::new_clean_cached(acc)),
None => { None => {
let maybe_acc = if self.db.check_account_bloom(a) { let maybe_acc = if self.db.check_non_null_bloom(a) {
let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR); let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
match db.get(a) { match db.get(a) {
Ok(Some(acc)) => AccountEntry::new_clean(Some(Account::from_rlp(&acc))), Ok(Some(acc)) => AccountEntry::new_clean(Some(Account::from_rlp(&acc))),
@ -793,9 +815,9 @@ fn should_apply_create_transaction() {
action: Action::Create, action: Action::Create,
value: 100.into(), value: 100.into(),
data: FromHex::from_hex("601080600c6000396000f3006000355415600957005b60203560003555").unwrap(), data: FromHex::from_hex("601080600c6000396000f3006000355415600957005b60203560003555").unwrap(),
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
let result = state.apply(&info, &engine, &t, true).unwrap(); let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace { let expected_trace = vec![FlatTrace {
trace_address: Default::default(), trace_address: Default::default(),
@ -853,9 +875,9 @@ fn should_trace_failed_create_transaction() {
action: Action::Create, action: Action::Create,
value: 100.into(), value: 100.into(),
data: FromHex::from_hex("5b600056").unwrap(), data: FromHex::from_hex("5b600056").unwrap(),
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
let result = state.apply(&info, &engine, &t, true).unwrap(); let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace { let expected_trace = vec![FlatTrace {
trace_address: Default::default(), trace_address: Default::default(),
@ -890,10 +912,10 @@ fn should_trace_call_transaction() {
action: Action::Call(0xa.into()), action: Action::Call(0xa.into()),
value: 100.into(), value: 100.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("6000").unwrap()); state.init_code(&0xa.into(), FromHex::from_hex("6000").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
let result = state.apply(&info, &engine, &t, true).unwrap(); let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace { let expected_trace = vec![FlatTrace {
trace_address: Default::default(), trace_address: Default::default(),
@ -933,9 +955,9 @@ fn should_trace_basic_call_transaction() {
action: Action::Call(0xa.into()), action: Action::Call(0xa.into()),
value: 100.into(), value: 100.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
let result = state.apply(&info, &engine, &t, true).unwrap(); let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace { let expected_trace = vec![FlatTrace {
trace_address: Default::default(), trace_address: Default::default(),
@ -975,7 +997,7 @@ fn should_trace_call_transaction_to_builtin() {
action: Action::Call(0x1.into()), action: Action::Call(0x1.into()),
value: 0.into(), value: 0.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
let result = state.apply(&info, engine, &t, true).unwrap(); let result = state.apply(&info, engine, &t, true).unwrap();
@ -1017,7 +1039,7 @@ fn should_not_trace_subcall_transaction_to_builtin() {
action: Action::Call(0xa.into()), action: Action::Call(0xa.into()),
value: 0.into(), value: 0.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060006001610be0f1").unwrap()); state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060006001610be0f1").unwrap());
let result = state.apply(&info, engine, &t, true).unwrap(); let result = state.apply(&info, engine, &t, true).unwrap();
@ -1060,7 +1082,7 @@ fn should_not_trace_callcode() {
action: Action::Call(0xa.into()), action: Action::Call(0xa.into()),
value: 0.into(), value: 0.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b611000f2").unwrap()); state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b611000f2").unwrap());
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
@ -1122,7 +1144,7 @@ fn should_not_trace_delegatecall() {
action: Action::Call(0xa.into()), action: Action::Call(0xa.into()),
value: 0.into(), value: 0.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("6000600060006000600b618000f4").unwrap()); state.init_code(&0xa.into(), FromHex::from_hex("6000600060006000600b618000f4").unwrap());
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
@ -1181,10 +1203,10 @@ fn should_trace_failed_call_transaction() {
action: Action::Call(0xa.into()), action: Action::Call(0xa.into()),
value: 100.into(), value: 100.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("5b600056").unwrap()); state.init_code(&0xa.into(), FromHex::from_hex("5b600056").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
let result = state.apply(&info, &engine, &t, true).unwrap(); let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace { let expected_trace = vec![FlatTrace {
trace_address: Default::default(), trace_address: Default::default(),
@ -1221,11 +1243,11 @@ fn should_trace_call_with_subcall_transaction() {
action: Action::Call(0xa.into()), action: Action::Call(0xa.into()),
value: 100.into(), value: 100.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
let result = state.apply(&info, &engine, &t, true).unwrap(); let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace { let expected_trace = vec![FlatTrace {
@ -1281,10 +1303,10 @@ fn should_trace_call_with_basic_subcall_transaction() {
action: Action::Call(0xa.into()), action: Action::Call(0xa.into()),
value: 100.into(), value: 100.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006045600b6000f1").unwrap()); state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006045600b6000f1").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
let result = state.apply(&info, &engine, &t, true).unwrap(); let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace { let expected_trace = vec![FlatTrace {
trace_address: Default::default(), trace_address: Default::default(),
@ -1336,10 +1358,10 @@ fn should_not_trace_call_with_invalid_basic_subcall_transaction() {
action: Action::Call(0xa.into()), action: Action::Call(0xa.into()),
value: 100.into(), value: 100.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060ff600b6000f1").unwrap()); // not enough funds. state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060ff600b6000f1").unwrap()); // not enough funds.
state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
let result = state.apply(&info, &engine, &t, true).unwrap(); let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace { let expected_trace = vec![FlatTrace {
trace_address: Default::default(), trace_address: Default::default(),
@ -1379,11 +1401,11 @@ fn should_trace_failed_subcall_transaction() {
action: Action::Call(0xa.into()), action: Action::Call(0xa.into()),
value: 100.into(), value: 100.into(),
data: vec![],//600480600b6000396000f35b600056 data: vec![],//600480600b6000396000f35b600056
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
state.init_code(&0xb.into(), FromHex::from_hex("5b600056").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("5b600056").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
let result = state.apply(&info, &engine, &t, true).unwrap(); let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace { let expected_trace = vec![FlatTrace {
trace_address: Default::default(), trace_address: Default::default(),
@ -1435,12 +1457,12 @@ fn should_trace_call_with_subcall_with_subcall_transaction() {
action: Action::Call(0xa.into()), action: Action::Call(0xa.into()),
value: 100.into(), value: 100.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1").unwrap());
state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap()); state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
let result = state.apply(&info, &engine, &t, true).unwrap(); let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace { let expected_trace = vec![FlatTrace {
trace_address: Default::default(), trace_address: Default::default(),
@ -1510,12 +1532,12 @@ fn should_trace_failed_subcall_with_subcall_transaction() {
action: Action::Call(0xa.into()), action: Action::Call(0xa.into()),
value: 100.into(), value: 100.into(),
data: vec![],//600480600b6000396000f35b600056 data: vec![],//600480600b6000396000f35b600056
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap()); state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1505b601256").unwrap()); state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1505b601256").unwrap());
state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap()); state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into())); state.add_balance(t.sender().as_ref().unwrap(), &(100.into()), CleanupMode::NoEmpty);
let result = state.apply(&info, &engine, &t, true).unwrap(); let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace { let expected_trace = vec![FlatTrace {
@ -1583,11 +1605,11 @@ fn should_trace_suicide() {
action: Action::Call(0xa.into()), action: Action::Call(0xa.into()),
value: 100.into(), value: 100.into(),
data: vec![], data: vec![],
}.sign(&"".sha3()); }.sign(&"".sha3(), None);
state.init_code(&0xa.into(), FromHex::from_hex("73000000000000000000000000000000000000000bff").unwrap()); state.init_code(&0xa.into(), FromHex::from_hex("73000000000000000000000000000000000000000bff").unwrap());
state.add_balance(&0xa.into(), &50.into()); state.add_balance(&0xa.into(), &50.into(), CleanupMode::NoEmpty);
state.add_balance(t.sender().as_ref().unwrap(), &100.into()); state.add_balance(t.sender().as_ref().unwrap(), &100.into(), CleanupMode::NoEmpty);
let result = state.apply(&info, &engine, &t, true).unwrap(); let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace { let expected_trace = vec![FlatTrace {
trace_address: Default::default(), trace_address: Default::default(),
@ -1658,7 +1680,7 @@ fn get_from_database() {
let (root, db) = { let (root, db) = {
let mut state = get_temp_state_in(temp.as_path()); let mut state = get_temp_state_in(temp.as_path());
state.inc_nonce(&a); state.inc_nonce(&a);
state.add_balance(&a, &U256::from(69u64)); state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty);
state.commit().unwrap(); state.commit().unwrap();
assert_eq!(state.balance(&a), U256::from(69u64)); assert_eq!(state.balance(&a), U256::from(69u64));
state.drop() state.drop()
@ -1675,27 +1697,47 @@ fn remove() {
let mut state_result = get_temp_state(); let mut state_result = get_temp_state();
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
assert_eq!(state.exists(&a), false); assert_eq!(state.exists(&a), false);
assert_eq!(state.exists_and_not_null(&a), false);
state.inc_nonce(&a); state.inc_nonce(&a);
assert_eq!(state.exists(&a), true); assert_eq!(state.exists(&a), true);
assert_eq!(state.exists_and_not_null(&a), true);
assert_eq!(state.nonce(&a), U256::from(1u64)); assert_eq!(state.nonce(&a), U256::from(1u64));
state.kill_account(&a); state.kill_account(&a);
assert_eq!(state.exists(&a), false); assert_eq!(state.exists(&a), false);
assert_eq!(state.exists_and_not_null(&a), false);
assert_eq!(state.nonce(&a), U256::from(0u64)); assert_eq!(state.nonce(&a), U256::from(0u64));
} }
#[test] #[test]
fn empty_account_exists() { fn empty_account_is_not_created() {
let a = Address::zero(); let a = Address::zero();
let path = RandomTempPath::new(); let path = RandomTempPath::new();
let db = get_temp_state_db_in(path.as_path()); let db = get_temp_state_db_in(path.as_path());
let (root, db) = { let (root, db) = {
let mut state = State::new(db, U256::from(0), Default::default()); let mut state = State::new(db, U256::from(0), Default::default());
state.add_balance(&a, &U256::default()); // create an empty account 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.commit().unwrap();
state.drop() state.drop()
}; };
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap(); let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
assert!(state.exists(&a)); assert!(state.exists(&a));
assert!(!state.exists_and_not_null(&a));
} }
#[test] #[test]
@ -1733,7 +1775,7 @@ fn alter_balance() {
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
let a = Address::zero(); let a = Address::zero();
let b = 1u64.into(); let b = 1u64.into();
state.add_balance(&a, &U256::from(69u64)); state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty);
assert_eq!(state.balance(&a), U256::from(69u64)); assert_eq!(state.balance(&a), U256::from(69u64));
state.commit().unwrap(); state.commit().unwrap();
assert_eq!(state.balance(&a), U256::from(69u64)); assert_eq!(state.balance(&a), U256::from(69u64));
@ -1741,7 +1783,7 @@ fn alter_balance() {
assert_eq!(state.balance(&a), U256::from(27u64)); assert_eq!(state.balance(&a), U256::from(27u64));
state.commit().unwrap(); state.commit().unwrap();
assert_eq!(state.balance(&a), U256::from(27u64)); assert_eq!(state.balance(&a), U256::from(27u64));
state.transfer_balance(&a, &b, &U256::from(18u64)); state.transfer_balance(&a, &b, &U256::from(18u64), CleanupMode::NoEmpty);
assert_eq!(state.balance(&a), U256::from(9u64)); assert_eq!(state.balance(&a), U256::from(9u64));
assert_eq!(state.balance(&b), U256::from(18u64)); assert_eq!(state.balance(&b), U256::from(18u64));
state.commit().unwrap(); state.commit().unwrap();
@ -1794,12 +1836,12 @@ fn checkpoint_basic() {
let mut state = state_result.reference_mut(); let mut state = state_result.reference_mut();
let a = Address::zero(); let a = Address::zero();
state.checkpoint(); state.checkpoint();
state.add_balance(&a, &U256::from(69u64)); state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty);
assert_eq!(state.balance(&a), U256::from(69u64)); assert_eq!(state.balance(&a), U256::from(69u64));
state.discard_checkpoint(); state.discard_checkpoint();
assert_eq!(state.balance(&a), U256::from(69u64)); assert_eq!(state.balance(&a), U256::from(69u64));
state.checkpoint(); state.checkpoint();
state.add_balance(&a, &U256::from(1u64)); state.add_balance(&a, &U256::from(1u64), CleanupMode::NoEmpty);
assert_eq!(state.balance(&a), U256::from(70u64)); assert_eq!(state.balance(&a), U256::from(70u64));
state.revert_to_checkpoint(); state.revert_to_checkpoint();
assert_eq!(state.balance(&a), U256::from(69u64)); assert_eq!(state.balance(&a), U256::from(69u64));
@ -1812,7 +1854,7 @@ fn checkpoint_nested() {
let a = Address::zero(); let a = Address::zero();
state.checkpoint(); state.checkpoint();
state.checkpoint(); state.checkpoint();
state.add_balance(&a, &U256::from(69u64)); state.add_balance(&a, &U256::from(69u64), CleanupMode::NoEmpty);
assert_eq!(state.balance(&a), U256::from(69u64)); assert_eq!(state.balance(&a), U256::from(69u64));
state.discard_checkpoint(); state.discard_checkpoint();
assert_eq!(state.balance(&a), U256::from(69u64)); assert_eq!(state.balance(&a), U256::from(69u64));
@ -1835,7 +1877,7 @@ fn should_not_panic_on_state_diff_with_storage() {
let a: Address = 0xa.into(); let a: Address = 0xa.into();
state.init_code(&a, b"abcdefg".to_vec()); state.init_code(&a, b"abcdefg".to_vec());
state.add_balance(&a, &256.into()); state.add_balance(&a, &256.into(), CleanupMode::NoEmpty);
state.set_storage(&a, 0xb.into(), 0xc.into()); state.set_storage(&a, 0xb.into(), 0xc.into());
let mut new_state = state.clone(); let mut new_state = state.clone();

View File

@ -18,6 +18,8 @@
use std::collections::HashSet; use std::collections::HashSet;
use util::{Address, U256}; use util::{Address, U256};
use log_entry::LogEntry; use log_entry::LogEntry;
use evm::Schedule;
use super::CleanupMode;
/// State changes which should be applied in finalize, /// State changes which should be applied in finalize,
/// after transaction is fully executed. /// after transaction is fully executed.
@ -26,6 +28,9 @@ pub struct Substate {
/// Any accounts that have suicided. /// Any accounts that have suicided.
pub suicides: HashSet<Address>, pub suicides: HashSet<Address>,
/// Any accounts that are tagged for garbage collection.
pub garbage: HashSet<Address>,
/// Any logs. /// Any logs.
pub logs: Vec<LogEntry>, pub logs: Vec<LogEntry>,
@ -45,10 +50,20 @@ impl Substate {
/// Merge secondary substate `s` into self, accruing each element correspondingly. /// Merge secondary substate `s` into self, accruing each element correspondingly.
pub fn accrue(&mut self, s: Substate) { pub fn accrue(&mut self, s: Substate) {
self.suicides.extend(s.suicides.into_iter()); self.suicides.extend(s.suicides.into_iter());
self.garbage.extend(s.garbage.into_iter());
self.logs.extend(s.logs.into_iter()); self.logs.extend(s.logs.into_iter());
self.sstore_clears_count = self.sstore_clears_count + s.sstore_clears_count; self.sstore_clears_count = self.sstore_clears_count + s.sstore_clears_count;
self.contracts_created.extend(s.contracts_created.into_iter()); self.contracts_created.extend(s.contracts_created.into_iter());
} }
/// Get the cleanup mode object from this.
pub fn to_cleanup_mode(&mut self, schedule: &Schedule) -> CleanupMode {
match (schedule.no_empty, schedule.kill_empty) {
(false, _) => CleanupMode::ForceCreate,
(true, false) => CleanupMode::NoEmpty,
(true, true) => CleanupMode::KillEmpty(&mut self.garbage),
}
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -165,13 +165,13 @@ impl StateDB {
bloom bloom
} }
pub fn check_account_bloom(&self, address: &Address) -> bool { pub fn check_non_null_bloom(&self, address: &Address) -> bool {
trace!(target: "account_bloom", "Check account bloom: {:?}", address); trace!(target: "account_bloom", "Check account bloom: {:?}", address);
let bloom = self.account_bloom.lock(); let bloom = self.account_bloom.lock();
bloom.check(&*address.sha3()) bloom.check(&*address.sha3())
} }
pub fn note_account_bloom(&self, address: &Address) { pub fn note_non_null_account(&self, address: &Address) {
trace!(target: "account_bloom", "Note account bloom: {:?}", address); trace!(target: "account_bloom", "Note account bloom: {:?}", address);
let mut bloom = self.account_bloom.lock(); let mut bloom = self.account_bloom.lock();
bloom.set(&*address.sha3()); bloom.set(&*address.sha3());

View File

@ -16,6 +16,7 @@
use io::IoChannel; use io::IoChannel;
use client::{BlockChainClient, MiningBlockChainClient, Client, ClientConfig, BlockID}; use client::{BlockChainClient, MiningBlockChainClient, Client, ClientConfig, BlockID};
use state::CleanupMode;
use ethereum; use ethereum;
use block::IsBlock; use block::IsBlock;
use tests::helpers::*; use tests::helpers::*;
@ -217,7 +218,7 @@ fn can_generate_gas_price_histogram() {
let client = client_result.reference(); let client = client_result.reference();
let hist = client.gas_price_histogram(20, 5).unwrap(); let hist = client.gas_price_histogram(20, 5).unwrap();
let correct_hist = Histogram { bucket_bounds: vec_into![643,2293,3943,5593,7243,8893], counts: vec![4,2,4,6,3] }; let correct_hist = Histogram { bucket_bounds: vec_into![643, 2294, 3945, 5596, 7247, 8898], counts: vec![4,2,4,6,4] };
assert_eq!(hist, correct_hist); assert_eq!(hist, correct_hist);
} }
@ -272,7 +273,7 @@ fn change_history_size() {
let client = Client::new(ClientConfig::default(), &test_spec, dir.as_path(), Arc::new(Miner::with_spec(&test_spec)), IoChannel::disconnected(), &db_config).unwrap(); let client = Client::new(ClientConfig::default(), &test_spec, dir.as_path(), Arc::new(Miner::with_spec(&test_spec)), IoChannel::disconnected(), &db_config).unwrap();
for _ in 0..20 { for _ in 0..20 {
let mut b = client.prepare_open_block(Address::default(), (3141562.into(), 31415620.into()), vec![]); let mut b = client.prepare_open_block(Address::default(), (3141562.into(), 31415620.into()), vec![]);
b.block_mut().fields_mut().state.add_balance(&address, &5.into()); b.block_mut().fields_mut().state.add_balance(&address, &5.into(), CleanupMode::NoEmpty);
b.block_mut().fields_mut().state.commit().unwrap(); b.block_mut().fields_mut().state.commit().unwrap();
let b = b.close_and_lock().seal(&*test_spec.engine, vec![]).unwrap(); let b = b.close_and_lock().seal(&*test_spec.engine, vec![]).unwrap();
client.import_sealed_block(b).unwrap(); // account change is in the journal overlay client.import_sealed_block(b).unwrap(); // account change is in the journal overlay

View File

@ -39,6 +39,7 @@ pub enum ChainEra {
Frontier, Frontier,
Homestead, Homestead,
Eip150, Eip150,
Eip161,
TransitionTest, TransitionTest,
} }
@ -193,7 +194,7 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
action: Action::Create, action: Action::Create,
data: vec![], data: vec![],
value: U256::zero(), value: U256::zero(),
}.sign(kp.secret()), None).unwrap(); }.sign(kp.secret(), None), None).unwrap();
n += 1; n += 1;
} }

View File

@ -93,6 +93,10 @@ pub struct RichReceipt {
pub contract_address: Option<Address>, pub contract_address: Option<Address>,
/// Logs /// Logs
pub logs: Vec<LogEntry>, pub logs: Vec<LogEntry>,
/// Logs bloom
pub log_bloom: LogBloom,
/// State root
pub state_root: H256,
} }
/// Receipt with additional info. /// Receipt with additional info.
@ -114,6 +118,10 @@ pub struct LocalizedReceipt {
pub contract_address: Option<Address>, pub contract_address: Option<Address>,
/// Logs /// Logs
pub logs: Vec<LocalizedLogEntry>, pub logs: Vec<LocalizedLogEntry>,
/// Logs bloom
pub log_bloom: LogBloom,
/// State root
pub state_root: H256,
} }
#[test] #[test]

View File

@ -72,8 +72,8 @@ pub struct Transaction {
impl Transaction { impl Transaction {
/// Append object with a without signature into RLP stream /// Append object with a without signature into RLP stream
pub fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream) { pub fn rlp_append_unsigned_transaction(&self, s: &mut RlpStream, network_id: Option<u8>) {
s.begin_list(6); s.begin_list(if let None = network_id { 6 } else { 9 });
s.append(&self.nonce); s.append(&self.nonce);
s.append(&self.gas_price); s.append(&self.gas_price);
s.append(&self.gas); s.append(&self.gas);
@ -83,6 +83,11 @@ impl Transaction {
}; };
s.append(&self.value); s.append(&self.value);
s.append(&self.data); s.append(&self.data);
if let Some(n) = network_id {
s.append(&n);
s.append(&0u8);
s.append(&0u8);
}
} }
} }
@ -105,7 +110,7 @@ impl From<ethjson::state::Transaction> for SignedTransaction {
}, },
value: t.value.into(), value: t.value.into(),
data: t.data.into(), data: t.data.into(),
}.sign(&t.secret.into()) }.sign(&t.secret.into(), None)
} }
} }
@ -135,26 +140,26 @@ impl From<ethjson::transaction::Transaction> for SignedTransaction {
impl Transaction { impl Transaction {
/// The message hash of the transaction. /// The message hash of the transaction.
pub fn hash(&self) -> H256 { pub fn hash(&self, network_id: Option<u8>) -> H256 {
let mut stream = RlpStream::new(); let mut stream = RlpStream::new();
self.rlp_append_unsigned_transaction(&mut stream); self.rlp_append_unsigned_transaction(&mut stream, network_id);
stream.out().sha3() stream.out().sha3()
} }
/// Signs the transaction as coming from `sender`. /// Signs the transaction as coming from `sender`.
pub fn sign(self, secret: &Secret) -> SignedTransaction { pub fn sign(self, secret: &Secret, network_id: Option<u8>) -> SignedTransaction {
let sig = ::ethkey::sign(secret, &self.hash()) let sig = ::ethkey::sign(secret, &self.hash(network_id))
.expect("data is valid and context has signing capabilities; qed"); .expect("data is valid and context has signing capabilities; qed");
self.with_signature(sig) self.with_signature(sig, network_id)
} }
/// Signs the transaction with signature. /// Signs the transaction with signature.
pub fn with_signature(self, sig: Signature) -> SignedTransaction { pub fn with_signature(self, sig: Signature, network_id: Option<u8>) -> SignedTransaction {
SignedTransaction { SignedTransaction {
unsigned: self, unsigned: self,
r: sig.r().into(), r: sig.r().into(),
s: sig.s().into(), s: sig.s().into(),
v: sig.v() + 27, v: sig.v() + if let Some(n) = network_id { 1 + n * 2 } else { 27 },
hash: Cell::new(None), hash: Cell::new(None),
sender: Cell::new(None), sender: Cell::new(None),
} }
@ -204,7 +209,8 @@ impl Transaction {
pub struct SignedTransaction { pub struct SignedTransaction {
/// Plain Transaction. /// Plain Transaction.
unsigned: Transaction, unsigned: Transaction,
/// The V field of the signature, either 27 or 28; helps describe the point on the curve. /// 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: u8,
/// The R field of the signature; helps describe the point on the curve. /// The R field of the signature; helps describe the point on the curve.
r: U256, r: U256,
@ -266,7 +272,7 @@ impl HeapSizeOf for SignedTransaction {
impl SignedTransaction { impl SignedTransaction {
/// Append object with a signature into RLP stream /// Append object with a signature into RLP stream
pub fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) { fn rlp_append_sealed_transaction(&self, s: &mut RlpStream) {
s.begin_list(9); s.begin_list(9);
s.append(&self.nonce); s.append(&self.nonce);
s.append(&self.gas_price); s.append(&self.gas_price);
@ -295,8 +301,16 @@ impl SignedTransaction {
} }
} }
/// 0 is `v` is 27, 1 if 28, and 4 otherwise. /// 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 { 27 => 0, 28 => 1, _ => 4 } } pub fn standard_v(&self) -> u8 { match self.v { 0 => 4, v => (v - 1) & 1, } }
/// The network ID, or `None` if this is a global transaction.
pub fn network_id(&self) -> Option<u8> {
match self.v {
0 | 27 | 28 => None,
v => Some((v - 1) / 2),
}
}
/// Construct a signature object from the sig. /// Construct a signature object from the sig.
pub fn signature(&self) -> Signature { pub fn signature(&self) -> Signature {
@ -327,20 +341,25 @@ impl SignedTransaction {
/// Returns the public key of the sender. /// Returns the public key of the sender.
pub fn public_key(&self) -> Result<Public, Error> { pub fn public_key(&self) -> Result<Public, Error> {
Ok(try!(recover(&self.signature(), &self.unsigned.hash()))) Ok(try!(recover(&self.signature(), &self.unsigned.hash(self.network_id()))))
} }
/// Do basic validation, checking for valid signature and minimum gas, /// Do basic validation, checking for valid signature and minimum gas,
// TODO: consider use in block validation. // TODO: consider use in block validation.
#[cfg(test)] #[cfg(test)]
#[cfg(feature = "json-tests")] #[cfg(feature = "json-tests")]
pub fn validate(self, schedule: &Schedule, require_low: bool) -> Result<SignedTransaction, Error> { pub fn validate(self, schedule: &Schedule, require_low: bool, allow_network_id_of_one: bool) -> Result<SignedTransaction, Error> {
if require_low && !self.signature().is_low_s() { if require_low && !self.signature().is_low_s() {
return Err(EthkeyError::InvalidSignature.into()) return Err(EthkeyError::InvalidSignature.into())
} }
match self.network_id() {
None => {},
Some(1) if allow_network_id_of_one => {},
_ => return Err(TransactionError::InvalidNetworkId.into()),
}
try!(self.sender()); try!(self.sender());
if self.gas < U256::from(self.gas_required(&schedule)) { if self.gas < U256::from(self.gas_required(&schedule)) {
Err(From::from(TransactionError::InvalidGasLimit(::util::OutOfBounds{min: Some(U256::from(self.gas_required(&schedule))), max: None, found: self.gas}))) Err(TransactionError::InvalidGasLimit(::util::OutOfBounds{min: Some(U256::from(self.gas_required(&schedule))), max: None, found: self.gas}).into())
} else { } else {
Ok(self) Ok(self)
} }
@ -380,6 +399,7 @@ fn sender_test() {
} else { panic!(); } } else { panic!(); }
assert_eq!(t.value, U256::from(0x0au64)); assert_eq!(t.value, U256::from(0x0au64));
assert_eq!(t.sender().unwrap(), "0f65fe9276bc9a24ae7083ae28e2660ef72df99e".into()); assert_eq!(t.sender().unwrap(), "0f65fe9276bc9a24ae7083ae28e2660ef72df99e".into());
assert_eq!(t.network_id(), None);
} }
#[test] #[test]
@ -394,8 +414,9 @@ fn signing() {
gas: U256::from(50_000), gas: U256::from(50_000),
value: U256::from(1), value: U256::from(1),
data: b"Hello!".to_vec() data: b"Hello!".to_vec()
}.sign(&key.secret()); }.sign(&key.secret(), None);
assert_eq!(Address::from(key.public().sha3()), t.sender().unwrap()); assert_eq!(Address::from(key.public().sha3()), t.sender().unwrap());
assert_eq!(t.network_id(), None);
} }
#[test] #[test]
@ -409,7 +430,47 @@ fn fake_signing() {
data: b"Hello!".to_vec() data: b"Hello!".to_vec()
}.fake_sign(Address::from(0x69)); }.fake_sign(Address::from(0x69));
assert_eq!(Address::from(0x69), t.sender().unwrap()); assert_eq!(Address::from(0x69), t.sender().unwrap());
assert_eq!(t.network_id(), None);
let t = t.clone(); let t = t.clone();
assert_eq!(Address::from(0x69), t.sender().unwrap()); assert_eq!(Address::from(0x69), t.sender().unwrap());
assert_eq!(t.network_id(), None);
}
#[test]
fn should_recover_from_network_specific_signing() {
use ethkey::{Random, Generator};
let key = Random.generate().unwrap();
let t = Transaction {
action: Action::Create,
nonce: U256::from(42),
gas_price: U256::from(3000),
gas: U256::from(50_000),
value: U256::from(1),
data: b"Hello!".to_vec()
}.sign(&key.secret(), Some(69));
assert_eq!(Address::from(key.public().sha3()), t.sender().unwrap());
assert_eq!(t.network_id(), Some(69));
}
#[test]
fn should_agree_with_vitalik() {
use rustc_serialize::hex::FromHex;
use std::str::FromStr;
let test_vector = |tx_data: &str, address: &'static str| {
let signed: SignedTransaction = decode(&FromHex::from_hex(tx_data).unwrap());
assert_eq!(signed.sender().unwrap(), address.into());
};
test_vector("f864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", "0xda39a520355857fdb37ecb527fe814230fa9962c");
test_vector("f864018504a817c80182a410943535353535353535353535353535353535353535018025a0c89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc8a0c89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", "0xd240215f30eafee2aaa5184d8f051ebb41c90b19");
test_vector("f864028504a817c80282f618943535353535353535353535353535353535353535088025a0ad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a8a0ad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", "0x2f2822c55d894df1ba32961c43325dcb3d614ee8");
test_vector("f865038504a817c803830148209435353535353535353535353535353535353535351b8025a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", "0xc21df0434ceab6e18a1300d18206e54e807b4456");
test_vector("f865048504a817c80483019a28943535353535353535353535353535353535353535408025a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", "0xf975cee81edae2ab5883f4e2fb2a7f2fd56f4131");
test_vector("f865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a0ceebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a0ceebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", "0xd477474c9f48dcbfde5d97f30646242ab7a17e06");
test_vector("f866068504a817c80683023e3894353535353535353535353535353535353535353581d88025a0e455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2da0e455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", "0xb49948deb719ca21e38d29e3360f534b39db0e76");
test_vector("f867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", "0xbddfc81a8ce87b2360837049a6eda68ab2f58999");
test_vector("f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a0e4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c11a0e4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", "0x8f2edcf67f329a146dd4cb1e6b3a072daff85b38");
test_vector("f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a0d2f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba0d2f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", "0x4ec38d4782fd4a6ff85c1cde77ccf1ae3c54472c");
} }

View File

@ -395,7 +395,7 @@ mod tests {
gas: U256::from(30_000), gas: U256::from(30_000),
gas_price: U256::from(40_000), gas_price: U256::from(40_000),
nonce: U256::one() nonce: U256::one()
}.sign(keypair.secret()); }.sign(keypair.secret(), None);
let tr2 = Transaction { let tr2 = Transaction {
action: Action::Create, action: Action::Create,
@ -404,7 +404,7 @@ mod tests {
gas: U256::from(30_000), gas: U256::from(30_000),
gas_price: U256::from(40_000), gas_price: U256::from(40_000),
nonce: U256::from(2) nonce: U256::from(2)
}.sign(keypair.secret()); }.sign(keypair.secret(), None);
let good_transactions = [ tr1.clone(), tr2.clone() ]; let good_transactions = [ tr1.clone(), tr2.clone() ];

View File

@ -51,6 +51,14 @@ impl Ext for FakeExt {
unimplemented!(); unimplemented!();
} }
fn exists_and_not_null(&self, address: &Address) -> bool {
unimplemented!();
}
fn origin_balance(&self) -> U256 {
unimplemented!();
}
fn balance(&self, _address: &Address) -> U256 { fn balance(&self, _address: &Address) -> U256 {
unimplemented!(); unimplemented!();
} }

View File

@ -13,6 +13,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
// test only
/** /**
* Run `PARITY_URL="127.0.0.1:8180" NODE_ENV="production" npm run build` * Run `PARITY_URL="127.0.0.1:8180" NODE_ENV="production" npm run build`

View File

@ -1,6 +1,6 @@
{ {
"name": "parity.js", "name": "parity.js",
"version": "0.1.47", "version": "0.1.61",
"main": "release/index.js", "main": "release/index.js",
"jsnext:main": "src/index.js", "jsnext:main": "src/index.js",
"author": "Parity Team <admin@parity.io>", "author": "Parity Team <admin@parity.io>",

View File

@ -50,20 +50,11 @@ setup_git_user
git remote set-url origin $GIT_PARITY git remote set-url origin $GIT_PARITY
git reset --hard origin/$BRANCH 2>$GITLOG git reset --hard origin/$BRANCH 2>$GITLOG
echo "*** Bumping package.json patch version" if [ "$BRANCH" == "master" ]; then
cd js cd js
echo "*** Bumping package.json patch version"
npm --no-git-tag-version version npm --no-git-tag-version version
npm version patch npm version patch
cd ..
echo "*** Updating cargo parity-ui-precompiled#$PRECOMPILED_HASH"
cargo update -p parity-ui-precompiled
# --precise "$PRECOMPILED_HASH"
echo "*** Committing updated files"
git add Cargo.lock js/package.json
git commit -m "[ci skip] js-precompiled $UTCDATE"
git push origin HEAD:refs/heads/$BRANCH 2>$GITLOG
echo "*** Building packages for npmjs" echo "*** Building packages for npmjs"
cd js cd js
@ -75,6 +66,16 @@ echo "*** Publishing $PACKAGE to npmjs"
cd .npmjs cd .npmjs
npm publish --access public npm publish --access public
cd .. cd ..
fi
echo "*** Updating cargo parity-ui-precompiled#$PRECOMPILED_HASH"
cargo update -p parity-ui-precompiled
# --precise "$PRECOMPILED_HASH"
echo "*** Committing updated files"
git add .
git commit -m "[ci skip] js-precompiled $UTCDATE"
git push origin HEAD:refs/heads/$BRANCH 2>$GITLOG
# back to root # back to root
echo "*** Release completed" echo "*** Release completed"

View File

@ -87,7 +87,8 @@ export default class Status {
setTimeout(this._pollStatus, timeout); setTimeout(this._pollStatus, timeout);
}; };
if (isConnected !== this._store.getState().nodeStatus.isConnected) { const wasConnected = this._store.getState().nodeStatus.isConnected;
if (isConnected !== wasConnected) {
this._fetchEnode(); this._fetchEnode();
} }

View File

@ -0,0 +1,75 @@
// 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 <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import { IconButton } from 'material-ui';
import Clipboard from 'react-copy-to-clipboard';
import CopyIcon from 'material-ui/svg-icons/content/content-copy';
import Theme from '../Theme';
const { textColor, disabledTextColor } = Theme.flatButton;
export default class CopyToClipboard extends Component {
static propTypes = {
data: PropTypes.string.isRequired,
label: PropTypes.string,
onCopy: PropTypes.func,
size: PropTypes.number, // in px
cooldown: PropTypes.number // in ms
};
static defaultProps = {
className: '',
label: 'copy to clipboard',
onCopy: () => {},
size: 16,
cooldown: 1000
};
state = {
copied: false
};
render () {
const { data, label, size } = this.props;
const { copied } = this.state;
return (
<Clipboard onCopy={ this.onCopy } text={ data }>
<IconButton
tooltip={ copied ? 'done!' : label }
disableTouchRipple
tooltipPosition={ 'top-right' }
tooltipStyles={ { marginTop: `-${size / 4}px` } }
style={ { width: size, height: size, padding: '0' } }
iconStyle={ { width: size, height: size } }
>
<CopyIcon color={ copied ? disabledTextColor : textColor } />
</IconButton>
</Clipboard>
);
}
onCopy = () => {
const { cooldown, onCopy } = this.props;
this.setState({ copied: true });
setTimeout(() => {
this.setState({ copied: false });
}, cooldown);
onCopy();
}
}

View File

@ -0,0 +1,17 @@
// 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 <http://www.gnu.org/licenses/>.
export default from './copyToClipboard';

View File

@ -19,12 +19,11 @@ import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import Contracts from '../../contracts';
import IdentityIcon from '../IdentityIcon'; import IdentityIcon from '../IdentityIcon';
import IdentityName from '../IdentityName'; import IdentityName from '../IdentityName';
import { Input, InputAddress } from '../Form'; import { Input, InputAddress } from '../Form';
import { fetchBytecode, fetchMethod } from '../../redux/providers/blockchainActions';
import styles from './methodDecoding.css'; import styles from './methodDecoding.css';
const CONTRACT_CREATE = '0x60606040'; const CONTRACT_CREATE = '0x60606040';
@ -41,12 +40,7 @@ class MethodDecoding extends Component {
address: PropTypes.string.isRequired, address: PropTypes.string.isRequired,
tokens: PropTypes.object, tokens: PropTypes.object,
transaction: PropTypes.object, transaction: PropTypes.object,
historic: PropTypes.bool, historic: PropTypes.bool
fetchBytecode: PropTypes.func,
fetchMethod: PropTypes.func,
bytecodes: PropTypes.object,
methods: PropTypes.object
} }
state = { state = {
@ -63,58 +57,7 @@ class MethodDecoding extends Component {
} }
componentWillMount () { componentWillMount () {
const { transaction } = this.props; this.lookup();
this.lookup(transaction);
}
componentDidMount () {
this.setMethod(this.props);
}
componentWillReceiveProps (newProps) {
const { transaction } = this.props;
this.setMethod(newProps);
if (newProps.transaction.hash !== transaction.hash) {
this.lookup(transaction);
return;
}
}
setMethod (props) {
const { bytecodes, methods } = props;
const { contractAddress, methodSignature, methodParams } = this.state;
if (contractAddress && bytecodes[contractAddress]) {
const bytecode = bytecodes[contractAddress];
if (bytecode && bytecode !== '0x') {
this.setState({ isContract: true });
}
}
if (methodSignature && methods[methodSignature]) {
const method = methods[methodSignature];
const { api } = this.context;
let methodInputs = null;
let methodName = null;
if (method && method.length) {
const abi = api.util.methodToAbi(method);
methodName = abi.name;
methodInputs = api.util
.decodeMethodInput(abi, methodParams)
.map((value, index) => {
const type = abi.inputs[index].type;
return { type, value };
});
}
this.setState({ method, methodName, methodInputs });
}
} }
render () { render () {
@ -321,7 +264,9 @@ class MethodDecoding extends Component {
); );
} }
lookup (transaction) { lookup () {
const { transaction } = this.props;
if (!transaction) { if (!transaction) {
return; return;
} }
@ -347,26 +292,51 @@ class MethodDecoding extends Component {
return; return;
} }
const { fetchBytecode, fetchMethod } = this.props; Promise
.all([
api.eth.getCode(contractAddress),
Contracts.get().signatureReg.lookup(signature)
])
.then(([bytecode, method]) => {
let methodInputs = null;
let methodName = null;
fetchBytecode(contractAddress); if (method && method.length) {
fetchMethod(signature); const { methodParams } = this.state;
const abi = api.util.methodToAbi(method);
methodName = abi.name;
methodInputs = api.util
.decodeMethodInput(abi, methodParams)
.map((value, index) => {
const type = abi.inputs[index].type;
return { type, value };
});
}
this.setState({
method,
methodName,
methodInputs,
bytecode,
isContract: bytecode && bytecode !== '0x'
});
})
.catch((error) => {
console.warn('lookup', error);
});
} }
} }
function mapStateToProps (state) { function mapStateToProps (state) {
const { tokens } = state.balances; const { tokens } = state.balances;
const { bytecodes, methods } = state.blockchain;
return { return { tokens };
tokens, bytecodes, methods
};
} }
function mapDispatchToProps (dispatch) { function mapDispatchToProps (dispatch) {
return bindActionCreators({ return bindActionCreators({}, dispatch);
fetchBytecode, fetchMethod
}, dispatch);
} }
export default connect( export default connect(

View File

@ -25,6 +25,7 @@ import Button from './Button';
import ConfirmDialog from './ConfirmDialog'; import ConfirmDialog from './ConfirmDialog';
import Container, { Title as ContainerTitle } from './Container'; import Container, { Title as ContainerTitle } from './Container';
import ContextProvider from './ContextProvider'; import ContextProvider from './ContextProvider';
import CopyToClipboard from './CopyToClipboard';
import Errors from './Errors'; import Errors from './Errors';
import Form, { AddressSelect, FormWrap, Input, InputAddress, InputAddressSelect, InputChip, InputInline, Select } from './Form'; import Form, { AddressSelect, FormWrap, Input, InputAddress, InputAddressSelect, InputChip, InputInline, Select } from './Form';
import IdentityIcon from './IdentityIcon'; import IdentityIcon from './IdentityIcon';
@ -53,6 +54,7 @@ export {
Container, Container,
ContainerTitle, ContainerTitle,
ContextProvider, ContextProvider,
CopyToClipboard,
Errors, Errors,
Form, Form,
FormWrap, FormWrap,

View File

@ -17,46 +17,37 @@
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import moment from 'moment'; import moment from 'moment';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { fetchBlock, fetchTransaction } from '../../../../redux/providers/blockchainActions';
import { IdentityIcon, IdentityName, MethodDecoding } from '../../../../ui'; import { IdentityIcon, IdentityName, MethodDecoding } from '../../../../ui';
import { txLink, addressLink } from '../../../../3rdparty/etherscan/links'; import { txLink, addressLink } from '../../../../3rdparty/etherscan/links';
import styles from '../transactions.css'; import styles from '../transactions.css';
class Transaction extends Component { export default class Transaction extends Component {
static contextTypes = { static contextTypes = {
api: PropTypes.object.isRequired api: PropTypes.object.isRequired
} }
static propTypes = { static propTypes = {
transaction: PropTypes.object.isRequired,
address: PropTypes.string.isRequired, address: PropTypes.string.isRequired,
isTest: PropTypes.bool.isRequired, isTest: PropTypes.bool.isRequired,
transaction: PropTypes.object.isRequired
fetchBlock: PropTypes.func.isRequired,
fetchTransaction: PropTypes.func.isRequired,
block: PropTypes.object,
transactionInfo: PropTypes.object
} }
state = { state = {
isContract: false, isContract: false,
isReceived: false isReceived: false,
transaction: null,
block: null
} }
componentDidMount () { componentDidMount () {
const { address, transaction } = this.props; this.lookup();
this.lookup(address, transaction);
} }
render () { render () {
const { block, transaction } = this.props; const { block } = this.state;
const { transaction } = this.props;
return ( return (
<tr> <tr>
@ -75,9 +66,10 @@ class Transaction extends Component {
} }
renderMethod () { renderMethod () {
const { address, transactionInfo } = this.props; const { address } = this.props;
const { transaction } = this.state;
if (!transactionInfo) { if (!transaction) {
return null; return null;
} }
@ -85,12 +77,13 @@ class Transaction extends Component {
<MethodDecoding <MethodDecoding
historic historic
address={ address } address={ address }
transaction={ transactionInfo } /> transaction={ transaction } />
); );
} }
renderTransaction () { renderTransaction () {
const { transaction, isTest } = this.props; const { isTest } = this.props;
const { transaction } = this.props;
return ( return (
<td className={ styles.transaction }> <td className={ styles.transaction }>
@ -138,13 +131,13 @@ class Transaction extends Component {
renderEtherValue () { renderEtherValue () {
const { api } = this.context; const { api } = this.context;
const { transactionInfo } = this.props; const { transaction } = this.state;
if (!transactionInfo) { if (!transaction) {
return null; return null;
} }
const value = api.util.fromWei(transactionInfo.value); const value = api.util.fromWei(transaction.value);
if (value.eq(0)) { if (value.eq(0)) {
return <div className={ styles.value }>{ ' ' }</div>; return <div className={ styles.value }>{ ' ' }</div>;
@ -177,34 +170,22 @@ class Transaction extends Component {
return moment(block.timestamp).fromNow(); return moment(block.timestamp).fromNow();
} }
lookup (address, transaction) { lookup () {
const { transactionInfo } = this.props; const { api } = this.context;
const { transaction, address } = this.props;
if (transactionInfo) {
return;
}
this.setState({ isReceived: address === transaction.to }); this.setState({ isReceived: address === transaction.to });
const { fetchBlock, fetchTransaction } = this.props; Promise
const { blockNumber, hash } = transaction; .all([
api.eth.getBlockByNumber(transaction.blockNumber),
fetchBlock(blockNumber); api.eth.getTransactionByHash(transaction.hash)
fetchTransaction(hash); ])
.then(([block, transaction]) => {
this.setState({ block, transaction });
})
.catch((error) => {
console.warn('lookup', error);
});
} }
} }
function mapStateToProps () {
return {};
}
function mapDispatchToProps (dispatch) {
return bindActionCreators({
fetchBlock, fetchTransaction
}, dispatch);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Transaction);

View File

@ -38,9 +38,7 @@ class Transactions extends Component {
contracts: PropTypes.object, contracts: PropTypes.object,
tokens: PropTypes.object, tokens: PropTypes.object,
isTest: PropTypes.bool, isTest: PropTypes.bool,
traceMode: PropTypes.bool, traceMode: PropTypes.bool
blocks: PropTypes.object,
transactionsInfo: PropTypes.object
} }
state = { state = {
@ -121,7 +119,7 @@ class Transactions extends Component {
} }
renderRows () { renderRows () {
const { address, accounts, contacts, contracts, tokens, isTest, blocks, transactionsInfo } = this.props; const { address, accounts, contacts, contracts, tokens, isTest } = this.props;
const { transactions } = this.state; const { transactions } = this.state;
return (transactions || []) return (transactions || [])
@ -130,16 +128,9 @@ class Transactions extends Component {
}) })
.slice(0, 25) .slice(0, 25)
.map((transaction, index) => { .map((transaction, index) => {
const { blockNumber, hash } = transaction;
const block = blocks[blockNumber.toString()];
const transactionInfo = transactionsInfo[hash];
return ( return (
<Transaction <Transaction
key={ index } key={ index }
block={ block }
transactionInfo={ transactionInfo }
transaction={ transaction } transaction={ transaction }
address={ address } address={ address }
accounts={ accounts } accounts={ accounts }
@ -165,9 +156,9 @@ class Transactions extends Component {
} }
fetchTransactions = (isTest, address, traceMode) => { fetchTransactions = (isTest, address, traceMode) => {
if (traceMode) { // if (traceMode) {
return this.fetchTraceTransactions(address); // return this.fetchTraceTransactions(address);
} // }
return this.fetchEtherscanTransactions(isTest, address); return this.fetchEtherscanTransactions(isTest, address);
} }
@ -211,7 +202,6 @@ function mapStateToProps (state) {
const { isTest, traceMode } = state.nodeStatus; const { isTest, traceMode } = state.nodeStatus;
const { accounts, contacts, contracts } = state.personal; const { accounts, contacts, contracts } = state.personal;
const { tokens } = state.balances; const { tokens } = state.balances;
const { blocks, transactions } = state.blockchain;
return { return {
isTest, isTest,
@ -219,9 +209,7 @@ function mapStateToProps (state) {
accounts, accounts,
contacts, contacts,
contracts, contracts,
tokens, tokens
blocks,
transactionsInfo: transactions
}; };
} }

View File

@ -15,12 +15,10 @@
/* along with Parity. If not, see <http://www.gnu.org/licenses/>. /* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/ */
.status { .status {
padding: 1.5em; padding: 0.5em;
text-align: right; font-size: x-small;
color: #ddd; color: #ccc;
display: flex; background-color: rgba(0, 0, 0, 0.2)
flex-direction: column;
align-items: flex-end;
} }
.title { .title {
@ -28,9 +26,14 @@
} }
.enode { .enode {
width: 45em;
word-wrap: break-word; word-wrap: break-word;
margin: 0.5em 0 0.25em; float: right;
}
.enode > * {
display: inline-block;
margin: 0.25em 0.5em;
vertical-align: top;
} }
.block { .block {
@ -39,9 +42,7 @@
.netinfo { .netinfo {
display: flex; display: flex;
align-items: center; align-items: center;
flex-direction: row; color: #ddd;
justify-content: flex-end;
margin-top: 0.25em;
} }
.netinfo > * { .netinfo > * {
@ -69,6 +70,8 @@
} }
.version { .version {
padding: 0.25em 0.5em;
float: left;
} }
.syncing { .syncing {

View File

@ -19,6 +19,7 @@ import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import { BlockStatus } from '../../../ui'; import { BlockStatus } from '../../../ui';
import CopyToClipboard from '../../../ui/CopyToClipboard';
import styles from './status.css'; import styles from './status.css';
@ -47,15 +48,13 @@ class Status extends Component {
</div> </div>
{ this.renderEnode() } { this.renderEnode() }
<div className={ styles.netinfo }> <div className={ styles.netinfo }>
<div>
<BlockStatus /> <BlockStatus />
<div className={ styles.peers }>
{ netPeers.active.toFormat() }/{ netPeers.connected.toFormat() }/{ netPeers.max.toFormat() } peers
</div>
</div>
<div className={ netStyle }> <div className={ netStyle }>
{ isTest ? 'test' : netChain } { isTest ? 'test' : netChain }
</div> </div>
<div className={ styles.peers }>
{ netPeers.active.toFormat() }/{ netPeers.connected.toFormat() }/{ netPeers.max.toFormat() } peers
</div>
</div> </div>
</div> </div>
); );
@ -68,9 +67,14 @@ class Status extends Component {
return null; return null;
} }
const [protocol, rest] = enode.split('://');
const [id, host] = rest.split('@');
const abbreviated = `${protocol}://${id.slice(0, 3)}${id.slice(-3)}@${host}`;
return ( return (
<div className={ styles.enode }> <div className={ styles.enode }>
{ enode } <CopyToClipboard data={ enode } />
<div>{ abbreviated }</div>
</div> </div>
); );
} }

View File

@ -149,15 +149,15 @@ class TabBar extends Component {
} }
renderStatusLabel = (label) => { renderStatusLabel = (label) => {
const { isTest, netChain } = this.props; // const { isTest, netChain } = this.props;
const bubble = ( // const bubble = (
<Badge // <Badge
color={ isTest ? 'red' : 'default' } // color={ isTest ? 'red' : 'default' }
className={ styles.labelBubble } // className={ styles.labelBubble }
value={ isTest ? 'TEST' : netChain } /> // value={ isTest ? 'TEST' : netChain } />
); // );
return this.renderLabel(label, bubble); return this.renderLabel(label, null);
} }
onActivate = (activeRoute) => { onActivate = (activeRoute) => {

View File

@ -17,27 +17,24 @@
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import moment from 'moment'; import moment from 'moment';
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { fetchBlock, fetchTransaction } from '../../../../redux/providers/blockchainActions';
import { IdentityIcon, IdentityName, Input, InputAddress } from '../../../../ui'; import { IdentityIcon, IdentityName, Input, InputAddress } from '../../../../ui';
import { txLink } from '../../../../3rdparty/etherscan/links'; import { txLink } from '../../../../3rdparty/etherscan/links';
import styles from '../../contract.css'; import styles from '../../contract.css';
class Event extends Component { export default class Event extends Component {
static contextTypes = { static contextTypes = {
api: PropTypes.object.isRequired api: PropTypes.object.isRequired
} }
static propTypes = { static propTypes = {
event: PropTypes.object.isRequired, event: PropTypes.object.isRequired,
blocks: PropTypes.object, isTest: PropTypes.bool
transactions: PropTypes.object, }
isTest: PropTypes.bool,
fetchBlock: PropTypes.func.isRequired, state = {
fetchTransaction: PropTypes.func.isRequired transaction: {}
} }
componentDidMount () { componentDidMount () {
@ -45,10 +42,9 @@ class Event extends Component {
} }
render () { render () {
const { event, blocks, transactions, isTest } = this.props; const { event, isTest } = this.props;
const { block, transaction } = this.state;
const block = blocks[event.blockNumber.toString()];
const transaction = transactions[event.transactionHash] || {};
const classes = `${styles.event} ${styles[event.state]}`; const classes = `${styles.event} ${styles[event.state]}`;
const url = txLink(event.transactionHash, isTest); const url = txLink(event.transactionHash, isTest);
const keys = Object.keys(event.params).join(', '); const keys = Object.keys(event.params).join(', ');
@ -156,31 +152,19 @@ class Event extends Component {
} }
retrieveTransaction () { retrieveTransaction () {
const { event, fetchBlock, fetchTransaction } = this.props; const { api } = this.context;
const { event } = this.props;
fetchBlock(event.blockNumber); Promise
fetchTransaction(event.transactionHash); .all([
api.eth.getBlockByNumber(event.blockNumber),
api.eth.getTransactionByHash(event.transactionHash)
])
.then(([block, transaction]) => {
this.setState({ block, transaction });
})
.catch((error) => {
console.warn('retrieveTransaction', error);
});
} }
} }
function mapStateToProps (state) {
const { isTest } = state.nodeStatus;
const { blocks, transactions } = state.blockchain;
return {
isTest,
blocks,
transactions
};
}
function mapDispatchToProps (dispatch) {
return bindActionCreators({
fetchBlock, fetchTransaction
}, dispatch);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Event);

View File

@ -27,21 +27,31 @@ export default class Events extends Component {
} }
static propTypes = { static propTypes = {
events: PropTypes.array events: PropTypes.array,
isTest: PropTypes.bool.isRequired
} }
render () { render () {
const { events } = this.props; const { events, isTest } = this.props;
if (!events || !events.length) { if (!events || !events.length) {
return null; return null;
} }
const list = events.map((event) => {
return (
<Event
key={ event.key }
event={ event }
isTest={ isTest } />
);
});
return ( return (
<Container> <Container>
<ContainerTitle title='events' /> <ContainerTitle title='events' />
<table className={ styles.events }> <table className={ styles.events }>
<tbody>{ events.map((event) => <Event event={ event } key={ event.key } />) }</tbody> <tbody>{ list }</tbody>
</table> </table>
</Container> </Container>
); );

View File

@ -116,6 +116,7 @@ class Contract extends Component {
contract={ contract } contract={ contract }
values={ queryValues } /> values={ queryValues } />
<Events <Events
isTest={ isTest }
events={ allEvents } /> events={ allEvents } />
</Page> </Page>
</div> </div>

View File

@ -70,6 +70,21 @@ pub struct EthashParams {
/// See main EthashParams docs. /// See main EthashParams docs.
#[serde(rename="eip150Transition")] #[serde(rename="eip150Transition")]
pub eip150_transition: Option<Uint>, pub eip150_transition: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="eip155Transition")]
pub eip155_transition: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="eip160Transition")]
pub eip160_transition: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="eip161abcTransition")]
pub eip161abc_transition: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="eip161dTransition")]
pub eip161d_transition: Option<Uint>,
} }
/// Ethash engine deserialization. /// Ethash engine deserialization.
@ -122,7 +137,11 @@ mod tests {
"difficultyHardforkTransition": "0x59d9", "difficultyHardforkTransition": "0x59d9",
"difficultyHardforkBoundDivisor": "0x0200", "difficultyHardforkBoundDivisor": "0x0200",
"bombDefuseTransition": "0x42", "bombDefuseTransition": "0x42",
"eip150Transition": "0x42" "eip150Transition": "0x42",
"eip155Transition": "0x42",
"eip160Transition": "0x42",
"eip161abcTransition": "0x42",
"eip161dTransition": "0x42"
} }
}"#; }"#;

View File

@ -28,15 +28,17 @@ pub struct Params {
/// Maximum size of extra data. /// Maximum size of extra data.
#[serde(rename="maximumExtraDataSize")] #[serde(rename="maximumExtraDataSize")]
pub maximum_extra_data_size: Uint, pub maximum_extra_data_size: Uint,
/// Minimum gas limit.
#[serde(rename="minGasLimit")]
pub min_gas_limit: Uint,
/// Network id. /// Network id.
#[serde(rename="networkID")] #[serde(rename="networkID")]
pub network_id: Uint, pub network_id: Uint,
/// Name of the main ("eth") subprotocol. /// Name of the main ("eth") subprotocol.
#[serde(rename="subprotocolName")] #[serde(rename="subprotocolName")]
pub subprotocol_name: Option<String>, pub subprotocol_name: Option<String>,
/// Minimum gas limit.
#[serde(rename="minGasLimit")]
pub min_gas_limit: Uint,
/// Option fork block number to check. /// Option fork block number to check.
#[serde(rename="forkBlock")] #[serde(rename="forkBlock")]
pub fork_block: Option<Uint>, pub fork_block: Option<Uint>,

View File

@ -98,7 +98,8 @@ section "install"
# Start Menu # Start Menu
createDirectory "$SMPROGRAMS\${COMPANYNAME}" createDirectory "$SMPROGRAMS\${COMPANYNAME}"
createShortCut "$SMPROGRAMS\${COMPANYNAME}\${APPNAME}.lnk" "$INSTDIR\parity.exe" "ui" "$INSTDIR\logo.ico" createShortCut "$SMPROGRAMS\${COMPANYNAME}\${APPNAME} Ethereum.lnk" "$INSTDIR\ptray.exe" "ui" "$INSTDIR\logo.ico"
createShortCut "$DESKTOP\${APPNAME} Ethereum.lnk" "$INSTDIR\ptray.exe" "ui" "$INSTDIR\logo.ico"
# Firewall remove rules if exists # Firewall remove rules if exists
SimpleFC::AdvRemoveRule "Parity incoming peers (TCP:30303)" SimpleFC::AdvRemoveRule "Parity incoming peers (TCP:30303)"

View File

@ -25,7 +25,7 @@ port = 30303
min_peers = 25 min_peers = 25
max_peers = 50 max_peers = 50
nat = "any" nat = "any"
id = "0x1" id = 1
bootnodes = [] bootnodes = []
discovery = true discovery = true
warp = true warp = true
@ -47,7 +47,7 @@ hosts = ["none"]
[ipc] [ipc]
disable = false disable = false
path = "$HOME/.parity/jsonrpc.ipc" path = "$HOME/.parity/jsonrpc.ipc"
apis = ["web3", "eth", "net", "ethcore", "traces", "rpc", "personal_safe"] apis = ["web3", "eth", "net", "ethcore", "traces", "rpc", "personal", "personal_safe"]
[dapps] [dapps]
disable = false disable = false

View File

@ -46,7 +46,7 @@ usage! {
flag_testnet: bool, flag_testnet: bool,
flag_import_geth_keys: bool, flag_import_geth_keys: bool,
flag_datadir: Option<String>, flag_datadir: Option<String>,
flag_networkid: Option<String>, flag_networkid: Option<usize>,
flag_peers: Option<u16>, flag_peers: Option<u16>,
flag_nodekey: Option<String>, flag_nodekey: Option<String>,
flag_nodiscover: bool, flag_nodiscover: bool,
@ -122,7 +122,7 @@ usage! {
or |c: &Config| otry!(c.network).nat.clone(), or |c: &Config| otry!(c.network).nat.clone(),
flag_allow_ips: String = "all", flag_allow_ips: String = "all",
or |c: &Config| otry!(c.network).allow_ips.clone(), or |c: &Config| otry!(c.network).allow_ips.clone(),
flag_network_id: Option<String> = None, flag_network_id: Option<usize> = None,
or |c: &Config| otry!(c.network).id.clone().map(Some), or |c: &Config| otry!(c.network).id.clone().map(Some),
flag_bootnodes: Option<String> = None, flag_bootnodes: Option<String> = None,
or |c: &Config| otry!(c.network).bootnodes.clone().map(|vec| Some(vec.join(","))), or |c: &Config| otry!(c.network).bootnodes.clone().map(|vec| Some(vec.join(","))),
@ -155,7 +155,7 @@ usage! {
or |c: &Config| otry!(c.ipc).disable.clone(), or |c: &Config| otry!(c.ipc).disable.clone(),
flag_ipc_path: String = "$HOME/.parity/jsonrpc.ipc", flag_ipc_path: String = "$HOME/.parity/jsonrpc.ipc",
or |c: &Config| otry!(c.ipc).path.clone(), or |c: &Config| otry!(c.ipc).path.clone(),
flag_ipc_apis: String = "web3,eth,net,ethcore,traces,rpc,personal_safe", flag_ipc_apis: String = "web3,eth,net,ethcore,traces,rpc,personal,personal_safe",
or |c: &Config| otry!(c.ipc).apis.clone().map(|vec| vec.join(",")), or |c: &Config| otry!(c.ipc).apis.clone().map(|vec| vec.join(",")),
// DAPPS // DAPPS
@ -323,7 +323,7 @@ struct Network {
max_pending_peers: Option<u16>, max_pending_peers: Option<u16>,
nat: Option<String>, nat: Option<String>,
allow_ips: Option<String>, allow_ips: Option<String>,
id: Option<String>, id: Option<usize>,
bootnodes: Option<Vec<String>>, bootnodes: Option<Vec<String>>,
discovery: Option<bool>, discovery: Option<bool>,
node_key: Option<String>, node_key: Option<String>,
@ -530,7 +530,7 @@ mod tests {
flag_snapshot_peers: 0u16, flag_snapshot_peers: 0u16,
flag_allow_ips: "all".into(), flag_allow_ips: "all".into(),
flag_nat: "any".into(), flag_nat: "any".into(),
flag_network_id: Some("0x1".into()), flag_network_id: Some(1),
flag_bootnodes: Some("".into()), flag_bootnodes: Some("".into()),
flag_no_discovery: false, flag_no_discovery: false,
flag_node_key: None, flag_node_key: None,
@ -549,7 +549,7 @@ mod tests {
// IPC // IPC
flag_no_ipc: false, flag_no_ipc: false,
flag_ipc_path: "$HOME/.parity/jsonrpc.ipc".into(), flag_ipc_path: "$HOME/.parity/jsonrpc.ipc".into(),
flag_ipc_apis: "web3,eth,net,ethcore,traces,rpc,personal_safe".into(), flag_ipc_apis: "web3,eth,net,ethcore,traces,rpc,personal,personal_safe".into(),
// DAPPS // DAPPS
flag_no_dapps: false, flag_no_dapps: false,

View File

@ -5,5 +5,6 @@ License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it. This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. There is NO WARRANTY, to the extent permitted by law.
By Wood/Paronyan/Kotewicz/Drwięga/Volf. By Wood/Paronyan/Kotewicz/Drwięga/Volf
Habermeier/Czaban/Greeff/Gotchac/Redmann

View File

@ -86,7 +86,7 @@ impl Configuration {
let http_conf = try!(self.http_config()); let http_conf = try!(self.http_config());
let ipc_conf = try!(self.ipc_config()); let ipc_conf = try!(self.ipc_config());
let net_conf = try!(self.net_config()); let net_conf = try!(self.net_config());
let network_id = try!(self.network_id()); let network_id = self.network_id();
let cache_config = self.cache_config(); let cache_config = self.cache_config();
let spec = try!(self.chain().parse()); let spec = try!(self.chain().parse());
let tracing = try!(self.args.flag_tracing.parse()); let tracing = try!(self.args.flag_tracing.parse());
@ -517,12 +517,8 @@ impl Configuration {
Ok(ret) Ok(ret)
} }
fn network_id(&self) -> Result<Option<U256>, String> { fn network_id(&self) -> Option<usize> {
let net_id = self.args.flag_network_id.as_ref().or(self.args.flag_networkid.as_ref()); self.args.flag_network_id.or(self.args.flag_networkid)
match net_id {
Some(id) => Ok(Some(try!(to_u256(id)))),
None => Ok(None),
}
} }
fn rpc_apis(&self) -> String { fn rpc_apis(&self) -> String {

View File

@ -63,7 +63,7 @@ impl Default for IpcConfiguration {
IpcConfiguration { IpcConfiguration {
enabled: true, enabled: true,
socket_addr: parity_ipc_path("$HOME/.parity/jsonrpc.ipc"), socket_addr: parity_ipc_path("$HOME/.parity/jsonrpc.ipc"),
apis: ApiSet::UnsafeContext, apis: ApiSet::IpcContext,
} }
} }
} }

View File

@ -69,6 +69,7 @@ impl FromStr for Api {
pub enum ApiSet { pub enum ApiSet {
SafeContext, SafeContext,
UnsafeContext, UnsafeContext,
IpcContext,
List(HashSet<Api>), List(HashSet<Api>),
} }
@ -139,6 +140,10 @@ impl ApiSet {
vec![Api::Web3, Api::Net, Api::Eth, Api::Ethcore, Api::Traces, Api::Rpc, Api::PersonalSafe] vec![Api::Web3, Api::Net, Api::Eth, Api::Ethcore, Api::Traces, Api::Rpc, Api::PersonalSafe]
.into_iter().collect() .into_iter().collect()
}, },
ApiSet::IpcContext => {
vec![Api::Web3, Api::Net, Api::Eth, Api::Ethcore, Api::Traces, Api::Rpc, Api::PersonalAccounts, Api::PersonalSafe]
.into_iter().collect()
},
ApiSet::SafeContext => { ApiSet::SafeContext => {
vec![Api::Web3, Api::Net, Api::Eth, Api::PersonalAccounts, Api::PersonalSafe, Api::Signer, Api::Ethcore, Api::EthcoreSet, Api::Traces, Api::Rpc] vec![Api::Web3, Api::Net, Api::Eth, Api::PersonalAccounts, Api::PersonalSafe, Api::Signer, Api::Ethcore, Api::EthcoreSet, Api::Traces, Api::Rpc]
.into_iter().collect() .into_iter().collect()

View File

@ -20,7 +20,7 @@ use ctrlc::CtrlC;
use fdlimit::raise_fd_limit; use fdlimit::raise_fd_limit;
use ethcore_rpc::{NetworkSettings, is_major_importing}; use ethcore_rpc::{NetworkSettings, is_major_importing};
use ethsync::NetworkConfiguration; use ethsync::NetworkConfiguration;
use util::{Colour, version, U256, RotatingLogger}; use util::{Colour, version, RotatingLogger};
use io::{MayPanic, ForwardPanic, PanicHandler}; use io::{MayPanic, ForwardPanic, PanicHandler};
use ethcore_logger::{Config as LogConfig}; use ethcore_logger::{Config as LogConfig};
use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, ChainNotify, BlockChainClient}; use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, ChainNotify, BlockChainClient};
@ -70,7 +70,7 @@ pub struct RunCmd {
pub http_conf: HttpConfiguration, pub http_conf: HttpConfiguration,
pub ipc_conf: IpcConfiguration, pub ipc_conf: IpcConfiguration,
pub net_conf: NetworkConfiguration, pub net_conf: NetworkConfiguration,
pub network_id: Option<U256>, pub network_id: Option<usize>,
pub warp_sync: bool, pub warp_sync: bool,
pub acc_conf: AccountsConfig, pub acc_conf: AccountsConfig,
pub gas_pricer: GasPricerConfig, pub gas_pricer: GasPricerConfig,

View File

@ -63,15 +63,16 @@ pub fn decrypt(accounts: &AccountProvider, address: Address, password: Option<St
pub fn sign_and_dispatch<C, M>(client: &C, miner: &M, accounts: &AccountProvider, request: TransactionRequest, password: Option<String>) -> Result<RpcH256, Error> pub fn sign_and_dispatch<C, M>(client: &C, miner: &M, accounts: &AccountProvider, request: TransactionRequest, password: Option<String>) -> Result<RpcH256, Error>
where C: MiningBlockChainClient, M: MinerService { where C: MiningBlockChainClient, M: MinerService {
let network_id = client.signing_network_id();
let address = request.from; let address = request.from;
let signed_transaction = { let signed_transaction = {
let t = prepare_transaction(client, miner, request); let t = prepare_transaction(client, miner, request);
let hash = t.hash(); let hash = t.hash(network_id);
let signature = try!(signature(accounts, address, password, hash)); let signature = try!(signature(accounts, address, password, hash));
t.with_signature(signature) t.with_signature(signature, network_id)
}; };
trace!(target: "miner", "send_transaction: dispatching tx: {}", ::rlp::encode(&signed_transaction).to_vec().pretty()); trace!(target: "miner", "send_transaction: dispatching tx: {} for network ID {:?}", ::rlp::encode(&signed_transaction).to_vec().pretty(), network_id);
dispatch_transaction(&*client, &*miner, signed_transaction) dispatch_transaction(&*client, &*miner, signed_transaction)
} }

View File

@ -255,6 +255,7 @@ pub fn from_transaction_error(error: EthcoreError) -> Error {
SenderBanned => "Sender is banned in local queue.".into(), SenderBanned => "Sender is banned in local queue.".into(),
RecipientBanned => "Recipient is banned in local queue.".into(), RecipientBanned => "Recipient is banned in local queue.".into(),
CodeBanned => "Code is banned in local queue.".into(), CodeBanned => "Code is banned in local queue.".into(),
e => format!("{}", e).into(),
}; };
Error { Error {
code: ErrorCode::ServerError(codes::TRANSACTION_ERROR), code: ErrorCode::ServerError(codes::TRANSACTION_ERROR),

View File

@ -45,7 +45,7 @@ fn account_provider() -> Arc<AccountProvider> {
fn sync_provider() -> Arc<TestSyncProvider> { fn sync_provider() -> Arc<TestSyncProvider> {
Arc::new(TestSyncProvider::new(Config { Arc::new(TestSyncProvider::new(Config {
network_id: U256::from(3), network_id: 3,
num_peers: 120, num_peers: 120,
})) }))
} }

View File

@ -209,6 +209,8 @@ impl MinerService for TestMinerService {
gas_used: r.gas_used.clone(), gas_used: r.gas_used.clone(),
contract_address: None, contract_address: None,
logs: r.logs.clone(), logs: r.logs.clone(),
log_bloom: r.log_bloom,
state_root: r.state_root,
} }
) )
} }

View File

@ -16,13 +16,13 @@
//! Test implementation of SyncProvider. //! Test implementation of SyncProvider.
use util::{RwLock, U256}; use util::{RwLock};
use ethsync::{SyncProvider, SyncStatus, SyncState, PeerInfo}; use ethsync::{SyncProvider, SyncStatus, SyncState, PeerInfo};
/// TestSyncProvider config. /// TestSyncProvider config.
pub struct Config { pub struct Config {
/// Protocol version. /// Protocol version.
pub network_id: U256, pub network_id: usize,
/// Number of peers. /// Number of peers.
pub num_peers: usize, pub num_peers: usize,
} }

View File

@ -43,7 +43,7 @@ fn accounts_provider() -> Arc<AccountProvider> {
fn sync_provider() -> Arc<TestSyncProvider> { fn sync_provider() -> Arc<TestSyncProvider> {
Arc::new(TestSyncProvider::new(Config { Arc::new(TestSyncProvider::new(Config {
network_id: U256::from(3), network_id: 3,
num_peers: 120, num_peers: 120,
})) }))
} }
@ -485,7 +485,7 @@ fn rpc_eth_pending_transaction_by_hash() {
tester.miner.pending_transactions.lock().insert(H256::zero(), tx); tester.miner.pending_transactions.lock().insert(H256::zero(), tx);
} }
let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"creates":null,"from":"0x0f65fe9276bc9a24ae7083ae28e2660ef72df99e","gas":"0x5208","gasPrice":"0x1","hash":"0x41df922fd0d4766fcc02e161f8295ec28522f329ae487f14d811e4b64c8d6e31","input":"0x","nonce":"0x0","publicKey":"0x7ae46da747962c2ee46825839c1ef9298e3bd2e70ca2938495c3693a485ec3eaa8f196327881090ff64cf4fbb0a48485d4f83098e189ed3b7a87d5941b59f789","raw":"0xf85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","to":"0x095e7baea6a6c7c4c2dfeb977efac326af552d87","transactionIndex":null,"value":"0xa"},"id":1}"#; let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"creates":null,"from":"0x0f65fe9276bc9a24ae7083ae28e2660ef72df99e","gas":"0x5208","gasPrice":"0x1","hash":"0x41df922fd0d4766fcc02e161f8295ec28522f329ae487f14d811e4b64c8d6e31","input":"0x","nonce":"0x0","publicKey":"0x7ae46da747962c2ee46825839c1ef9298e3bd2e70ca2938495c3693a485ec3eaa8f196327881090ff64cf4fbb0a48485d4f83098e189ed3b7a87d5941b59f789","r":"0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353","raw":"0xf85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","s":"0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","to":"0x095e7baea6a6c7c4c2dfeb977efac326af552d87","transactionIndex":null,"v":0,"value":"0xa"},"id":1}"#;
let request = r#"{ let request = r#"{
"jsonrpc": "2.0", "jsonrpc": "2.0",
"method": "eth_getTransactionByHash", "method": "eth_getTransactionByHash",
@ -737,8 +737,8 @@ fn rpc_eth_send_transaction() {
value: U256::from(0x9184e72au64), value: U256::from(0x9184e72au64),
data: vec![] data: vec![]
}; };
let signature = tester.accounts_provider.sign(address, None, t.hash()).unwrap(); let signature = tester.accounts_provider.sign(address, None, t.hash(None)).unwrap();
let t = t.with_signature(signature); let t = t.with_signature(signature, None);
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#;
@ -754,8 +754,8 @@ fn rpc_eth_send_transaction() {
value: U256::from(0x9184e72au64), value: U256::from(0x9184e72au64),
data: vec![] data: vec![]
}; };
let signature = tester.accounts_provider.sign(address, None, t.hash()).unwrap(); let signature = tester.accounts_provider.sign(address, None, t.hash(None)).unwrap();
let t = t.with_signature(signature); let t = t.with_signature(signature, None);
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#;
@ -819,8 +819,8 @@ fn rpc_eth_send_raw_transaction() {
value: U256::from(0x9184e72au64), value: U256::from(0x9184e72au64),
data: vec![] data: vec![]
}; };
let signature = tester.accounts_provider.sign(address, None, t.hash()).unwrap(); let signature = tester.accounts_provider.sign(address, None, t.hash(None)).unwrap();
let t = t.with_signature(signature); let t = t.with_signature(signature, None);
let rlp = ::rlp::encode(&t).to_vec().to_hex(); let rlp = ::rlp::encode(&t).to_vec().to_hex();
@ -862,7 +862,9 @@ fn rpc_eth_transaction_receipt() {
transaction_hash: H256::new(), transaction_hash: H256::new(),
transaction_index: 0, transaction_index: 0,
log_index: 1, log_index: 1,
}] }],
log_bloom: 0.into(),
state_root: 0.into(),
}; };
let hash = H256::from_str("b903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238").unwrap(); let hash = H256::from_str("b903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238").unwrap();
@ -875,7 +877,7 @@ fn rpc_eth_transaction_receipt() {
"params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"], "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"],
"id": 1 "id": 1
}"#; }"#;
let response = r#"{"jsonrpc":"2.0","result":{"blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","contractAddress":null,"cumulativeGasUsed":"0x20","gasUsed":"0x10","logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","data":"0x","logIndex":"0x1","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","type":"mined"}],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0"},"id":1}"#; let response = r#"{"jsonrpc":"2.0","result":{"blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","contractAddress":null,"cumulativeGasUsed":"0x20","gasUsed":"0x10","logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","data":"0x","logIndex":"0x1","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","type":"mined"}],"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","root":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0"},"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned())); assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
} }

View File

@ -246,8 +246,8 @@ fn should_dispatch_transaction_if_account_is_unlock() {
value: U256::from(0x9184e72au64), value: U256::from(0x9184e72au64),
data: vec![] data: vec![]
}; };
let signature = tester.accounts.sign(acc, None, t.hash()).unwrap(); let signature = tester.accounts.sign(acc, None, t.hash(None)).unwrap();
let t = t.with_signature(signature); let t = t.with_signature(signature, None);
// when // when
let request = r#"{ let request = r#"{

View File

@ -16,7 +16,7 @@
use std::sync::Arc; use std::sync::Arc;
use util::log::RotatingLogger; use util::log::RotatingLogger;
use util::{U256, Address}; use util::{Address};
use ethsync::ManageNetwork; use ethsync::ManageNetwork;
use ethcore::client::{TestBlockChainClient}; use ethcore::client::{TestBlockChainClient};
use ethstore::ethkey::{Generator, Random}; use ethstore::ethkey::{Generator, Random};
@ -46,7 +46,7 @@ impl Dependencies {
miner: Arc::new(TestMinerService::default()), miner: Arc::new(TestMinerService::default()),
client: Arc::new(TestBlockChainClient::default()), client: Arc::new(TestBlockChainClient::default()),
sync: Arc::new(TestSyncProvider::new(Config { sync: Arc::new(TestSyncProvider::new(Config {
network_id: U256::from(3), network_id: 3,
num_peers: 120, num_peers: 120,
})), })),
logger: Arc::new(RotatingLogger::new("rpc=trace".to_owned())), logger: Arc::new(RotatingLogger::new("rpc=trace".to_owned())),

View File

@ -21,7 +21,7 @@ use v1::tests::helpers::{Config, TestSyncProvider};
fn sync_provider() -> Arc<TestSyncProvider> { fn sync_provider() -> Arc<TestSyncProvider> {
Arc::new(TestSyncProvider::new(Config { Arc::new(TestSyncProvider::new(Config {
network_id: 3.into(), network_id: 3,
num_peers: 120, num_peers: 120,
})) }))
} }

View File

@ -201,8 +201,8 @@ fn sign_and_send_transaction() {
data: vec![] data: vec![]
}; };
tester.accounts.unlock_account_temporarily(address, "password123".into()).unwrap(); tester.accounts.unlock_account_temporarily(address, "password123".into()).unwrap();
let signature = tester.accounts.sign(address, None, t.hash()).unwrap(); let signature = tester.accounts.sign(address, None, t.hash(None)).unwrap();
let t = t.with_signature(signature); let t = t.with_signature(signature, None);
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#;
@ -219,8 +219,8 @@ fn sign_and_send_transaction() {
data: vec![] data: vec![]
}; };
tester.accounts.unlock_account_temporarily(address, "password123".into()).unwrap(); tester.accounts.unlock_account_temporarily(address, "password123".into()).unwrap();
let signature = tester.accounts.sign(address, None, t.hash()).unwrap(); let signature = tester.accounts.sign(address, None, t.hash(None)).unwrap();
let t = t.with_signature(signature); let t = t.with_signature(signature, None);
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#;

View File

@ -186,8 +186,8 @@ fn should_confirm_transaction_and_dispatch() {
data: vec![] data: vec![]
}; };
tester.accounts.unlock_account_temporarily(address, "test".into()).unwrap(); tester.accounts.unlock_account_temporarily(address, "test".into()).unwrap();
let signature = tester.accounts.sign(address, None, t.hash()).unwrap(); let signature = tester.accounts.sign(address, None, t.hash(None)).unwrap();
let t = t.with_signature(signature); let t = t.with_signature(signature, None);
assert_eq!(tester.signer.requests().len(), 1); assert_eq!(tester.signer.requests().len(), 1);

View File

@ -103,7 +103,7 @@ mod tests {
fn test_serialize_block_transactions() { fn test_serialize_block_transactions() {
let t = BlockTransactions::Full(vec![Transaction::default()]); let t = BlockTransactions::Full(vec![Transaction::default()]);
let serialized = serde_json::to_string(&t).unwrap(); let serialized = serde_json::to_string(&t).unwrap();
assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null}]"#); assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null,"v":0,"r":"0x0000000000000000000000000000000000000000000000000000000000000000","s":"0x0000000000000000000000000000000000000000000000000000000000000000"}]"#);
let t = BlockTransactions::Hashes(vec![H256::default().into()]); let t = BlockTransactions::Hashes(vec![H256::default().into()]);
let serialized = serde_json::to_string(&t).unwrap(); let serialized = serde_json::to_string(&t).unwrap();

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use v1::types::{Log, H160, H256, U256}; use v1::types::{Log, H160, H256, H2048, U256};
use ethcore::receipt::{Receipt as EthReceipt, RichReceipt, LocalizedReceipt}; use ethcore::receipt::{Receipt as EthReceipt, RichReceipt, LocalizedReceipt};
/// Receipt /// Receipt
@ -43,6 +43,12 @@ pub struct Receipt {
pub contract_address: Option<H160>, pub contract_address: Option<H160>,
/// Logs /// Logs
pub logs: Vec<Log>, pub logs: Vec<Log>,
/// State Root
#[serde(rename="root")]
pub state_root: H256,
/// Logs bloom
#[serde(rename="logsBloom")]
pub logs_bloom: H2048,
} }
impl From<LocalizedReceipt> for Receipt { impl From<LocalizedReceipt> for Receipt {
@ -56,6 +62,8 @@ impl From<LocalizedReceipt> for Receipt {
gas_used: Some(r.gas_used.into()), gas_used: Some(r.gas_used.into()),
contract_address: r.contract_address.map(Into::into), contract_address: r.contract_address.map(Into::into),
logs: r.logs.into_iter().map(Into::into).collect(), logs: r.logs.into_iter().map(Into::into).collect(),
state_root: r.state_root.into(),
logs_bloom: r.log_bloom.into(),
} }
} }
} }
@ -71,6 +79,8 @@ impl From<RichReceipt> for Receipt {
gas_used: Some(r.gas_used.into()), gas_used: Some(r.gas_used.into()),
contract_address: r.contract_address.map(Into::into), contract_address: r.contract_address.map(Into::into),
logs: r.logs.into_iter().map(Into::into).collect(), logs: r.logs.into_iter().map(Into::into).collect(),
state_root: r.state_root.into(),
logs_bloom: r.log_bloom.into(),
} }
} }
} }
@ -86,6 +96,8 @@ impl From<EthReceipt> for Receipt {
gas_used: None, gas_used: None,
contract_address: None, contract_address: None,
logs: r.logs.into_iter().map(Into::into).collect(), logs: r.logs.into_iter().map(Into::into).collect(),
state_root: r.state_root.into(),
logs_bloom: r.log_bloom.into(),
} }
} }
} }
@ -93,35 +105,36 @@ impl From<EthReceipt> for Receipt {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use serde_json; use serde_json;
use std::str::FromStr; use v1::types::{Log, Receipt};
use v1::types::{Log, Receipt, U256, H256, H160};
#[test] #[test]
fn receipt_serialization() { fn receipt_serialization() {
let s = r#"{"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","cumulativeGasUsed":"0x20","gasUsed":"0x10","contractAddress":null,"logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"data":"0x","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","logIndex":"0x1","type":"mined"}]}"#; let s = r#"{"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","cumulativeGasUsed":"0x20","gasUsed":"0x10","contractAddress":null,"logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"data":"0x","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x4510c","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","logIndex":"0x1","type":"mined"}],"root":"0x000000000000000000000000000000000000000000000000000000000000000a","logsBloom":"0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f"}"#;
let receipt = Receipt { let receipt = Receipt {
transaction_hash: Some(H256::from(0)), transaction_hash: Some(0.into()),
transaction_index: Some(U256::from(0)), transaction_index: Some(0.into()),
block_hash: Some(H256::from_str("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5").unwrap()), block_hash: Some("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5".parse().unwrap()),
block_number: Some(U256::from(0x4510c)), block_number: Some(0x4510c.into()),
cumulative_gas_used: U256::from(0x20), cumulative_gas_used: 0x20.into(),
gas_used: Some(U256::from(0x10)), gas_used: Some(0x10.into()),
contract_address: None, contract_address: None,
logs: vec![Log { logs: vec![Log {
address: H160::from_str("33990122638b9132ca29c723bdf037f1a891a70c").unwrap(), address: "33990122638b9132ca29c723bdf037f1a891a70c".parse().unwrap(),
topics: vec![ topics: vec![
H256::from_str("a6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc").unwrap(), "a6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc".parse().unwrap(),
H256::from_str("4861736852656700000000000000000000000000000000000000000000000000").unwrap(), "4861736852656700000000000000000000000000000000000000000000000000".parse().unwrap(),
], ],
data: vec![].into(), data: vec![].into(),
block_hash: Some(H256::from_str("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5").unwrap()), block_hash: Some("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5".parse().unwrap()),
block_number: Some(U256::from(0x4510c)), block_number: Some(0x4510c.into()),
transaction_hash: Some(H256::default()), transaction_hash: Some(0.into()),
transaction_index: Some(U256::default()), transaction_index: Some(0.into()),
log_index: Some(U256::from(1)), log_index: Some(1.into()),
log_type: "mined".to_owned(), log_type: "mined".into(),
}] }],
logs_bloom: 15.into(),
state_root: 10.into(),
}; };
let serialized = serde_json::to_string(&receipt).unwrap(); let serialized = serde_json::to_string(&receipt).unwrap();

View File

@ -54,10 +54,17 @@ pub struct Transaction {
/// Public key of the signer. /// Public key of the signer.
#[serde(rename="publicKey")] #[serde(rename="publicKey")]
pub public_key: Option<H512>, pub public_key: Option<H512>,
/// The V field of the signature.
pub v: u8,
/// The R field of the signature.
pub r: H256,
/// The S field of the signature.
pub s: H256,
} }
impl From<LocalizedTransaction> for Transaction { impl From<LocalizedTransaction> for Transaction {
fn from(t: LocalizedTransaction) -> Transaction { fn from(t: LocalizedTransaction) -> Transaction {
let signature = t.signature();
Transaction { Transaction {
hash: t.hash().into(), hash: t.hash().into(),
nonce: t.nonce.into(), nonce: t.nonce.into(),
@ -79,12 +86,16 @@ impl From<LocalizedTransaction> for Transaction {
}, },
raw: ::rlp::encode(&t.signed).to_vec().into(), raw: ::rlp::encode(&t.signed).to_vec().into(),
public_key: t.public_key().ok().map(Into::into), public_key: t.public_key().ok().map(Into::into),
v: signature.v(),
r: signature.r().into(),
s: signature.s().into(),
} }
} }
} }
impl From<SignedTransaction> for Transaction { impl From<SignedTransaction> for Transaction {
fn from(t: SignedTransaction) -> Transaction { fn from(t: SignedTransaction) -> Transaction {
let signature = t.signature();
Transaction { Transaction {
hash: t.hash().into(), hash: t.hash().into(),
nonce: t.nonce.into(), nonce: t.nonce.into(),
@ -106,6 +117,9 @@ impl From<SignedTransaction> for Transaction {
}, },
raw: ::rlp::encode(&t).to_vec().into(), raw: ::rlp::encode(&t).to_vec().into(),
public_key: t.public_key().ok().map(Into::into), public_key: t.public_key().ok().map(Into::into),
v: signature.v(),
r: signature.r().into(),
s: signature.s().into(),
} }
} }
} }
@ -119,7 +133,7 @@ mod tests {
fn test_transaction_serialize() { fn test_transaction_serialize() {
let t = Transaction::default(); let t = Transaction::default();
let serialized = serde_json::to_string(&t).unwrap(); let serialized = serde_json::to_string(&t).unwrap();
assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null}"#); assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null,"v":0,"r":"0x0000000000000000000000000000000000000000000000000000000000000000","s":"0x0000000000000000000000000000000000000000000000000000000000000000"}"#);
} }
} }

View File

@ -42,7 +42,7 @@ pub struct SyncConfig {
/// Max blocks to download ahead /// Max blocks to download ahead
pub max_download_ahead_blocks: usize, pub max_download_ahead_blocks: usize,
/// Network ID /// Network ID
pub network_id: U256, pub network_id: usize,
/// Main "eth" subprotocol name. /// Main "eth" subprotocol name.
pub subprotocol_name: [u8; 3], pub subprotocol_name: [u8; 3],
/// Fork block to check /// Fork block to check
@ -55,7 +55,7 @@ impl Default for SyncConfig {
fn default() -> SyncConfig { fn default() -> SyncConfig {
SyncConfig { SyncConfig {
max_download_ahead_blocks: 20000, max_download_ahead_blocks: 20000,
network_id: U256::from(1), network_id: 1,
subprotocol_name: *b"eth", subprotocol_name: *b"eth",
fork_block: None, fork_block: None,
warp_sync: false, warp_sync: false,

View File

@ -188,7 +188,7 @@ pub struct SyncStatus {
/// Syncing protocol version. That's the maximum protocol version we connect to. /// Syncing protocol version. That's the maximum protocol version we connect to.
pub protocol_version: u8, pub protocol_version: u8,
/// The underlying p2p network version. /// The underlying p2p network version.
pub network_id: U256, pub network_id: usize,
/// `BlockChain` height for the moment the sync started. /// `BlockChain` height for the moment the sync started.
pub start_block_number: BlockNumber, pub start_block_number: BlockNumber,
/// Last fully downloaded and imported block number (if any). /// Last fully downloaded and imported block number (if any).
@ -269,7 +269,7 @@ struct PeerInfo {
/// Peer chain genesis hash /// Peer chain genesis hash
genesis: H256, genesis: H256,
/// Peer network id /// Peer network id
network_id: U256, network_id: usize,
/// Peer best block hash /// Peer best block hash
latest_hash: H256, latest_hash: H256,
/// Peer total difficulty if known /// Peer total difficulty if known
@ -328,7 +328,7 @@ pub struct ChainSync {
/// Last propagated block number /// Last propagated block number
last_sent_block_number: BlockNumber, last_sent_block_number: BlockNumber,
/// Network ID /// Network ID
network_id: U256, network_id: usize,
/// Optional fork block to check /// Optional fork block to check
fork_block: Option<(BlockNumber, H256)>, fork_block: Option<(BlockNumber, H256)>,
/// Snapshot downloader. /// Snapshot downloader.
@ -2145,7 +2145,7 @@ mod tests {
PeerInfo { PeerInfo {
protocol_version: 0, protocol_version: 0,
genesis: H256::zero(), genesis: H256::zero(),
network_id: U256::zero(), network_id: 0,
latest_hash: peer_latest_hash, latest_hash: peer_latest_hash,
difficulty: None, difficulty: None,
asking: PeerAsking::Nothing, asking: PeerAsking::Nothing,

View File

@ -4,7 +4,7 @@ homepage = "http://ethcore.io"
repository = "https://github.com/ethcore/parity" repository = "https://github.com/ethcore/parity"
license = "GPL-3.0" license = "GPL-3.0"
name = "ethcore-bigint" name = "ethcore-bigint"
version = "0.1.1" version = "0.1.2"
authors = ["Ethcore <admin@ethcore.io>"] authors = ["Ethcore <admin@ethcore.io>"]
build = "build.rs" build = "build.rs"

View File

@ -386,6 +386,12 @@ macro_rules! impl_hash {
} }
} }
} }
impl<'a> From<&'a [u8]> for $from {
fn from(s: &'a [u8]) -> $from {
$from::from_slice(s)
}
}
} }
} }

View File

@ -40,7 +40,7 @@ pub fn version() -> String {
let date_dash = if commit_date.is_empty() { "" } else { "-" }; let date_dash = if commit_date.is_empty() { "" } else { "-" };
let env = Target::env(); let env = Target::env();
let env_dash = if env.is_empty() { "" } else { "-" }; let env_dash = if env.is_empty() { "" } else { "-" };
format!("Parity/v{}-unstable{}{}{}{}/{}-{}{}{}/rustc{}", env!("CARGO_PKG_VERSION"), sha3_dash, sha3, date_dash, commit_date, Target::arch(), Target::os(), env_dash, env, rustc_version()) format!("Parity/v{}-beta{}{}{}{}/{}-{}{}{}/rustc{}", env!("CARGO_PKG_VERSION"), sha3_dash, sha3, date_dash, commit_date, Target::arch(), Target::os(), env_dash, env, rustc_version())
} }
/// Get the standard version data for this software. /// Get the standard version data for this software.

View File

@ -28,13 +28,17 @@ pub struct Histogram {
} }
impl Histogram { impl Histogram {
/// Histogram if a sorted corpus is at least fills the buckets. /// Histogram of a sorted corpus if it at least spans the buckets. Bounds are left closed.
pub fn new(corpus: &[U256], bucket_number: usize) -> Option<Histogram> { pub fn new(corpus: &[U256], bucket_number: usize) -> Option<Histogram> {
if corpus.len() <= bucket_number { return None; } if corpus.len() < 1 { return None; }
let corpus_end = corpus.last().expect("there are at least bucket_number elements; qed").clone(); let corpus_end = corpus.last().expect("there is at least 1 element; qed").clone();
// If there are extremely few transactions, go from zero. let corpus_start = corpus.first().expect("there is at least 1 element; qed").clone();
let corpus_start = corpus.first().expect("there are at least bucket_number elements; qed").clone(); // Bucket needs to be at least 1 wide.
let bucket_size = (corpus_end - corpus_start + 1.into()) / bucket_number.into(); let bucket_size = {
// Round up to get the entire corpus included.
let raw_bucket_size = (corpus_end - corpus_start + bucket_number.into()) / bucket_number.into();
if raw_bucket_size == 0.into() { 1.into() } else { raw_bucket_size }
};
let mut bucket_end = corpus_start + bucket_size; let mut bucket_end = corpus_start + bucket_size;
let mut bucket_bounds = vec![corpus_start; bucket_number + 1]; let mut bucket_bounds = vec![corpus_start; bucket_number + 1];
@ -42,10 +46,12 @@ impl Histogram {
let mut corpus_i = 0; let mut corpus_i = 0;
// Go through the corpus adding to buckets. // Go through the corpus adding to buckets.
for bucket in 0..bucket_number { for bucket in 0..bucket_number {
while corpus[corpus_i] < bucket_end { while corpus.get(corpus_i).map_or(false, |v| v < &bucket_end) {
// Initialized to size bucket_number above; iterates up to bucket_number; qed
counts[bucket] += 1; counts[bucket] += 1;
corpus_i += 1; corpus_i += 1;
} }
// Initialized to size bucket_number + 1 above; iterates up to bucket_number; subscript is in range; qed
bucket_bounds[bucket + 1] = bucket_end; bucket_bounds[bucket + 1] = bucket_end;
bucket_end = bucket_end + bucket_size; bucket_end = bucket_end + bucket_size;
} }
@ -62,14 +68,36 @@ mod tests {
#[test] #[test]
fn check_histogram() { fn check_histogram() {
let hist = Histogram::new(&vec_into![643,689,1408,2000,2296,2512,4250,4320,4842,4958,5804,6065,6098,6354,7002,7145,7845,8589,8593,8895], 5).unwrap(); let hist = Histogram::new(&vec_into![643,689,1408,2000,2296,2512,4250,4320,4842,4958,5804,6065,6098,6354,7002,7145,7845,8589,8593,8895], 5).unwrap();
let correct_bounds: Vec<U256> = vec_into![643,2293,3943,5593,7243,8893]; let correct_bounds: Vec<U256> = vec_into![643, 2294, 3945, 5596, 7247, 8898];
assert_eq!(Histogram { bucket_bounds: correct_bounds, counts: vec![4,2,4,6,3] }, hist); assert_eq!(Histogram { bucket_bounds: correct_bounds, counts: vec![4,2,4,6,4] }, hist);
assert!(Histogram::new(&vec_into![1, 2], 5).is_none());
} }
#[test] #[test]
fn should_not_panic_when_asking_for_bucket_too_big() { fn smaller_data_range_than_bucket_range() {
assert!(Histogram::new(&vec_into![1, 2], 2).is_none()); assert_eq!(
Histogram::new(&vec_into![1, 2, 2], 3),
Some(Histogram { bucket_bounds: vec_into![1, 2, 3, 4], counts: vec![1, 2, 0] })
);
}
#[test]
fn data_range_is_not_multiple_of_bucket_range() {
assert_eq!(
Histogram::new(&vec_into![1, 2, 5], 2),
Some(Histogram { bucket_bounds: vec_into![1, 4, 7], counts: vec![2, 1] })
);
}
#[test]
fn data_range_is_multiple_of_bucket_range() {
assert_eq!(
Histogram::new(&vec_into![1, 2, 6], 2),
Some(Histogram { bucket_bounds: vec_into![1, 4, 7], counts: vec![2, 1] })
);
}
#[test]
fn none_when_too_few_data() {
assert!(Histogram::new(&vec_into![], 1).is_none());
} }
} }

View File

@ -69,8 +69,12 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
UNREFERENCED_PARAMETER(lpCmdLine); UNREFERENCED_PARAMETER(lpCmdLine);
CreateMutex(0, FALSE, _T("Local\\ParityTray")); CreateMutex(0, FALSE, _T("Local\\ParityTray"));
if (GetLastError() == ERROR_ALREADY_EXISTS) if (GetLastError() == ERROR_ALREADY_EXISTS) {
return -1; // open the UI
OpenUI();
return 0;
}
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_PTRAY, szWindowClass, MAX_LOADSTRING); LoadStringW(hInstance, IDC_PTRAY, szWindowClass, MAX_LOADSTRING);