Merge branch 'master' into ui-2

This commit is contained in:
Jaco Greeff 2017-05-03 10:40:53 +02:00
commit a1502738f1
22 changed files with 286 additions and 177 deletions

View File

@ -62,7 +62,7 @@ linux-stable:
name: "stable-x86_64-unknown-linux-gnu_parity"
linux-stable-debian:
stage: build
image: ethcore/rust-debian:latest
image: parity/rust-debian:gitlab-ci
only:
- beta
- tags
@ -146,7 +146,7 @@ linux-nightly:
allow_failure: true
linux-centos:
stage: build
image: ethcore/rust-centos:latest
image: parity/rust-centos:gitlab-ci
only:
- beta
- tags
@ -177,7 +177,7 @@ linux-centos:
name: "x86_64-unknown-centos-gnu_parity"
linux-i686:
stage: build
image: ethcore/rust-i686:latest
image: parity/rust-i686:gitlab-ci
only:
- beta
- tags
@ -217,7 +217,7 @@ linux-i686:
allow_failure: true
linux-armv7:
stage: build
image: ethcore/rust-armv7:latest
image: parity/rust-armv7:gitlab-ci
only:
- beta
- tags
@ -263,7 +263,7 @@ linux-armv7:
allow_failure: true
linux-arm:
stage: build
image: ethcore/rust-arm:latest
image: parity/rust-arm:gitlab-ci
only:
- beta
- tags
@ -348,7 +348,7 @@ linux-armv6:
allow_failure: true
linux-aarch64:
stage: build
image: ethcore/rust-aarch64:latest
image: parity/rust-arm64:gitlab-ci
only:
- beta
- tags
@ -560,7 +560,7 @@ test-rust-stable:
- rust-stable
js-test:
stage: test
image: ethcore/rust:stable
image: parity/rust:gitlab-ci
before_script:
- 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)
@ -574,11 +574,12 @@ test-rust-beta:
stage: test
only:
- triggers
image: ethcore/rust:beta
image: parity/rust:gitlab-ci
before_script:
- 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)
script:
- rustup default beta
- 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
tags:
@ -589,11 +590,12 @@ test-rust-nightly:
stage: test
only:
- triggers
image: ethcore/rust:nightly
image: parity/rust:gitlab-ci
before_script:
- 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)
script:
- rustup default stable
- 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
tags:
@ -607,12 +609,13 @@ js-release:
- beta
- stable
- tags
image: ethcore/rust:stable
image: parity/rust:gitlab-ci
before_script:
- export JS_FILES_MODIFIED=$(git --no-pager diff --name-only $CI_BUILD_REF^ $CI_BUILD_REF | grep ^js/ | wc -l)
- 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
script:
- rustup default stable
- 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
tags:
@ -621,8 +624,9 @@ push-release:
stage: push-release
only:
- tags
image: ethcore/rust:stable
image: parity/rust:gitlab-ci
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:1338/push-release/$CI_BUILD_REF_NAME/$CI_BUILD_REF
tags:

2
Cargo.lock generated
View File

@ -1778,7 +1778,7 @@ dependencies = [
[[package]]
name = "parity-ui-precompiled"
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 = [
"parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

View File

@ -31,7 +31,7 @@ const SECRETSTORE_ACL_STORAGE_ABI: &'static str = r#"[{"constant":true,"inputs":
// 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_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) {
let code = ::native_contract_generator::generate_module(name, abi).unwrap();

View File

@ -36,7 +36,7 @@
"0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
"0000000000000000000000000000000000000005": {
"balance": "1",
"constructor": "6060604052604060405190810160405280737d577a597b2742b498cb5cf0c26cdcd726d39e6e73ffffffffffffffffffffffffffffffffffffffff1681526020017382a978b3f5962a5b0957d9ee9eef472ee55b42f173ffffffffffffffffffffffffffffffffffffffff1681525060009060028280548282559060005260206000209081019282156100ec579160200282015b828111156100eb5782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555091602001919060010190610093565b5b50905061012f91905b8082111561012b57600081816101000a81549073ffffffffffffffffffffffffffffffffffffffff0219169055506001016100f5565b5090565b505034610000575b6000600090505b6000805490508110156101d5578060016000600084815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b808060010191505061013e565b5b505b6105f2806101e76000396000f30060606040523615610076576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806335aa2e441461007b5780634d238c8e146100d8578063b7ab4db51461010b578063bfc708a01461017d578063d8f2e0bf146101b0578063fd6e1b50146101ff575b610000565b34610000576100966004808035906020019091905050610232565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3461000057610109600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061026f565b005b346100005761011861030f565b604051808060200182810382528381815181526020019150805190602001906020028083836000831461016a575b80518252602083111561016a57602082019150602081019050602083039250610146565b5050509050019250505060405180910390f35b34610000576101ae600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506103ad565b005b34610000576101bd61055b565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3461000057610230600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610581565b005b600081815481101561000057906000526020600020900160005b915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600080548060010182818154818355818115116102b8578183600052602060002091820191016102b791905b808211156102b357600081600090555060010161029b565b5090565b5b505050916000526020600020900160005b83909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505b50565b602060405190810160405280600081525060008054806020026020016040519081016040528092919081815260200182805480156103a257602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610358575b505050505090505b90565b6000600160008054905003815481101561000057906000526020600020900160005b9054906101000a900473ffffffffffffffffffffffffffffffffffffffff166000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054815481101561000057906000526020600020900160005b6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600160008273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600090556000600160008054905003815481101561000057906000526020600020900160005b6101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905560008054809190600190038154818355818115116105535781836000526020600020918201910161055291905b8082111561054e576000816000905550600101610536565b5090565b5b505050505b50565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b505600a165627a7a7230582063a0123d8e8f5dde980af6b47e20acc5b7a1acac3e3101fa1c933471ef4b405c0029"
"constructor": "60a06040819052737d577a597b2742b498cb5cf0c26cdcd726d39e6e60609081527382a978b3f5962a5b0957d9ee9eef472ee55b42f1608052600080546002825581805290927f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5639182019291905b828111156100a25782518254600160a060020a031916600160a060020a0390911617825560209092019160019091019061006d565b5b506100cd9291505b808211156100c9578054600160a060020a03191681556001016100ab565b5090565b505034610000575b60005b60005481101561012f578060016000600084815481101561000057906000526020600020900160005b9054600160a060020a036101009290920a90041681526020810191909152604001600020555b6001016100d8565b5b505b610453806101416000396000f3006060604052361561005c5763ffffffff60e060020a60003504166335aa2e4481146100615780634d238c8e1461008d578063b7ab4db5146100a8578063c476dd4014610110578063d69f13bb14610172578063d8f2e0bf14610190575b610000565b34610000576100716004356101b9565b60408051600160a060020a039092168252519081900360200190f35b34610000576100a6600160a060020a03600435166101e9565b005b34610000576100b5610260565b60408051602080825283518183015283519192839290830191858101910280838382156100fd575b8051825260208311156100fd57601f1990920191602091820191016100dd565b5050509050019250505060405180910390f35b3461000057604080516020600460443581810135601f81018490048402850184019095528484526100a6948235600160a060020a03169460248035956064949293919092019181908401838280828437509496506102ca95505050505050565b005b34610000576100a6600160a060020a03600435166024356103eb565b005b3461000057610071610418565b60408051600160a060020a039092168252519081900360200190f35b600081815481101561000057906000526020600020900160005b915054906101000a9004600160a060020a031681565b6000805480600101828181548183558181151161022b5760008381526020902061022b9181019083015b808211156102275760008155600101610213565b5090565b5b505050916000526020600020900160005b8154600160a060020a038086166101009390930a92830292021916179055505b50565b60408051602081810183526000808352805484518184028101840190955280855292939290918301828280156102bf57602002820191906000526020600020905b8154600160a060020a031681526001909101906020018083116102a1575b505050505090505b90565b6000805460001981019081101561000057906000526020600020900160005b9054906101000a9004600160a060020a031660006001600086600160a060020a0316600160a060020a0316815260200190815260200160002054815481101561000057906000526020600020900160005b8154600160a060020a039384166101009290920a918202918402191617905583166000908152600160205260408120819055805460001981019081101561000057906000526020600020900160005b6101000a815490600160a060020a03021916905560008054809190600190038154818355818115116103e0576000838152602090206103e09181019083015b808211156102275760008155600101610213565b5090565b5b505050505b505050565b6002805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0384161790555b5050565b600254600160a060020a0316815600a165627a7a72305820f7876e17abd5f0927fff16788b4b3c9028ed64e6db740d788b07fc5f0a8f10920029"
},
"0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e": { "balance": "1606938044258990275541962092341162602522202993782792835301376" },
"0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1": { "balance": "1606938044258990275541962092341162602522202993782792835301376" }

View File

@ -78,6 +78,7 @@ pub struct AccountDB<'db> {
impl<'db> AccountDB<'db> {
/// Create a new AccountDB from an address.
#[cfg(test)]
pub fn new(db: &'db HashDB, address: &Address) -> Self {
Self::from_hash(db, address.sha3())
}
@ -131,6 +132,7 @@ pub struct AccountDBMut<'db> {
impl<'db> AccountDBMut<'db> {
/// Create a new AccountDB from an address.
#[cfg(test)]
pub fn new(db: &'db mut HashDB, address: &Address) -> Self {
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> {
AccountDB { db: self.db, address_hash: self.address_hash.clone() }
}

View File

@ -166,8 +166,7 @@ impl Client {
db: Arc<KeyValueDB>,
miner: Arc<Miner>,
message_channel: IoChannel<ClientIoMessage>,
) -> Result<Arc<Client>, ClientError> {
) -> Result<Arc<Client>, ::error::Error> {
let trie_spec = match config.fat_db {
true => TrieSpec::Fat,
false => TrieSpec::Secure,

View File

@ -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.
if step.is_future(header_step) {
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)?
} else {
let proposer_signature = header_signature(header)?;
@ -381,7 +381,7 @@ impl Engine for AuthorityRound {
let parent_step = header_step(parent)?;
if 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()))?;
}

View File

@ -471,8 +471,8 @@ impl Engine for Tendermint {
return Err(EngineError::NotAuthorized(sender).into());
}
self.broadcast_message(rlp.as_raw().to_vec());
if self.votes.vote(message.clone(), &sender).is_some() {
self.validators.report_malicious(&sender);
if let Some(double) = self.votes.vote(message.clone(), &sender) {
self.validators.report_malicious(&sender, message.vote_step.height as BlockNumber, ::rlp::encode(&double).to_vec());
return Err(EngineError::DoubleVote(sender).into());
}
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 max_gas = parent.gas_limit().clone() + parent.gas_limit().clone() / gas_limit_divisor;
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());
}
@ -610,8 +610,9 @@ impl Engine for Tendermint {
trace!(target: "engine", "Propose timeout.");
if self.proposal.read().is_none() {
// 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));
self.validators.report_benign(&current_proposer);
let height = self.height.load(AtomicOrdering::SeqCst);
let current_proposer = self.view_proposer(&*self.proposal_parent.read(), height, self.view.load(AtomicOrdering::SeqCst));
self.validators.report_benign(&current_proposer, height as BlockNumber);
}
Step::Prevote
},

View File

@ -25,7 +25,7 @@ use native_contracts::ValidatorReport as Provider;
use client::{Client, BlockChainClient};
use engines::Call;
use header::Header;
use header::{Header, BlockNumber};
use super::ValidatorSet;
use super::safe_contract::ValidatorSafeContract;
@ -92,15 +92,15 @@ impl ValidatorSet for ValidatorContract {
self.validators.count_with_caller(bh, caller)
}
fn report_malicious(&self, address: &Address) {
match self.provider.report_malicious(&*self.transact(), *address).wait() {
fn report_malicious(&self, address: &Address, block: BlockNumber, proof: Bytes) {
match self.provider.report_malicious(&*self.transact(), *address, block.into(), proof).wait() {
Ok(_) => warn!(target: "engine", "Reported malicious validator {}", address),
Err(s) => warn!(target: "engine", "Validator {} could not be reported {}", address, s),
}
}
fn report_benign(&self, address: &Address) {
match self.provider.report_benign(&*self.transact(), *address).wait() {
fn report_benign(&self, address: &Address, block: BlockNumber) {
match self.provider.report_benign(&*self.transact(), *address, block.into()).wait() {
Ok(_) => warn!(target: "engine", "Reported benign validator misbehaviour {}", address),
Err(s) => warn!(target: "engine", "Validator {} could not be reported {}", address, s),
}

View File

@ -23,10 +23,10 @@ mod multi;
use std::sync::Weak;
use ids::BlockId;
use util::{Address, H256};
use util::{Bytes, Address, H256};
use ethjson::spec::ValidatorSet as ValidatorSpec;
use client::Client;
use header::Header;
use header::{Header, BlockNumber};
pub use self::simple_list::SimpleList;
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;
/// Notifies about malicious behaviour.
fn report_malicious(&self, _validator: &Address) {}
fn report_malicious(&self, _validator: &Address, _block: BlockNumber, _proof: Bytes) {}
/// Notifies about benign misbehaviour.
fn report_benign(&self, _validator: &Address) {}
fn report_benign(&self, _validator: &Address, _block: BlockNumber) {}
/// Allows blockchain state access.
fn register_contract(&self, _client: Weak<Client>) {}
}

View File

@ -19,7 +19,7 @@
use std::collections::BTreeMap;
use std::sync::Weak;
use engines::{Call, EpochChange};
use util::{H256, Address, RwLock};
use util::{Bytes, H256, Address, RwLock};
use ids::BlockId;
use header::{BlockNumber, Header};
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))
}
fn report_malicious(&self, validator: &Address) {
for set in self.sets.values() {
set.report_malicious(validator);
}
fn report_malicious(&self, validator: &Address, block: BlockNumber, proof: Bytes) {
self.correct_set_by_number(block).1.report_malicious(validator, block, proof);
}
fn report_benign(&self, validator: &Address) {
for set in self.sets.values() {
set.report_benign(validator);
}
fn report_benign(&self, validator: &Address, block: BlockNumber) {
self.correct_set_by_number(block).1.report_benign(validator, block);
}
fn register_contract(&self, client: Weak<Client>) {

View File

@ -18,7 +18,7 @@
use std::fmt::Debug;
use util::*;
use rlp::Encodable;
use rlp::{Encodable, RlpStream};
pub trait Message: Clone + PartialEq + Eq + Hash + Encodable + Debug {
type Round: Clone + PartialEq + Eq + Hash + Default + Debug + Ord;
@ -40,25 +40,44 @@ pub struct VoteCollector<M: Message> {
#[derive(Debug, Default)]
struct StepCollector<M: Message> {
voted: HashSet<Address>,
voted: HashMap<Address, M>,
pub block_votes: HashMap<Option<H256>, HashMap<H520, Address>>,
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> {
/// 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.
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
.block_votes
.entry(message.block_hash())
.or_insert_with(HashMap::new)
.insert(message.signature(), address.clone());
} else {
// Bad validator sent a different message.
return Some(address);
}
}
None
@ -101,7 +120,7 @@ impl <M: Message + Default> Default for VoteCollector<M> {
impl <M: Message + Default + Encodable + Debug> VoteCollector<M> {
/// 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
.votes
.write()
@ -220,11 +239,11 @@ mod tests {
}
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> {
collector.vote(TestMessage { signature: signature, step: step, block_hash: block_hash }, 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).is_none()
}
#[test]
@ -319,9 +338,9 @@ mod tests {
let collector = VoteCollector::default();
let round = 3;
// 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.
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);
}
}

View File

@ -95,6 +95,7 @@ mod tests {
let engine = &spec.engine;
let genesis_header = spec.genesis_header();
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();
assert_eq!(s.balance(&"0000000000000000000000000000000000000001".into()).unwrap(), 1u64.into());
assert_eq!(s.balance(&"0000000000000000000000000000000000000002".into()).unwrap(), 1u64.into());

View File

@ -51,7 +51,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
ChainEra::_Eip161 => ethereum::new_eip161_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);
assert!(spec.is_state_root_valid());
spec

View File

@ -16,7 +16,6 @@
use util::*;
use state::Account;
use account_db::AccountDBMut;
use ethjson;
use types::account_diff::*;
use rlp::{self, RlpStream};
@ -64,7 +63,7 @@ impl PodAccount {
}
/// 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 {
Some(ref c) if !c.is_empty() => { db.insert(c); }
_ => {}

View File

@ -16,25 +16,27 @@
//! 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::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 ethjson;
use executive::Executive;
use factory::Factories;
use header::{BlockNumber, Header};
use pod_state::*;
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.
#[derive(Debug, PartialEq, Clone, Default)]
@ -119,39 +121,46 @@ pub struct Spec {
constructors: Vec<(Address, Bytes)>,
/// 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: PodState,
}
impl From<ethjson::spec::Spec> for Spec {
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 g = Genesis::from(s.genesis);
let GenericSeal(seal_rlp) = g.seal.into();
let params = CommonParams::from(s.params);
Spec {
name: s.name.clone().into(),
params: params.clone(),
engine: Spec::engine(s.engine, params, builtins),
data_dir: s.data_dir.unwrap_or(s.name).into(),
nodes: s.nodes.unwrap_or_else(Vec::new),
parent_hash: g.parent_hash,
transactions_root: g.transactions_root,
receipts_root: g.receipts_root,
author: g.author,
difficulty: g.difficulty,
gas_limit: g.gas_limit,
gas_used: g.gas_used,
timestamp: g.timestamp,
extra_data: g.extra_data,
seal_rlp: seal_rlp,
constructors: s.accounts.constructors().into_iter().map(|(a, c)| (a.into(), c.into())).collect(),
state_root_memo: RwLock::new(g.state_root),
genesis_state: From::from(s.accounts),
}
fn load_from(s: ethjson::spec::Spec) -> Result<Spec, Error> {
let builtins = s.accounts.builtins().into_iter().map(|p| (p.0.into(), From::from(p.1))).collect();
let g = Genesis::from(s.genesis);
let GenericSeal(seal_rlp) = g.seal.into();
let params = CommonParams::from(s.params);
let mut s = Spec {
name: s.name.clone().into(),
params: params.clone(),
engine: Spec::engine(s.engine, params, builtins),
data_dir: s.data_dir.unwrap_or(s.name).into(),
nodes: s.nodes.unwrap_or_else(Vec::new),
parent_hash: g.parent_hash,
transactions_root: g.transactions_root,
receipts_root: g.receipts_root,
author: g.author,
difficulty: g.difficulty,
gas_limit: g.gas_limit,
gas_used: g.gas_used,
timestamp: g.timestamp,
extra_data: g.extra_data,
seal_rlp: seal_rlp,
constructors: s.accounts.constructors().into_iter().map(|(a, c)| (a.into(), c.into())).collect(),
state_root_memo: RwLock::new(Default::default()), // will be overwritten right after.
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 {
@ -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.
pub fn state_root(&self) -> H256 {
if self.state_root_memo.read().is_none() {
*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")
self.state_root_memo.read().clone()
}
/// Get the known knodes of the network in enode format.
@ -243,95 +332,46 @@ impl Spec {
self.timestamp = g.timestamp;
self.extra_data = g.extra_data;
self.seal_rlp = seal_rlp;
self.state_root_memo = RwLock::new(g.state_root);
}
/// 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.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.
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.
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()) {
return Ok(db)
}
trace!(target: "spec", "ensure_db_good: Fresh database? Cannot find state root {}", self.state_root());
let mut root = H256::new();
{
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())?;
}
}
// TODO: could optimize so we don't re-run, but `ensure_db_good` is barely ever
// called anyway.
let db = self.run_constructors(factories, db)?;
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)
}
/// 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 {
match ethjson::spec::Spec::load(reader) {
Ok(spec) => Ok(spec.into()),
Err(e) => Err(format!("Spec json is invalid: {}", e)),
fn fmt<F: ::std::fmt::Display>(f: F) -> String {
format!("Spec json is invalid: {}", f)
}
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.

View File

@ -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> {
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 }
}

View File

@ -448,7 +448,8 @@ impl state::Backend for StateDB {
fn is_known_null(&self, address: &Address) -> bool {
trace!(target: "account_bloom", "Check account bloom: {:?}", address);
let bloom = self.account_bloom.lock();
!bloom.check(&*address.sha3())
let is_null = !bloom.check(&*address.sha3());
is_null
}
}

View File

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

View File

@ -113,7 +113,15 @@ export default class Decoder {
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':
lengthOffset = asU32(Decoder.peek(slices, offset)).div(32).toNumber();

View File

@ -38,6 +38,7 @@ describe('abi/decoder/Decoder', () => {
const int1 = '0111111111111111111111111111111111111111111111111111111111111111';
const intn = 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85';
const string1 = '6761766f66796f726b0000000000000000000000000000000000000000000000';
const string2 = '4665726ee16e64657a0000000000000000000000000000000000000000000000';
const tokenAddress1 = new Token('address', `0x${address1.slice(-40)}`);
const tokenAddress2 = new Token('address', `0x${address2.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 tokenUintn = new Token('uint', new BigNumber(intn, 16));
const tokenString1 = new Token('string', 'gavofyork');
const tokenString2 = new Token('string', 'Fernández');
const slices = [ address1, address2, address3, address4 ];
describe('peek', () => {
@ -160,6 +162,12 @@ describe('abi/decoder/Decoder', () => {
).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)', () => {
expect(
Decoder.decodeParam(new ParamType('string', null, 0, true), [bytes1], 0)

View File

@ -83,7 +83,7 @@ fn make_spec(chain: &BlockChain) -> Spec {
let genesis = Genesis::from(chain.genesis());
let mut spec = ethereum::new_frontier_test();
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);
assert!(spec.is_state_root_valid());
spec