Merge branch 'master' into ui-2
This commit is contained in:
commit
a1502738f1
@ -62,7 +62,7 @@ linux-stable:
|
|||||||
name: "stable-x86_64-unknown-linux-gnu_parity"
|
name: "stable-x86_64-unknown-linux-gnu_parity"
|
||||||
linux-stable-debian:
|
linux-stable-debian:
|
||||||
stage: build
|
stage: build
|
||||||
image: ethcore/rust-debian:latest
|
image: parity/rust-debian:gitlab-ci
|
||||||
only:
|
only:
|
||||||
- beta
|
- beta
|
||||||
- tags
|
- tags
|
||||||
@ -146,7 +146,7 @@ linux-nightly:
|
|||||||
allow_failure: true
|
allow_failure: true
|
||||||
linux-centos:
|
linux-centos:
|
||||||
stage: build
|
stage: build
|
||||||
image: ethcore/rust-centos:latest
|
image: parity/rust-centos:gitlab-ci
|
||||||
only:
|
only:
|
||||||
- beta
|
- beta
|
||||||
- tags
|
- tags
|
||||||
@ -177,7 +177,7 @@ linux-centos:
|
|||||||
name: "x86_64-unknown-centos-gnu_parity"
|
name: "x86_64-unknown-centos-gnu_parity"
|
||||||
linux-i686:
|
linux-i686:
|
||||||
stage: build
|
stage: build
|
||||||
image: ethcore/rust-i686:latest
|
image: parity/rust-i686:gitlab-ci
|
||||||
only:
|
only:
|
||||||
- beta
|
- beta
|
||||||
- tags
|
- tags
|
||||||
@ -217,7 +217,7 @@ linux-i686:
|
|||||||
allow_failure: true
|
allow_failure: true
|
||||||
linux-armv7:
|
linux-armv7:
|
||||||
stage: build
|
stage: build
|
||||||
image: ethcore/rust-armv7:latest
|
image: parity/rust-armv7:gitlab-ci
|
||||||
only:
|
only:
|
||||||
- beta
|
- beta
|
||||||
- tags
|
- tags
|
||||||
@ -263,7 +263,7 @@ linux-armv7:
|
|||||||
allow_failure: true
|
allow_failure: true
|
||||||
linux-arm:
|
linux-arm:
|
||||||
stage: build
|
stage: build
|
||||||
image: ethcore/rust-arm:latest
|
image: parity/rust-arm:gitlab-ci
|
||||||
only:
|
only:
|
||||||
- beta
|
- beta
|
||||||
- tags
|
- tags
|
||||||
@ -348,7 +348,7 @@ linux-armv6:
|
|||||||
allow_failure: true
|
allow_failure: true
|
||||||
linux-aarch64:
|
linux-aarch64:
|
||||||
stage: build
|
stage: build
|
||||||
image: ethcore/rust-aarch64:latest
|
image: parity/rust-arm64:gitlab-ci
|
||||||
only:
|
only:
|
||||||
- beta
|
- beta
|
||||||
- tags
|
- tags
|
||||||
@ -560,7 +560,7 @@ test-rust-stable:
|
|||||||
- rust-stable
|
- rust-stable
|
||||||
js-test:
|
js-test:
|
||||||
stage: test
|
stage: test
|
||||||
image: ethcore/rust:stable
|
image: parity/rust:gitlab-ci
|
||||||
before_script:
|
before_script:
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
- export JS_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep ^js/ | wc -l)
|
- export JS_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep ^js/ | wc -l)
|
||||||
@ -574,11 +574,12 @@ test-rust-beta:
|
|||||||
stage: test
|
stage: test
|
||||||
only:
|
only:
|
||||||
- triggers
|
- triggers
|
||||||
image: ethcore/rust:beta
|
image: parity/rust:gitlab-ci
|
||||||
before_script:
|
before_script:
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
- export RUST_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep -v -e ^js -e ^\\. -e ^LICENSE -e ^README.md -e ^appveyor.yml -e ^test.sh -e ^windows/ -e ^scripts/ -e^mac/ -e ^nsis/ | wc -l)
|
- export RUST_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep -v -e ^js -e ^\\. -e ^LICENSE -e ^README.md -e ^appveyor.yml -e ^test.sh -e ^windows/ -e ^scripts/ -e^mac/ -e ^nsis/ | wc -l)
|
||||||
script:
|
script:
|
||||||
|
- rustup default beta
|
||||||
- export RUST_BACKTRACE=1
|
- export RUST_BACKTRACE=1
|
||||||
- if [ $RUST_FILES_MODIFIED -eq 0 ]; then echo "Skipping Rust tests since no Rust files modified."; else ./test.sh $CARGOFLAGS; fi
|
- if [ $RUST_FILES_MODIFIED -eq 0 ]; then echo "Skipping Rust tests since no Rust files modified."; else ./test.sh $CARGOFLAGS; fi
|
||||||
tags:
|
tags:
|
||||||
@ -589,11 +590,12 @@ test-rust-nightly:
|
|||||||
stage: test
|
stage: test
|
||||||
only:
|
only:
|
||||||
- triggers
|
- triggers
|
||||||
image: ethcore/rust:nightly
|
image: parity/rust:gitlab-ci
|
||||||
before_script:
|
before_script:
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
- export RUST_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep -v -e ^js -e ^\\. -e ^LICENSE -e ^README.md -e ^appveyor.yml -e ^test.sh -e ^windows/ -e ^scripts/ -e^mac/ -e ^nsis/ | wc -l)
|
- export RUST_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep -v -e ^js -e ^\\. -e ^LICENSE -e ^README.md -e ^appveyor.yml -e ^test.sh -e ^windows/ -e ^scripts/ -e^mac/ -e ^nsis/ | wc -l)
|
||||||
script:
|
script:
|
||||||
|
- rustup default stable
|
||||||
- export RUST_BACKTRACE=1
|
- export RUST_BACKTRACE=1
|
||||||
- if [ $RUST_FILES_MODIFIED -eq 0 ]; then echo "Skipping Rust tests since no Rust files modified."; else ./test.sh $CARGOFLAGS; fi
|
- if [ $RUST_FILES_MODIFIED -eq 0 ]; then echo "Skipping Rust tests since no Rust files modified."; else ./test.sh $CARGOFLAGS; fi
|
||||||
tags:
|
tags:
|
||||||
@ -607,12 +609,13 @@ js-release:
|
|||||||
- beta
|
- beta
|
||||||
- stable
|
- stable
|
||||||
- tags
|
- tags
|
||||||
image: ethcore/rust:stable
|
image: parity/rust:gitlab-ci
|
||||||
before_script:
|
before_script:
|
||||||
- export JS_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep ^js/ | wc -l)
|
- export JS_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep ^js/ | wc -l)
|
||||||
- echo $JS_FILES_MODIFIED
|
- echo $JS_FILES_MODIFIED
|
||||||
- if [ $JS_FILES_MODIFIED -eq 0 ]; then echo "Skipping JS deps install since no JS files modified."; else ./js/scripts/install-deps.sh;fi
|
- if [ $JS_FILES_MODIFIED -eq 0 ]; then echo "Skipping JS deps install since no JS files modified."; else ./js/scripts/install-deps.sh;fi
|
||||||
script:
|
script:
|
||||||
|
- rustup default stable
|
||||||
- echo $JS_FILES_MODIFIED
|
- echo $JS_FILES_MODIFIED
|
||||||
- if [ $JS_FILES_MODIFIED -eq 0 ]; then echo "Skipping JS rebuild since no JS files modified."; else ./js/scripts/build.sh && ./js/scripts/release.sh; fi
|
- if [ $JS_FILES_MODIFIED -eq 0 ]; then echo "Skipping JS rebuild since no JS files modified."; else ./js/scripts/build.sh && ./js/scripts/release.sh; fi
|
||||||
tags:
|
tags:
|
||||||
@ -621,8 +624,9 @@ push-release:
|
|||||||
stage: push-release
|
stage: push-release
|
||||||
only:
|
only:
|
||||||
- tags
|
- tags
|
||||||
image: ethcore/rust:stable
|
image: parity/rust:gitlab-ci
|
||||||
script:
|
script:
|
||||||
|
- rustup default stable
|
||||||
- curl --data "secret=$RELEASES_SECRET" http://update.parity.io:1337/push-release/$CI_BUILD_REF_NAME/$CI_BUILD_REF
|
- curl --data "secret=$RELEASES_SECRET" http://update.parity.io:1337/push-release/$CI_BUILD_REF_NAME/$CI_BUILD_REF
|
||||||
- curl --data "secret=$RELEASES_SECRET" http://update.parity.io:1338/push-release/$CI_BUILD_REF_NAME/$CI_BUILD_REF
|
- curl --data "secret=$RELEASES_SECRET" http://update.parity.io:1338/push-release/$CI_BUILD_REF_NAME/$CI_BUILD_REF
|
||||||
tags:
|
tags:
|
||||||
|
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1778,7 +1778,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "parity-ui-precompiled"
|
name = "parity-ui-precompiled"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
source = "git+https://github.com/paritytech/js-precompiled.git#6ae27a1126a30b21bac014d8d2a5eaac0c38ba1f"
|
source = "git+https://github.com/paritytech/js-precompiled.git#b5581e7b303487d9696b62a70eb54b96bc76f590"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -31,7 +31,7 @@ const SECRETSTORE_ACL_STORAGE_ABI: &'static str = r#"[{"constant":true,"inputs":
|
|||||||
// changes.
|
// changes.
|
||||||
const VALIDATOR_SET_ABI: &'static str = r#"[{"constant":true,"inputs":[],"name":"transitionNonce","outputs":[{"name":"nonce","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"validators","type":"address[]"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_parent_hash","type":"bytes32"},{"indexed":true,"name":"_nonce","type":"uint256"},{"indexed":false,"name":"_new_set","type":"address[]"}],"name":"ValidatorsChanged","type":"event"}]"#;
|
const VALIDATOR_SET_ABI: &'static str = r#"[{"constant":true,"inputs":[],"name":"transitionNonce","outputs":[{"name":"nonce","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"validators","type":"address[]"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_parent_hash","type":"bytes32"},{"indexed":true,"name":"_nonce","type":"uint256"},{"indexed":false,"name":"_new_set","type":"address[]"}],"name":"ValidatorsChanged","type":"event"}]"#;
|
||||||
|
|
||||||
const VALIDATOR_REPORT_ABI: &'static str = r#"[{"constant":false,"inputs":[{"name":"validator","type":"address"}],"name":"reportMalicious","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"validator","type":"address"}],"name":"reportBenign","outputs":[],"payable":false,"type":"function"}]"#;
|
const VALIDATOR_REPORT_ABI: &'static str = r#"[{"constant":false,"inputs":[{"name":"validator","type":"address"},{"name":"blockNumber","type":"uint256"},{"name":"proof","type":"bytes"}],"name":"reportMalicious","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"validator","type":"address"},{"name":"blockNumber","type":"uint256"}],"name":"reportBenign","outputs":[],"payable":false,"type":"function"}]"#;
|
||||||
|
|
||||||
fn build_file(name: &str, abi: &str, filename: &str) {
|
fn build_file(name: &str, abi: &str, filename: &str) {
|
||||||
let code = ::native_contract_generator::generate_module(name, abi).unwrap();
|
let code = ::native_contract_generator::generate_module(name, abi).unwrap();
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
|
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
|
||||||
"0000000000000000000000000000000000000005": {
|
"0000000000000000000000000000000000000005": {
|
||||||
"balance": "1",
|
"balance": "1",
|
||||||
"constructor": "6060604052604060405190810160405280737d577a597b2742b498cb5cf0c26cdcd726d39e6e73ffffffffffffffffffffffffffffffffffffffff1681526020017382a978b3f5962a5b0957d9ee9eef472ee55b42f173ffffffffffffffffffffffffffffffffffffffff1681525060009060028280548282559060005260206000209081019282156100ec579160200282015b828111156100eb5782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555091602001919060010190610093565b5b50905061012f91905b8082111561012b57600081816101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055506001016100f5565b5090565b505034610000575b6000600090505b6000805490508110156101d5578060016000600084815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b808060010191505061013e565b5b505b6105f2806101e76000396000f30060606040523615610076576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806335aa2e441461007b5780634d238c8e146100d8578063b7ab4db51461010b578063bfc708a01461017d578063d8f2e0bf146101b0578063fd6e1b50146101ff575b610000565b34610000576100966004808035906020019091905050610232565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3461000057610109600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061026f565b005b346100005761011861030f565b604051808060200182810382528381815181526020019150805190602001906020028083836000831461016a575b80518252602083111561016a57602082019150602081019050602083039250610146565b5050509050019250505060405180910390f35b34610000576101ae600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506103ad565b005b34610000576101bd61055b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3461000057610230600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610581565b005b600081815481101561000057906000526020600020900160005b915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600080548060010182818154818355818115116102b8578183600052602060002091820191016102b791905b808211156102b357600081600090555060010161029b565b5090565b5b505050916000526020600020900160005b83909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b50565b602060405190810160405280600081525060008054806020026020016040519081016040528092919081815260200182805480156103a257602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610358575b505050505090505b90565b6000600160008054905003815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff166000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054815481101561000057906000526020600020900160005b6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600090556000600160008054905003815481101561000057906000526020600020900160005b6101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905560008054809190600190038154818355818115116105535781836000526020600020918201910161055291905b8082111561054e576000816000905550600101610536565b5090565b5b505050505b50565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b505600a165627a7a7230582063a0123d8e8f5dde980af6b47e20acc5b7a1acac3e3101fa1c933471ef4b405c0029"
|
"constructor": "60a06040819052737d577a597b2742b498cb5cf0c26cdcd726d39e6e60609081527382a978b3f5962a5b0957d9ee9eef472ee55b42f1608052600080546002825581805290927f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5639182019291905b828111156100a25782518254600160a060020a031916600160a060020a0390911617825560209092019160019091019061006d565b5b506100cd9291505b808211156100c9578054600160a060020a03191681556001016100ab565b5090565b505034610000575b60005b60005481101561012f578060016000600084815481101561000057906000526020600020900160005b9054600160a060020a036101009290920a90041681526020810191909152604001600020555b6001016100d8565b5b505b610453806101416000396000f3006060604052361561005c5763ffffffff60e060020a60003504166335aa2e4481146100615780634d238c8e1461008d578063b7ab4db5146100a8578063c476dd4014610110578063d69f13bb14610172578063d8f2e0bf14610190575b610000565b34610000576100716004356101b9565b60408051600160a060020a039092168252519081900360200190f35b34610000576100a6600160a060020a03600435166101e9565b005b34610000576100b5610260565b60408051602080825283518183015283519192839290830191858101910280838382156100fd575b8051825260208311156100fd57601f1990920191602091820191016100dd565b5050509050019250505060405180910390f35b3461000057604080516020600460443581810135601f81018490048402850184019095528484526100a6948235600160a060020a03169460248035956064949293919092019181908401838280828437509496506102ca95505050505050565b005b34610000576100a6600160a060020a03600435166024356103eb565b005b3461000057610071610418565b60408051600160a060020a039092168252519081900360200190f35b600081815481101561000057906000526020600020900160005b915054906101000a9004600160a060020a031681565b6000805480600101828181548183558181151161022b5760008381526020902061022b9181019083015b808211156102275760008155600101610213565b5090565b5b505050916000526020600020900160005b8154600160a060020a038086166101009390930a92830292021916179055505b50565b60408051602081810183526000808352805484518184028101840190955280855292939290918301828280156102bf57602002820191906000526020600020905b8154600160a060020a031681526001909101906020018083116102a1575b505050505090505b90565b6000805460001981019081101561000057906000526020600020900160005b9054906101000a9004600160a060020a031660006001600086600160a060020a0316600160a060020a0316815260200190815260200160002054815481101561000057906000526020600020900160005b8154600160a060020a039384166101009290920a918202918402191617905583166000908152600160205260408120819055805460001981019081101561000057906000526020600020900160005b6101000a815490600160a060020a03021916905560008054809190600190038154818355818115116103e0576000838152602090206103e09181019083015b808211156102275760008155600101610213565b5090565b5b505050505b505050565b6002805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0384161790555b5050565b600254600160a060020a0316815600a165627a7a72305820f7876e17abd5f0927fff16788b4b3c9028ed64e6db740d788b07fc5f0a8f10920029"
|
||||||
},
|
},
|
||||||
"0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e": { "balance": "1606938044258990275541962092341162602522202993782792835301376" },
|
"0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e": { "balance": "1606938044258990275541962092341162602522202993782792835301376" },
|
||||||
"0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }
|
"0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }
|
||||||
|
@ -78,6 +78,7 @@ pub struct AccountDB<'db> {
|
|||||||
|
|
||||||
impl<'db> AccountDB<'db> {
|
impl<'db> AccountDB<'db> {
|
||||||
/// Create a new AccountDB from an address.
|
/// Create a new AccountDB from an address.
|
||||||
|
#[cfg(test)]
|
||||||
pub fn new(db: &'db HashDB, address: &Address) -> Self {
|
pub fn new(db: &'db HashDB, address: &Address) -> Self {
|
||||||
Self::from_hash(db, address.sha3())
|
Self::from_hash(db, address.sha3())
|
||||||
}
|
}
|
||||||
@ -131,6 +132,7 @@ pub struct AccountDBMut<'db> {
|
|||||||
|
|
||||||
impl<'db> AccountDBMut<'db> {
|
impl<'db> AccountDBMut<'db> {
|
||||||
/// Create a new AccountDB from an address.
|
/// Create a new AccountDB from an address.
|
||||||
|
#[cfg(test)]
|
||||||
pub fn new(db: &'db mut HashDB, address: &Address) -> Self {
|
pub fn new(db: &'db mut HashDB, address: &Address) -> Self {
|
||||||
Self::from_hash(db, address.sha3())
|
Self::from_hash(db, address.sha3())
|
||||||
}
|
}
|
||||||
@ -143,7 +145,7 @@ impl<'db> AccountDBMut<'db> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[cfg(test)]
|
||||||
pub fn immutable(&'db self) -> AccountDB<'db> {
|
pub fn immutable(&'db self) -> AccountDB<'db> {
|
||||||
AccountDB { db: self.db, address_hash: self.address_hash.clone() }
|
AccountDB { db: self.db, address_hash: self.address_hash.clone() }
|
||||||
}
|
}
|
||||||
|
@ -166,8 +166,7 @@ impl Client {
|
|||||||
db: Arc<KeyValueDB>,
|
db: Arc<KeyValueDB>,
|
||||||
miner: Arc<Miner>,
|
miner: Arc<Miner>,
|
||||||
message_channel: IoChannel<ClientIoMessage>,
|
message_channel: IoChannel<ClientIoMessage>,
|
||||||
) -> Result<Arc<Client>, ClientError> {
|
) -> Result<Arc<Client>, ::error::Error> {
|
||||||
|
|
||||||
let trie_spec = match config.fat_db {
|
let trie_spec = match config.fat_db {
|
||||||
true => TrieSpec::Fat,
|
true => TrieSpec::Fat,
|
||||||
false => TrieSpec::Secure,
|
false => TrieSpec::Secure,
|
||||||
|
@ -160,7 +160,7 @@ fn verify_external(header: &Header, validators: &ValidatorSet, step: &Step) -> R
|
|||||||
// Give one step slack if step is lagging, double vote is still not possible.
|
// Give one step slack if step is lagging, double vote is still not possible.
|
||||||
if step.is_future(header_step) {
|
if step.is_future(header_step) {
|
||||||
trace!(target: "engine", "verify_block_unordered: block from the future");
|
trace!(target: "engine", "verify_block_unordered: block from the future");
|
||||||
validators.report_benign(header.author());
|
validators.report_benign(header.author(), header.number());
|
||||||
Err(BlockError::InvalidSeal)?
|
Err(BlockError::InvalidSeal)?
|
||||||
} else {
|
} else {
|
||||||
let proposer_signature = header_signature(header)?;
|
let proposer_signature = header_signature(header)?;
|
||||||
@ -381,7 +381,7 @@ impl Engine for AuthorityRound {
|
|||||||
let parent_step = header_step(parent)?;
|
let parent_step = header_step(parent)?;
|
||||||
if step <= parent_step {
|
if step <= parent_step {
|
||||||
trace!(target: "engine", "Multiple blocks proposed for step {}.", parent_step);
|
trace!(target: "engine", "Multiple blocks proposed for step {}.", parent_step);
|
||||||
self.validators.report_malicious(header.author());
|
self.validators.report_malicious(header.author(), header.number(), Default::default());
|
||||||
Err(EngineError::DoubleVote(header.author().clone()))?;
|
Err(EngineError::DoubleVote(header.author().clone()))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -471,8 +471,8 @@ impl Engine for Tendermint {
|
|||||||
return Err(EngineError::NotAuthorized(sender).into());
|
return Err(EngineError::NotAuthorized(sender).into());
|
||||||
}
|
}
|
||||||
self.broadcast_message(rlp.as_raw().to_vec());
|
self.broadcast_message(rlp.as_raw().to_vec());
|
||||||
if self.votes.vote(message.clone(), &sender).is_some() {
|
if let Some(double) = self.votes.vote(message.clone(), &sender) {
|
||||||
self.validators.report_malicious(&sender);
|
self.validators.report_malicious(&sender, message.vote_step.height as BlockNumber, ::rlp::encode(&double).to_vec());
|
||||||
return Err(EngineError::DoubleVote(sender).into());
|
return Err(EngineError::DoubleVote(sender).into());
|
||||||
}
|
}
|
||||||
trace!(target: "engine", "Handling a valid {:?} from {}.", message, sender);
|
trace!(target: "engine", "Handling a valid {:?} from {}.", message, sender);
|
||||||
@ -560,7 +560,7 @@ impl Engine for Tendermint {
|
|||||||
let min_gas = parent.gas_limit().clone() - parent.gas_limit().clone() / gas_limit_divisor;
|
let min_gas = parent.gas_limit().clone() - parent.gas_limit().clone() / gas_limit_divisor;
|
||||||
let max_gas = parent.gas_limit().clone() + parent.gas_limit().clone() / gas_limit_divisor;
|
let max_gas = parent.gas_limit().clone() + parent.gas_limit().clone() / gas_limit_divisor;
|
||||||
if header.gas_limit() <= &min_gas || header.gas_limit() >= &max_gas {
|
if header.gas_limit() <= &min_gas || header.gas_limit() >= &max_gas {
|
||||||
self.validators.report_malicious(header.author());
|
self.validators.report_malicious(header.author(), header.number(), Default::default());
|
||||||
return Err(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(max_gas), found: header.gas_limit().clone() }).into());
|
return Err(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(max_gas), found: header.gas_limit().clone() }).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -610,8 +610,9 @@ impl Engine for Tendermint {
|
|||||||
trace!(target: "engine", "Propose timeout.");
|
trace!(target: "engine", "Propose timeout.");
|
||||||
if self.proposal.read().is_none() {
|
if self.proposal.read().is_none() {
|
||||||
// Report the proposer if no proposal was received.
|
// Report the proposer if no proposal was received.
|
||||||
let current_proposer = self.view_proposer(&*self.proposal_parent.read(), self.height.load(AtomicOrdering::SeqCst), self.view.load(AtomicOrdering::SeqCst));
|
let height = self.height.load(AtomicOrdering::SeqCst);
|
||||||
self.validators.report_benign(¤t_proposer);
|
let current_proposer = self.view_proposer(&*self.proposal_parent.read(), height, self.view.load(AtomicOrdering::SeqCst));
|
||||||
|
self.validators.report_benign(¤t_proposer, height as BlockNumber);
|
||||||
}
|
}
|
||||||
Step::Prevote
|
Step::Prevote
|
||||||
},
|
},
|
||||||
|
@ -25,7 +25,7 @@ use native_contracts::ValidatorReport as Provider;
|
|||||||
|
|
||||||
use client::{Client, BlockChainClient};
|
use client::{Client, BlockChainClient};
|
||||||
use engines::Call;
|
use engines::Call;
|
||||||
use header::Header;
|
use header::{Header, BlockNumber};
|
||||||
|
|
||||||
use super::ValidatorSet;
|
use super::ValidatorSet;
|
||||||
use super::safe_contract::ValidatorSafeContract;
|
use super::safe_contract::ValidatorSafeContract;
|
||||||
@ -92,15 +92,15 @@ impl ValidatorSet for ValidatorContract {
|
|||||||
self.validators.count_with_caller(bh, caller)
|
self.validators.count_with_caller(bh, caller)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_malicious(&self, address: &Address) {
|
fn report_malicious(&self, address: &Address, block: BlockNumber, proof: Bytes) {
|
||||||
match self.provider.report_malicious(&*self.transact(), *address).wait() {
|
match self.provider.report_malicious(&*self.transact(), *address, block.into(), proof).wait() {
|
||||||
Ok(_) => warn!(target: "engine", "Reported malicious validator {}", address),
|
Ok(_) => warn!(target: "engine", "Reported malicious validator {}", address),
|
||||||
Err(s) => warn!(target: "engine", "Validator {} could not be reported {}", address, s),
|
Err(s) => warn!(target: "engine", "Validator {} could not be reported {}", address, s),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_benign(&self, address: &Address) {
|
fn report_benign(&self, address: &Address, block: BlockNumber) {
|
||||||
match self.provider.report_benign(&*self.transact(), *address).wait() {
|
match self.provider.report_benign(&*self.transact(), *address, block.into()).wait() {
|
||||||
Ok(_) => warn!(target: "engine", "Reported benign validator misbehaviour {}", address),
|
Ok(_) => warn!(target: "engine", "Reported benign validator misbehaviour {}", address),
|
||||||
Err(s) => warn!(target: "engine", "Validator {} could not be reported {}", address, s),
|
Err(s) => warn!(target: "engine", "Validator {} could not be reported {}", address, s),
|
||||||
}
|
}
|
||||||
|
@ -23,10 +23,10 @@ mod multi;
|
|||||||
|
|
||||||
use std::sync::Weak;
|
use std::sync::Weak;
|
||||||
use ids::BlockId;
|
use ids::BlockId;
|
||||||
use util::{Address, H256};
|
use util::{Bytes, Address, H256};
|
||||||
use ethjson::spec::ValidatorSet as ValidatorSpec;
|
use ethjson::spec::ValidatorSet as ValidatorSpec;
|
||||||
use client::Client;
|
use client::Client;
|
||||||
use header::Header;
|
use header::{Header, BlockNumber};
|
||||||
|
|
||||||
pub use self::simple_list::SimpleList;
|
pub use self::simple_list::SimpleList;
|
||||||
use self::contract::ValidatorContract;
|
use self::contract::ValidatorContract;
|
||||||
@ -111,9 +111,9 @@ pub trait ValidatorSet: Send + Sync {
|
|||||||
fn count_with_caller(&self, parent_block_hash: &H256, caller: &Call) -> usize;
|
fn count_with_caller(&self, parent_block_hash: &H256, caller: &Call) -> usize;
|
||||||
|
|
||||||
/// Notifies about malicious behaviour.
|
/// Notifies about malicious behaviour.
|
||||||
fn report_malicious(&self, _validator: &Address) {}
|
fn report_malicious(&self, _validator: &Address, _block: BlockNumber, _proof: Bytes) {}
|
||||||
/// Notifies about benign misbehaviour.
|
/// Notifies about benign misbehaviour.
|
||||||
fn report_benign(&self, _validator: &Address) {}
|
fn report_benign(&self, _validator: &Address, _block: BlockNumber) {}
|
||||||
/// Allows blockchain state access.
|
/// Allows blockchain state access.
|
||||||
fn register_contract(&self, _client: Weak<Client>) {}
|
fn register_contract(&self, _client: Weak<Client>) {}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::sync::Weak;
|
use std::sync::Weak;
|
||||||
use engines::{Call, EpochChange};
|
use engines::{Call, EpochChange};
|
||||||
use util::{H256, Address, RwLock};
|
use util::{Bytes, H256, Address, RwLock};
|
||||||
use ids::BlockId;
|
use ids::BlockId;
|
||||||
use header::{BlockNumber, Header};
|
use header::{BlockNumber, Header};
|
||||||
use client::{Client, BlockChainClient};
|
use client::{Client, BlockChainClient};
|
||||||
@ -110,16 +110,12 @@ impl ValidatorSet for Multi {
|
|||||||
.map_or_else(usize::max_value, |set| set.count_with_caller(bh, caller))
|
.map_or_else(usize::max_value, |set| set.count_with_caller(bh, caller))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_malicious(&self, validator: &Address) {
|
fn report_malicious(&self, validator: &Address, block: BlockNumber, proof: Bytes) {
|
||||||
for set in self.sets.values() {
|
self.correct_set_by_number(block).1.report_malicious(validator, block, proof);
|
||||||
set.report_malicious(validator);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_benign(&self, validator: &Address) {
|
fn report_benign(&self, validator: &Address, block: BlockNumber) {
|
||||||
for set in self.sets.values() {
|
self.correct_set_by_number(block).1.report_benign(validator, block);
|
||||||
set.report_benign(validator);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_contract(&self, client: Weak<Client>) {
|
fn register_contract(&self, client: Weak<Client>) {
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use util::*;
|
use util::*;
|
||||||
use rlp::Encodable;
|
use rlp::{Encodable, RlpStream};
|
||||||
|
|
||||||
pub trait Message: Clone + PartialEq + Eq + Hash + Encodable + Debug {
|
pub trait Message: Clone + PartialEq + Eq + Hash + Encodable + Debug {
|
||||||
type Round: Clone + PartialEq + Eq + Hash + Default + Debug + Ord;
|
type Round: Clone + PartialEq + Eq + Hash + Default + Debug + Ord;
|
||||||
@ -40,25 +40,44 @@ pub struct VoteCollector<M: Message> {
|
|||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
struct StepCollector<M: Message> {
|
struct StepCollector<M: Message> {
|
||||||
voted: HashSet<Address>,
|
voted: HashMap<Address, M>,
|
||||||
pub block_votes: HashMap<Option<H256>, HashMap<H520, Address>>,
|
pub block_votes: HashMap<Option<H256>, HashMap<H520, Address>>,
|
||||||
messages: HashSet<M>,
|
messages: HashSet<M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DoubleVote<'a, M: Message> {
|
||||||
|
pub author: &'a Address,
|
||||||
|
vote_one: M,
|
||||||
|
vote_two: M,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, M: Message> Encodable for DoubleVote<'a, M> {
|
||||||
|
fn rlp_append(&self, s: &mut RlpStream) {
|
||||||
|
s.begin_list(2)
|
||||||
|
.append(&self.vote_one)
|
||||||
|
.append(&self.vote_two);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl <M: Message> StepCollector<M> {
|
impl <M: Message> StepCollector<M> {
|
||||||
/// Returns Some(&Address) when validator is double voting.
|
/// Returns Some(&Address) when validator is double voting.
|
||||||
fn insert<'a>(&mut self, message: M, address: &'a Address) -> Option<&'a Address> {
|
fn insert<'a>(&mut self, message: M, address: &'a Address) -> Option<DoubleVote<'a, M>> {
|
||||||
// Do nothing when message was seen.
|
// Do nothing when message was seen.
|
||||||
if self.messages.insert(message.clone()) {
|
if self.messages.insert(message.clone()) {
|
||||||
if self.voted.insert(address.clone()) {
|
if let Some(previous) = self.voted.insert(address.clone(), message.clone()) {
|
||||||
|
// Bad validator sent a different message.
|
||||||
|
return Some(DoubleVote {
|
||||||
|
author: address,
|
||||||
|
vote_one: previous,
|
||||||
|
vote_two: message
|
||||||
|
});
|
||||||
|
} else {
|
||||||
self
|
self
|
||||||
.block_votes
|
.block_votes
|
||||||
.entry(message.block_hash())
|
.entry(message.block_hash())
|
||||||
.or_insert_with(HashMap::new)
|
.or_insert_with(HashMap::new)
|
||||||
.insert(message.signature(), address.clone());
|
.insert(message.signature(), address.clone());
|
||||||
} else {
|
|
||||||
// Bad validator sent a different message.
|
|
||||||
return Some(address);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
@ -101,7 +120,7 @@ impl <M: Message + Default> Default for VoteCollector<M> {
|
|||||||
|
|
||||||
impl <M: Message + Default + Encodable + Debug> VoteCollector<M> {
|
impl <M: Message + Default + Encodable + Debug> VoteCollector<M> {
|
||||||
/// Insert vote if it is newer than the oldest one.
|
/// Insert vote if it is newer than the oldest one.
|
||||||
pub fn vote<'a>(&self, message: M, voter: &'a Address) -> Option<&'a Address> {
|
pub fn vote<'a>(&self, message: M, voter: &'a Address) -> Option<DoubleVote<'a, M>> {
|
||||||
self
|
self
|
||||||
.votes
|
.votes
|
||||||
.write()
|
.write()
|
||||||
@ -220,11 +239,11 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn random_vote(collector: &VoteCollector<TestMessage>, signature: H520, step: TestStep, block_hash: Option<H256>) -> bool {
|
fn random_vote(collector: &VoteCollector<TestMessage>, signature: H520, step: TestStep, block_hash: Option<H256>) -> bool {
|
||||||
full_vote(collector, signature, step, block_hash, &H160::random()).is_none()
|
full_vote(collector, signature, step, block_hash, &H160::random())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn full_vote<'a>(collector: &VoteCollector<TestMessage>, signature: H520, step: TestStep, block_hash: Option<H256>, address: &'a Address) -> Option<&'a Address> {
|
fn full_vote<'a>(collector: &VoteCollector<TestMessage>, signature: H520, step: TestStep, block_hash: Option<H256>, address: &'a Address) -> bool {
|
||||||
collector.vote(TestMessage { signature: signature, step: step, block_hash: block_hash }, address)
|
collector.vote(TestMessage { signature: signature, step: step, block_hash: block_hash }, address).is_none()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -319,9 +338,9 @@ mod tests {
|
|||||||
let collector = VoteCollector::default();
|
let collector = VoteCollector::default();
|
||||||
let round = 3;
|
let round = 3;
|
||||||
// Vote is inserted fine.
|
// Vote is inserted fine.
|
||||||
assert!(full_vote(&collector, H520::random(), round, Some("0".sha3()), &Address::default()).is_none());
|
assert!(full_vote(&collector, H520::random(), round, Some("0".sha3()), &Address::default()));
|
||||||
// Returns the double voting address.
|
// Returns the double voting address.
|
||||||
full_vote(&collector, H520::random(), round, Some("1".sha3()), &Address::default()).unwrap();
|
assert!(!full_vote(&collector, H520::random(), round, Some("1".sha3()), &Address::default()));
|
||||||
assert_eq!(collector.count_round_votes(&round), 1);
|
assert_eq!(collector.count_round_votes(&round), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,6 +95,7 @@ mod tests {
|
|||||||
let engine = &spec.engine;
|
let engine = &spec.engine;
|
||||||
let genesis_header = spec.genesis_header();
|
let genesis_header = spec.genesis_header();
|
||||||
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
||||||
|
|
||||||
let s = State::from_existing(db, genesis_header.state_root().clone(), engine.account_start_nonce(), Default::default()).unwrap();
|
let s = State::from_existing(db, genesis_header.state_root().clone(), engine.account_start_nonce(), Default::default()).unwrap();
|
||||||
assert_eq!(s.balance(&"0000000000000000000000000000000000000001".into()).unwrap(), 1u64.into());
|
assert_eq!(s.balance(&"0000000000000000000000000000000000000001".into()).unwrap(), 1u64.into());
|
||||||
assert_eq!(s.balance(&"0000000000000000000000000000000000000002".into()).unwrap(), 1u64.into());
|
assert_eq!(s.balance(&"0000000000000000000000000000000000000002".into()).unwrap(), 1u64.into());
|
||||||
|
@ -51,7 +51,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
|
|||||||
ChainEra::_Eip161 => ethereum::new_eip161_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).expect("Failed to overwrite genesis state");
|
||||||
spec.overwrite_genesis_params(genesis);
|
spec.overwrite_genesis_params(genesis);
|
||||||
assert!(spec.is_state_root_valid());
|
assert!(spec.is_state_root_valid());
|
||||||
spec
|
spec
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
use util::*;
|
use util::*;
|
||||||
use state::Account;
|
use state::Account;
|
||||||
use account_db::AccountDBMut;
|
|
||||||
use ethjson;
|
use ethjson;
|
||||||
use types::account_diff::*;
|
use types::account_diff::*;
|
||||||
use rlp::{self, RlpStream};
|
use rlp::{self, RlpStream};
|
||||||
@ -64,7 +63,7 @@ impl PodAccount {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Place additional data into given hash DB.
|
/// Place additional data into given hash DB.
|
||||||
pub fn insert_additional(&self, db: &mut AccountDBMut, factory: &TrieFactory) {
|
pub fn insert_additional(&self, db: &mut HashDB, factory: &TrieFactory) {
|
||||||
match self.code {
|
match self.code {
|
||||||
Some(ref c) if !c.is_empty() => { db.insert(c); }
|
Some(ref c) if !c.is_empty() => { db.insert(c); }
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -16,25 +16,27 @@
|
|||||||
|
|
||||||
//! Parameters for a block chain.
|
//! Parameters for a block chain.
|
||||||
|
|
||||||
use util::*;
|
|
||||||
use builtin::Builtin;
|
|
||||||
use engines::{Engine, NullEngine, InstantSeal, BasicAuthority, AuthorityRound, Tendermint};
|
|
||||||
use factory::Factories;
|
|
||||||
use executive::Executive;
|
|
||||||
use trace::{NoopTracer, NoopVMTracer};
|
|
||||||
use action_params::{ActionValue, ActionParams};
|
|
||||||
use types::executed::CallType;
|
|
||||||
use state::{Backend, State, Substate};
|
|
||||||
use env_info::EnvInfo;
|
|
||||||
use pod_state::*;
|
|
||||||
use account_db::*;
|
|
||||||
use header::{BlockNumber, Header};
|
|
||||||
use state_db::StateDB;
|
|
||||||
use super::genesis::Genesis;
|
use super::genesis::Genesis;
|
||||||
use super::seal::Generic as GenericSeal;
|
use super::seal::Generic as GenericSeal;
|
||||||
|
|
||||||
|
use action_params::{ActionValue, ActionParams};
|
||||||
|
use builtin::Builtin;
|
||||||
|
use engines::{Engine, NullEngine, InstantSeal, BasicAuthority, AuthorityRound, Tendermint};
|
||||||
|
use env_info::EnvInfo;
|
||||||
|
use error::Error;
|
||||||
use ethereum;
|
use ethereum;
|
||||||
use ethjson;
|
use ethjson;
|
||||||
|
use executive::Executive;
|
||||||
|
use factory::Factories;
|
||||||
|
use header::{BlockNumber, Header};
|
||||||
|
use pod_state::*;
|
||||||
use rlp::{Rlp, RlpStream};
|
use rlp::{Rlp, RlpStream};
|
||||||
|
use state_db::StateDB;
|
||||||
|
use state::{Backend, State, Substate};
|
||||||
|
use state::backend::Basic as BasicBackend;
|
||||||
|
use trace::{NoopTracer, NoopVMTracer};
|
||||||
|
use types::executed::CallType;
|
||||||
|
use util::*;
|
||||||
|
|
||||||
/// Parameters common to all engines.
|
/// Parameters common to all engines.
|
||||||
#[derive(Debug, PartialEq, Clone, Default)]
|
#[derive(Debug, PartialEq, Clone, Default)]
|
||||||
@ -119,19 +121,19 @@ pub struct Spec {
|
|||||||
constructors: Vec<(Address, Bytes)>,
|
constructors: Vec<(Address, Bytes)>,
|
||||||
|
|
||||||
/// May be prepopulated if we know this in advance.
|
/// May be prepopulated if we know this in advance.
|
||||||
state_root_memo: RwLock<Option<H256>>,
|
state_root_memo: RwLock<H256>,
|
||||||
|
|
||||||
/// Genesis state as plain old data.
|
/// Genesis state as plain old data.
|
||||||
genesis_state: PodState,
|
genesis_state: PodState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ethjson::spec::Spec> for Spec {
|
fn load_from(s: ethjson::spec::Spec) -> Result<Spec, Error> {
|
||||||
fn from(s: ethjson::spec::Spec) -> Self {
|
|
||||||
let builtins = s.accounts.builtins().into_iter().map(|p| (p.0.into(), From::from(p.1))).collect();
|
let builtins = s.accounts.builtins().into_iter().map(|p| (p.0.into(), From::from(p.1))).collect();
|
||||||
let g = Genesis::from(s.genesis);
|
let g = Genesis::from(s.genesis);
|
||||||
let GenericSeal(seal_rlp) = g.seal.into();
|
let GenericSeal(seal_rlp) = g.seal.into();
|
||||||
let params = CommonParams::from(s.params);
|
let params = CommonParams::from(s.params);
|
||||||
Spec {
|
|
||||||
|
let mut s = Spec {
|
||||||
name: s.name.clone().into(),
|
name: s.name.clone().into(),
|
||||||
params: params.clone(),
|
params: params.clone(),
|
||||||
engine: Spec::engine(s.engine, params, builtins),
|
engine: Spec::engine(s.engine, params, builtins),
|
||||||
@ -148,10 +150,17 @@ impl From<ethjson::spec::Spec> for Spec {
|
|||||||
extra_data: g.extra_data,
|
extra_data: g.extra_data,
|
||||||
seal_rlp: seal_rlp,
|
seal_rlp: seal_rlp,
|
||||||
constructors: s.accounts.constructors().into_iter().map(|(a, c)| (a.into(), c.into())).collect(),
|
constructors: s.accounts.constructors().into_iter().map(|(a, c)| (a.into(), c.into())).collect(),
|
||||||
state_root_memo: RwLock::new(g.state_root),
|
state_root_memo: RwLock::new(Default::default()), // will be overwritten right after.
|
||||||
genesis_state: From::from(s.accounts),
|
genesis_state: s.accounts.into(),
|
||||||
}
|
};
|
||||||
|
|
||||||
|
// use memoized state root if provided.
|
||||||
|
match g.state_root {
|
||||||
|
Some(root) => *s.state_root_memo.get_mut() = root,
|
||||||
|
None => { let _ = s.run_constructors(&Default::default(), BasicBackend(MemoryDB::new()))?; },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! load_bundled {
|
macro_rules! load_bundled {
|
||||||
@ -174,13 +183,93 @@ impl Spec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// given a pre-constructor state, run all the given constructors and produce a new state and state root.
|
||||||
|
fn run_constructors<T: Backend>(&self, factories: &Factories, mut db: T) -> Result<T, Error> {
|
||||||
|
let mut root = SHA3_NULL_RLP;
|
||||||
|
|
||||||
|
// basic accounts in spec.
|
||||||
|
{
|
||||||
|
let mut t = factories.trie.create(db.as_hashdb_mut(), &mut root);
|
||||||
|
|
||||||
|
for (address, account) in self.genesis_state.get().iter() {
|
||||||
|
t.insert(&**address, &account.rlp())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (address, account) in self.genesis_state.get().iter() {
|
||||||
|
db.note_non_null_account(address);
|
||||||
|
account.insert_additional(
|
||||||
|
&mut *factories.accountdb.create(db.as_hashdb_mut(), address.sha3()),
|
||||||
|
&factories.trie
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let start_nonce = self.engine.account_start_nonce();
|
||||||
|
|
||||||
|
let (root, db) = {
|
||||||
|
let mut state = State::from_existing(
|
||||||
|
db,
|
||||||
|
root,
|
||||||
|
start_nonce,
|
||||||
|
factories.clone(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Execute contract constructors.
|
||||||
|
let env_info = EnvInfo {
|
||||||
|
number: 0,
|
||||||
|
author: self.author,
|
||||||
|
timestamp: self.timestamp,
|
||||||
|
difficulty: self.difficulty,
|
||||||
|
last_hashes: Default::default(),
|
||||||
|
gas_used: U256::zero(),
|
||||||
|
gas_limit: U256::max_value(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let from = Address::default();
|
||||||
|
for &(ref address, ref constructor) in self.constructors.iter() {
|
||||||
|
trace!(target: "spec", "run_constructors: Creating a contract at {}.", address);
|
||||||
|
trace!(target: "spec", " .. root before = {}", state.root());
|
||||||
|
let params = ActionParams {
|
||||||
|
code_address: address.clone(),
|
||||||
|
code_hash: constructor.sha3(),
|
||||||
|
address: address.clone(),
|
||||||
|
sender: from.clone(),
|
||||||
|
origin: from.clone(),
|
||||||
|
gas: U256::max_value(),
|
||||||
|
gas_price: Default::default(),
|
||||||
|
value: ActionValue::Transfer(Default::default()),
|
||||||
|
code: Some(Arc::new(constructor.clone())),
|
||||||
|
data: None,
|
||||||
|
call_type: CallType::None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut substate = Substate::new();
|
||||||
|
state.kill_account(&address);
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut exec = Executive::new(&mut state, &env_info, self.engine.as_ref(), &factories.vm);
|
||||||
|
if let Err(e) = exec.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer) {
|
||||||
|
warn!(target: "spec", "Genesis constructor execution at {} failed: {}.", address, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(e) = state.commit() {
|
||||||
|
warn!(target: "spec", "Genesis constructor trie commit at {} failed: {}.", address, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
trace!(target: "spec", " .. root after = {}", state.root());
|
||||||
|
}
|
||||||
|
|
||||||
|
state.drop()
|
||||||
|
};
|
||||||
|
|
||||||
|
*self.state_root_memo.write() = root;
|
||||||
|
Ok(db)
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the state root for the genesis state, memoising accordingly.
|
/// Return the state root for the genesis state, memoising accordingly.
|
||||||
pub fn state_root(&self) -> H256 {
|
pub fn state_root(&self) -> H256 {
|
||||||
if self.state_root_memo.read().is_none() {
|
self.state_root_memo.read().clone()
|
||||||
*self.state_root_memo.write() = Some(self.genesis_state.root());
|
|
||||||
}
|
|
||||||
self.state_root_memo.read().as_ref().cloned()
|
|
||||||
.expect("state root memo ensured to be set at this point; qed")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the known knodes of the network in enode format.
|
/// Get the known knodes of the network in enode format.
|
||||||
@ -243,95 +332,46 @@ impl Spec {
|
|||||||
self.timestamp = g.timestamp;
|
self.timestamp = g.timestamp;
|
||||||
self.extra_data = g.extra_data;
|
self.extra_data = g.extra_data;
|
||||||
self.seal_rlp = seal_rlp;
|
self.seal_rlp = seal_rlp;
|
||||||
self.state_root_memo = RwLock::new(g.state_root);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Alter the value of the genesis state.
|
/// Alter the value of the genesis state.
|
||||||
pub fn set_genesis_state(&mut self, s: PodState) {
|
pub fn set_genesis_state(&mut self, s: PodState) -> Result<(), Error> {
|
||||||
self.genesis_state = s;
|
self.genesis_state = s;
|
||||||
*self.state_root_memo.write() = None;
|
let _ = self.run_constructors(&Default::default(), BasicBackend(MemoryDB::new()))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `false` if the memoized state root is invalid. `true` otherwise.
|
/// Returns `false` if the memoized state root is invalid. `true` otherwise.
|
||||||
pub fn is_state_root_valid(&self) -> bool {
|
pub fn is_state_root_valid(&self) -> bool {
|
||||||
self.state_root_memo.read().clone().map_or(true, |sr| sr == self.genesis_state.root())
|
// TODO: get rid of this function and ensure state root always is valid.
|
||||||
|
// we're mostly there, but `self.genesis_state.root()` doesn't encompass
|
||||||
|
// post-constructor state.
|
||||||
|
*self.state_root_memo.read() == self.genesis_state.root()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensure that the given state DB has the trie nodes in for the genesis state.
|
/// Ensure that the given state DB has the trie nodes in for the genesis state.
|
||||||
pub fn ensure_db_good(&self, mut db: StateDB, factories: &Factories) -> Result<StateDB, Box<TrieError>> {
|
pub fn ensure_db_good(&self, db: StateDB, factories: &Factories) -> Result<StateDB, Error> {
|
||||||
if db.as_hashdb().contains(&self.state_root()) {
|
if db.as_hashdb().contains(&self.state_root()) {
|
||||||
return Ok(db)
|
return Ok(db)
|
||||||
}
|
}
|
||||||
trace!(target: "spec", "ensure_db_good: Fresh database? Cannot find state root {}", self.state_root());
|
|
||||||
let mut root = H256::new();
|
|
||||||
|
|
||||||
{
|
// TODO: could optimize so we don't re-run, but `ensure_db_good` is barely ever
|
||||||
let mut t = factories.trie.create(db.as_hashdb_mut(), &mut root);
|
// called anyway.
|
||||||
for (address, account) in self.genesis_state.get().iter() {
|
let db = self.run_constructors(factories, db)?;
|
||||||
t.insert(&**address, &account.rlp())?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trace!(target: "spec", "ensure_db_good: Populated sec trie; root is {}", root);
|
|
||||||
for (address, account) in self.genesis_state.get().iter() {
|
|
||||||
db.note_non_null_account(address);
|
|
||||||
account.insert_additional(&mut AccountDBMut::new(db.as_hashdb_mut(), address), &factories.trie);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute contract constructors.
|
|
||||||
let env_info = EnvInfo {
|
|
||||||
number: 0,
|
|
||||||
author: self.author,
|
|
||||||
timestamp: self.timestamp,
|
|
||||||
difficulty: self.difficulty,
|
|
||||||
last_hashes: Default::default(),
|
|
||||||
gas_used: U256::zero(),
|
|
||||||
gas_limit: U256::max_value(),
|
|
||||||
};
|
|
||||||
let from = Address::default();
|
|
||||||
let start_nonce = self.engine.account_start_nonce();
|
|
||||||
|
|
||||||
let mut state = State::from_existing(db, root, start_nonce, factories.clone())?;
|
|
||||||
// Mutate the state with each constructor.
|
|
||||||
for &(ref address, ref constructor) in self.constructors.iter() {
|
|
||||||
trace!(target: "spec", "ensure_db_good: Creating a contract at {}.", address);
|
|
||||||
let params = ActionParams {
|
|
||||||
code_address: address.clone(),
|
|
||||||
code_hash: constructor.sha3(),
|
|
||||||
address: address.clone(),
|
|
||||||
sender: from.clone(),
|
|
||||||
origin: from.clone(),
|
|
||||||
gas: U256::max_value(),
|
|
||||||
gas_price: Default::default(),
|
|
||||||
value: ActionValue::Transfer(Default::default()),
|
|
||||||
code: Some(Arc::new(constructor.clone())),
|
|
||||||
data: None,
|
|
||||||
call_type: CallType::None,
|
|
||||||
};
|
|
||||||
let mut substate = Substate::new();
|
|
||||||
state.kill_account(address);
|
|
||||||
{
|
|
||||||
let mut exec = Executive::new(&mut state, &env_info, self.engine.as_ref(), &factories.vm);
|
|
||||||
if let Err(e) = exec.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer) {
|
|
||||||
warn!(target: "spec", "Genesis constructor execution at {} failed: {}.", address, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Err(e) = state.commit() {
|
|
||||||
warn!(target: "spec", "Genesis constructor trie commit at {} failed: {}.", address, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let (root, db) = state.drop();
|
|
||||||
|
|
||||||
*self.state_root_memo.write() = Some(root);
|
|
||||||
Ok(db)
|
Ok(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads spec from json file.
|
/// Loads spec from json file. Provide factories for executing contracts and ensuring
|
||||||
|
/// storage goes to the right place.
|
||||||
pub fn load<R>(reader: R) -> Result<Self, String> where R: Read {
|
pub fn load<R>(reader: R) -> Result<Self, String> where R: Read {
|
||||||
match ethjson::spec::Spec::load(reader) {
|
fn fmt<F: ::std::fmt::Display>(f: F) -> String {
|
||||||
Ok(spec) => Ok(spec.into()),
|
format!("Spec json is invalid: {}", f)
|
||||||
Err(e) => Err(format!("Spec json is invalid: {}", e)),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ethjson::spec::Spec::load(reader).map_err(fmt)
|
||||||
|
.and_then(|x| load_from(x).map_err(fmt))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new Spec which conforms to the Frontier-era Morden chain except that it's a NullEngine consensus.
|
/// Create a new Spec which conforms to the Frontier-era Morden chain except that it's a NullEngine consensus.
|
||||||
|
@ -206,7 +206,8 @@ impl<H: AsHashDB> Proving<H> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consume the backend, extracting the gathered proof.
|
/// Consume the backend, extracting the gathered proof in lexicographical order
|
||||||
|
/// by value.
|
||||||
pub fn extract_proof(self) -> Vec<DBValue> {
|
pub fn extract_proof(self) -> Vec<DBValue> {
|
||||||
self.proof.into_inner().into_iter().collect()
|
self.proof.into_inner().into_iter().collect()
|
||||||
}
|
}
|
||||||
@ -221,3 +222,33 @@ impl<H: AsHashDB + Clone> Clone for Proving<H> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A basic backend. Just wraps the given database, directly inserting into and deleting from
|
||||||
|
/// it. Doesn't cache anything.
|
||||||
|
pub struct Basic<H>(pub H);
|
||||||
|
|
||||||
|
impl<H: AsHashDB + Send + Sync> Backend for Basic<H> {
|
||||||
|
fn as_hashdb(&self) -> &HashDB {
|
||||||
|
self.0.as_hashdb()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_hashdb_mut(&mut self) -> &mut HashDB {
|
||||||
|
self.0.as_hashdb_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_to_account_cache(&mut self, _: Address, _: Option<Account>, _: bool) { }
|
||||||
|
|
||||||
|
fn cache_code(&self, _: H256, _: Arc<Vec<u8>>) { }
|
||||||
|
|
||||||
|
fn get_cached_account(&self, _: &Address) -> Option<Option<Account>> { None }
|
||||||
|
|
||||||
|
fn get_cached<F, U>(&self, _: &Address, _: F) -> Option<U>
|
||||||
|
where F: FnOnce(Option<&mut Account>) -> U
|
||||||
|
{
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_cached_code(&self, _: &H256) -> Option<Arc<Vec<u8>>> { None }
|
||||||
|
fn note_non_null_account(&self, _: &Address) { }
|
||||||
|
fn is_known_null(&self, _: &Address) -> bool { false }
|
||||||
|
}
|
||||||
|
@ -448,7 +448,8 @@ impl state::Backend for StateDB {
|
|||||||
fn is_known_null(&self, address: &Address) -> bool {
|
fn is_known_null(&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())
|
let is_null = !bloom.check(&*address.sha3());
|
||||||
|
is_null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "parity.js",
|
"name": "parity.js",
|
||||||
"version": "1.7.63",
|
"version": "1.7.64",
|
||||||
"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>",
|
||||||
|
@ -113,7 +113,15 @@ export default class Decoder {
|
|||||||
|
|
||||||
const str = taken.bytes.map((code) => String.fromCharCode(code)).join('');
|
const str = taken.bytes.map((code) => String.fromCharCode(code)).join('');
|
||||||
|
|
||||||
return new DecodeResult(new Token(param.type, utf8.decode(str)), offset + 1);
|
let decoded;
|
||||||
|
|
||||||
|
try {
|
||||||
|
decoded = utf8.decode(str);
|
||||||
|
} catch (error) {
|
||||||
|
decoded = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DecodeResult(new Token(param.type, decoded), offset + 1);
|
||||||
|
|
||||||
case 'array':
|
case 'array':
|
||||||
lengthOffset = asU32(Decoder.peek(slices, offset)).div(32).toNumber();
|
lengthOffset = asU32(Decoder.peek(slices, offset)).div(32).toNumber();
|
||||||
|
@ -38,6 +38,7 @@ describe('abi/decoder/Decoder', () => {
|
|||||||
const int1 = '0111111111111111111111111111111111111111111111111111111111111111';
|
const int1 = '0111111111111111111111111111111111111111111111111111111111111111';
|
||||||
const intn = 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85';
|
const intn = 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85';
|
||||||
const string1 = '6761766f66796f726b0000000000000000000000000000000000000000000000';
|
const string1 = '6761766f66796f726b0000000000000000000000000000000000000000000000';
|
||||||
|
const string2 = '4665726ee16e64657a0000000000000000000000000000000000000000000000';
|
||||||
const tokenAddress1 = new Token('address', `0x${address1.slice(-40)}`);
|
const tokenAddress1 = new Token('address', `0x${address1.slice(-40)}`);
|
||||||
const tokenAddress2 = new Token('address', `0x${address2.slice(-40)}`);
|
const tokenAddress2 = new Token('address', `0x${address2.slice(-40)}`);
|
||||||
const tokenAddress3 = new Token('address', `0x${address3.slice(-40)}`);
|
const tokenAddress3 = new Token('address', `0x${address3.slice(-40)}`);
|
||||||
@ -53,6 +54,7 @@ describe('abi/decoder/Decoder', () => {
|
|||||||
const tokenUint1 = new Token('uint', new BigNumber(int1, 16));
|
const tokenUint1 = new Token('uint', new BigNumber(int1, 16));
|
||||||
const tokenUintn = new Token('uint', new BigNumber(intn, 16));
|
const tokenUintn = new Token('uint', new BigNumber(intn, 16));
|
||||||
const tokenString1 = new Token('string', 'gavofyork');
|
const tokenString1 = new Token('string', 'gavofyork');
|
||||||
|
const tokenString2 = new Token('string', 'Fernández');
|
||||||
const slices = [ address1, address2, address3, address4 ];
|
const slices = [ address1, address2, address3, address4 ];
|
||||||
|
|
||||||
describe('peek', () => {
|
describe('peek', () => {
|
||||||
@ -160,6 +162,12 @@ describe('abi/decoder/Decoder', () => {
|
|||||||
).to.deep.equal(tokenString1);
|
).to.deep.equal(tokenString1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('decodes utf8-invalid string', () => {
|
||||||
|
expect(
|
||||||
|
Decoder.decodeParam(new ParamType('string'), [padU32(0x20), padU32(9), string2], 0).token
|
||||||
|
).to.deep.equal(tokenString2);
|
||||||
|
});
|
||||||
|
|
||||||
it('decodes string (indexed)', () => {
|
it('decodes string (indexed)', () => {
|
||||||
expect(
|
expect(
|
||||||
Decoder.decodeParam(new ParamType('string', null, 0, true), [bytes1], 0)
|
Decoder.decodeParam(new ParamType('string', null, 0, true), [bytes1], 0)
|
||||||
|
@ -83,7 +83,7 @@ fn make_spec(chain: &BlockChain) -> Spec {
|
|||||||
let genesis = Genesis::from(chain.genesis());
|
let genesis = Genesis::from(chain.genesis());
|
||||||
let mut spec = ethereum::new_frontier_test();
|
let mut spec = ethereum::new_frontier_test();
|
||||||
let state = chain.pre_state.clone().into();
|
let state = chain.pre_state.clone().into();
|
||||||
spec.set_genesis_state(state);
|
spec.set_genesis_state(state).expect("unable to set genesis state");
|
||||||
spec.overwrite_genesis_params(genesis);
|
spec.overwrite_genesis_params(genesis);
|
||||||
assert!(spec.is_state_root_valid());
|
assert!(spec.is_state_root_valid());
|
||||||
spec
|
spec
|
||||||
|
Loading…
Reference in New Issue
Block a user