ethabi version 5 (#7723)

* Refactor updater to use ethabi-derive

* Grumble: do_call type alias

* Empty commit to trigger test re-run

* migration to ethabi-5.0

* migration to ethabi-5.0 in progress

* use ethabi_deriven to generate TransactAcl contract

* use ethabi_deriven to generate Registry contract

* hash-fetch uses ethabi_derive, removed retain cycle from updater, fixed #7720

* node-filter crate uses ethabi_derive to generate peer_set contract interface

* use LruCache in node-filter instead of HashMap

* validator_set engine uses ethabi_derive

* ethcore does not depend on native_contracts

* miner does no depend on native_contracts

* secret_store does not use native_contracts (in progress)

* removed native-contracts

* ethcore and updater does not depend on futures

* updated ethereum-types

* fixed all warnings caused by using new version of ethereum-types

* updated ethabi_derive && ethabi_contract to get rid of warnings

* removed another retain cycle in updater, fixed following minor version on update

* moved contracts out of native_contracts res

* updated ethabi_contract

* fixed failing test

* fixed failing test

* there is no need to create two contracts of the same kind any more

* simplify updater::ReleaseTrack conversion into u8 and add several tests for it

* applied review suggestions

* applied review suggestions
This commit is contained in:
Marek Kotewicz
2018-02-09 09:32:06 +01:00
committed by GitHub
parent 2c60a53fef
commit c060d9584d
129 changed files with 1678 additions and 2173 deletions

View File

@@ -50,13 +50,11 @@ use vm::{EnvInfo, LastHashes};
use evm::{Factory as EvmFactory, Schedule};
use executive::{Executive, Executed, TransactOptions, contract_address};
use factory::Factories;
use futures::{future, Future};
use header::{BlockNumber, Header, Seal};
use io::*;
use log_entry::LocalizedLogEntry;
use miner::{Miner, MinerService};
use native_contracts::Registry;
use parking_lot::{Mutex, RwLock, MutexGuard};
use parking_lot::{Mutex, RwLock};
use rand::OsRng;
use receipt::{Receipt, LocalizedReceipt};
use rlp::UntrustedRlp;
@@ -82,6 +80,8 @@ pub use types::block_status::BlockStatus;
pub use blockchain::CacheSize as BlockChainCacheSize;
pub use verification::queue::QueueInfo as BlockQueueInfo;
use_contract!(registry, "Registry", "res/contracts/registrar.json");
const MAX_TX_QUEUE_SIZE: usize = 4096;
const MAX_QUEUE_SIZE_TO_SLEEP_ON: usize = 2;
const MIN_HISTORY_SIZE: u64 = 8;
@@ -165,7 +165,8 @@ pub struct Client {
history: u64,
ancient_verifier: Mutex<Option<AncientVerifier>>,
on_user_defaults_change: Mutex<Option<Box<FnMut(Option<Mode>) + 'static + Send>>>,
registrar: Mutex<Option<Registry>>,
registrar: registry::Registry,
registrar_address: Option<Address>,
exit_handler: Mutex<Option<Box<Fn(bool, Option<String>) + 'static + Send>>>,
}
@@ -217,7 +218,7 @@ impl Client {
};
if !chain.block_header(&chain.best_block_hash()).map_or(true, |h| state_db.journal_db().contains(h.state_root())) {
warn!("State root not found for block #{} ({})", chain.best_block_number(), chain.best_block_hash().hex());
warn!("State root not found for block #{} ({:x})", chain.best_block_number(), chain.best_block_hash());
}
let engine = spec.engine.clone();
@@ -226,6 +227,11 @@ impl Client {
let awake = match config.mode { Mode::Dark(..) | Mode::Off => false, _ => true };
let registrar_address = engine.additional_params().get("registrar").and_then(|s| Address::from_str(s).ok());
if let Some(ref addr) = registrar_address {
trace!(target: "client", "Found registrar at {}", addr);
}
let client = Arc::new(Client {
enabled: AtomicBool::new(true),
sleep_state: Mutex::new(SleepState::new(awake)),
@@ -251,7 +257,8 @@ impl Client {
history: history,
ancient_verifier: Mutex::new(None),
on_user_defaults_change: Mutex::new(None),
registrar: Mutex::new(None),
registrar: registry::Registry::default(),
registrar_address,
exit_handler: Mutex::new(None),
});
@@ -294,12 +301,6 @@ impl Client {
}
}
if let Some(reg_addr) = client.additional_params().get("registrar").and_then(|s| Address::from_str(s).ok()) {
trace!(target: "client", "Found registrar at {}", reg_addr);
let registrar = Registry::new(reg_addr);
*client.registrar.lock() = Some(registrar);
}
// ensure buffered changes are flushed.
client.db.read().flush().map_err(ClientError::Database)?;
Ok(client)
@@ -340,11 +341,6 @@ impl Client {
}
}
/// Get the Registry object - useful for looking up names.
pub fn registrar(&self) -> MutexGuard<Option<Registry>> {
self.registrar.lock()
}
/// Register an action to be done if a mode/spec_name change happens.
pub fn on_user_defaults_change<F>(&self, f: F) where F: 'static + FnMut(Option<Mode>) + Send {
*self.on_user_defaults_change.lock() = Some(Box::new(f));
@@ -1828,18 +1824,24 @@ impl BlockChainClient for Client {
}
fn registrar_address(&self) -> Option<Address> {
self.registrar.lock().as_ref().map(|r| r.address)
self.registrar_address.clone()
}
fn registry_address(&self, name: String) -> Option<Address> {
self.registrar.lock().as_ref()
.and_then(|r| {
let dispatch = move |reg_addr, data| {
future::done(self.call_contract(BlockId::Latest, reg_addr, data))
};
r.get_address(dispatch, keccak(name.as_bytes()), "A".to_string()).wait().ok()
let address = match self.registrar_address {
Some(address) => address,
None => return None,
};
self.registrar.functions()
.get_address()
.call(keccak(name.as_bytes()), "A", &|data| self.call_contract(BlockId::Latest, address, data))
.ok()
.and_then(|a| if a.is_zero() {
None
} else {
Some(a)
})
.and_then(|a| if a.is_zero() { None } else { Some(a) })
}
fn eip86_transition(&self) -> u64 {

View File

@@ -18,12 +18,10 @@
/// It can also report validators for misbehaviour with two levels: `reportMalicious` and `reportBenign`.
use std::sync::Weak;
use bytes::Bytes;
use ethereum_types::{H256, Address};
use parking_lot::RwLock;
use bytes::Bytes;
use futures::Future;
use native_contracts::ValidatorReport as Provider;
use client::EngineClient;
use header::{Header, BlockNumber};
@@ -32,40 +30,41 @@ use machine::{AuxiliaryData, Call, EthereumMachine};
use super::{ValidatorSet, SimpleList, SystemCall};
use super::safe_contract::ValidatorSafeContract;
use_contract!(validator_report, "ValidatorReport", "res/contracts/validator_report.json");
/// A validator contract with reporting.
pub struct ValidatorContract {
contract_address: Address,
validators: ValidatorSafeContract,
provider: Provider,
provider: validator_report::ValidatorReport,
client: RwLock<Option<Weak<EngineClient>>>, // TODO [keorn]: remove
}
impl ValidatorContract {
pub fn new(contract_address: Address) -> Self {
ValidatorContract {
contract_address,
validators: ValidatorSafeContract::new(contract_address),
provider: Provider::new(contract_address),
provider: validator_report::ValidatorReport::default(),
client: RwLock::new(None),
}
}
}
impl ValidatorContract {
// could be `impl Trait`.
// note: dispatches transactions to network as well as execute.
// TODO [keorn]: Make more general.
fn transact(&self) -> Box<Fn(Address, Bytes) -> Result<Bytes, String>> {
let client = self.client.read().clone();
Box::new(move |a, d| client.as_ref()
fn transact(&self, data: Bytes) -> Result<(), String> {
let client = self.client.read().as_ref()
.and_then(Weak::upgrade)
.ok_or_else(|| "No client!".into())
.and_then(|c| {
match c.as_full_client() {
Some(c) => c.transact_contract(a, d)
.map_err(|e| format!("Transaction import error: {}", e)),
None => Err("No full client!".into()),
}
})
.map(|_| Default::default()))
.ok_or_else(|| "No client!")?;
match client.as_full_client() {
Some(c) => {
c.transact_contract(self.contract_address, data)
.map_err(|e| format!("Transaction import error: {}", e))?;
Ok(())
},
None => Err("No full client!".into()),
}
}
}
@@ -112,14 +111,16 @@ impl ValidatorSet for ValidatorContract {
}
fn report_malicious(&self, address: &Address, _set_block: BlockNumber, block: BlockNumber, proof: Bytes) {
match self.provider.report_malicious(&*self.transact(), *address, block.into(), proof).wait() {
let data = self.provider.functions().report_malicious().input(*address, block, proof);
match self.transact(data) {
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, _set_block: BlockNumber, block: BlockNumber) {
match self.provider.report_benign(&*self.transact(), *address, block.into()).wait() {
let data = self.provider.functions().report_benign().input(*address, block);
match self.transact(data) {
Ok(_) => warn!(target: "engine", "Reported benign validator misbehaviour {}", address),
Err(s) => warn!(target: "engine", "Validator {} could not be reported {}", address, s),
}

View File

@@ -17,11 +17,9 @@
/// Validator set maintained in a contract, updated using `getValidators` method.
use std::sync::{Weak, Arc};
use futures::Future;
use native_contracts::ValidatorSet as Provider;
use hash::keccak;
use ethereum_types::{H160, H256, U256, Address, Bloom};
use ethereum_types::{H256, U256, Address, Bloom};
use parking_lot::{Mutex, RwLock};
use bytes::Bytes;
@@ -40,6 +38,8 @@ use receipt::Receipt;
use super::{SystemCall, ValidatorSet};
use super::simple_list::SimpleList;
use_contract!(validator_set, "ValidatorSet", "res/contracts/validator_set.json");
const MEMOIZE_CAPACITY: usize = 500;
// TODO: ethabi should be able to generate this.
@@ -52,13 +52,14 @@ lazy_static! {
// state-dependent proofs for the safe contract:
// only "first" proofs are such.
struct StateProof {
contract_address: Address,
header: Mutex<Header>,
provider: Provider,
provider: validator_set::ValidatorSet,
}
impl ::engines::StateDependentProof<EthereumMachine> for StateProof {
fn generate_proof(&self, caller: &Call) -> Result<Vec<u8>, String> {
prove_initial(&self.provider, &*self.header.lock(), caller)
prove_initial(&self.provider, self.contract_address, &*self.header.lock(), caller)
}
fn check_proof(&self, machine: &EthereumMachine, proof: &[u8]) -> Result<(), String> {
@@ -68,15 +69,15 @@ impl ::engines::StateDependentProof<EthereumMachine> for StateProof {
return Err("wrong header in proof".into());
}
check_first_proof(machine, &self.provider, header, &state_items).map(|_| ())
check_first_proof(machine, &self.provider, self.contract_address, header, &state_items).map(|_| ())
}
}
/// The validator contract should have the following interface:
pub struct ValidatorSafeContract {
pub address: Address,
contract_address: Address,
validators: RwLock<MemoryLruCache<H256, SimpleList>>,
provider: Provider,
provider: validator_set::ValidatorSet,
client: RwLock<Option<Weak<EngineClient>>>, // TODO [keorn]: remove
}
@@ -92,7 +93,7 @@ fn encode_first_proof(header: &Header, state_items: &[Vec<u8>]) -> Bytes {
}
// check a first proof: fetch the validator set at the given block.
fn check_first_proof(machine: &EthereumMachine, provider: &Provider, old_header: Header, state_items: &[DBValue])
fn check_first_proof(machine: &EthereumMachine, provider: &validator_set::ValidatorSet, contract_address: Address, old_header: Header, state_items: &[DBValue])
-> Result<Vec<Address>, String>
{
use transaction::{Action, Transaction};
@@ -117,15 +118,15 @@ fn check_first_proof(machine: &EthereumMachine, provider: &Provider, old_header:
// check state proof using given machine.
let number = old_header.number();
provider.get_validators(move |a, d| {
provider.functions().get_validators().call(&|data| {
let from = Address::default();
let tx = Transaction {
nonce: machine.account_start_nonce(number),
action: Action::Call(a),
action: Action::Call(contract_address),
gas: PROVIDED_GAS.into(),
gas_price: U256::default(),
value: U256::default(),
data: d,
data,
}.fake_sign(from);
let res = ::state::check_proof(
@@ -141,7 +142,7 @@ fn check_first_proof(machine: &EthereumMachine, provider: &Provider, old_header:
::state::ProvedExecution::Failed(e) => Err(format!("Failed call: {}", e)),
::state::ProvedExecution::Complete(e) => Ok(e.output),
}
}).wait()
}).map_err(|err| err.to_string())
}
fn decode_first_proof(rlp: &UntrustedRlp) -> Result<(Header, Vec<DBValue>), ::error::Error> {
@@ -170,18 +171,19 @@ fn decode_proof(rlp: &UntrustedRlp) -> Result<(Header, Vec<Receipt>), ::error::E
// given a provider and caller, generate proof. this will just be a state proof
// of `getValidators`.
fn prove_initial(provider: &Provider, header: &Header, caller: &Call) -> Result<Vec<u8>, String> {
fn prove_initial(provider: &validator_set::ValidatorSet, contract_address: Address, header: &Header, caller: &Call) -> Result<Vec<u8>, String> {
use std::cell::RefCell;
let epoch_proof = RefCell::new(None);
let res = {
let caller = |a, d| {
let (result, proof) = caller(a, d)?;
let caller = |data| {
let (result, proof) = caller(contract_address, data)?;
*epoch_proof.borrow_mut() = Some(encode_first_proof(header, &proof));
Ok(result)
};
provider.get_validators(caller).wait()
provider.functions().get_validators().call(&caller)
.map_err(|err| err.to_string())
};
res.map(|validators| {
@@ -200,17 +202,18 @@ fn prove_initial(provider: &Provider, header: &Header, caller: &Call) -> Result<
impl ValidatorSafeContract {
pub fn new(contract_address: Address) -> Self {
ValidatorSafeContract {
address: contract_address,
contract_address,
validators: RwLock::new(MemoryLruCache::new(MEMOIZE_CAPACITY)),
provider: Provider::new(contract_address),
provider: validator_set::ValidatorSet::default(),
client: RwLock::new(None),
}
}
/// Queries the state and gets the set of validators.
fn get_list(&self, caller: &Call) -> Option<SimpleList> {
let caller = move |a, d| caller(a, d).map(|x| x.0);
match self.provider.get_validators(caller).wait() {
let contract_address = self.contract_address;
let caller = move |data| caller(contract_address, data).map(|x| x.0);
match self.provider.functions().get_validators().call(&caller) {
Ok(new) => {
debug!(target: "engine", "Set of validators obtained: {:?}", new);
Some(SimpleList::new(new))
@@ -244,7 +247,7 @@ impl ValidatorSafeContract {
header.hash(), topics);
LogEntry {
address: self.address,
address: self.contract_address,
topics: topics,
data: Vec::new(), // irrelevant for bloom.
}.bloom()
@@ -254,52 +257,29 @@ impl ValidatorSafeContract {
// header the receipts correspond to.
fn extract_from_event(&self, bloom: Bloom, header: &Header, receipts: &[Receipt]) -> Option<SimpleList> {
let check_log = |log: &LogEntry| {
log.address == self.address &&
log.address == self.contract_address &&
log.topics.len() == 2 &&
log.topics[0] == *EVENT_NAME_HASH &&
log.topics[1] == *header.parent_hash()
};
let event = Provider::contract(&self.provider)
.event("InitiateChange".into())
.expect("Contract known ahead of time to have `InitiateChange` event; qed");
// iterate in reverse because only the _last_ change in a given
// block actually has any effect.
// the contract should only increment the nonce once.
let event = self.provider.events().initiate_change();
//// iterate in reverse because only the _last_ change in a given
//// block actually has any effect.
//// the contract should only increment the nonce once.
let mut decoded_events = receipts.iter()
.rev()
.filter(|r| &bloom & &r.log_bloom == bloom)
.filter(|r| r.log_bloom.contains_bloom(&bloom))
.flat_map(|r| r.logs.iter())
.filter(move |l| check_log(l))
.filter_map(|log| {
let topics = log.topics.iter().map(|x| x.0.clone()).collect();
event.parse_log((topics, log.data.clone()).into()).ok()
event.parse_log((log.topics.clone(), log.data.clone()).into()).ok()
});
// only last log is taken into account
match decoded_events.next() {
None => None,
Some(matched_event) => {
// decode log manually until the native contract generator is
// good enough to do it for us.
let validators_token = &matched_event.params[1].value;
let validators = validators_token.clone().to_array()
.and_then(|a| a.into_iter()
.map(|x| x.to_address().map(H160))
.collect::<Option<Vec<_>>>()
)
.map(SimpleList::new);
if validators.is_none() {
debug!(target: "engine", "Successfully decoded log turned out to be bad.");
}
trace!(target: "engine", "decoded log. validators: {:?}", validators);
validators
}
Some(matched_event) => Some(SimpleList::new(matched_event.new_set))
}
}
}
@@ -320,14 +300,15 @@ impl ValidatorSet for ValidatorSafeContract {
}
fn on_epoch_begin(&self, _first: bool, _header: &Header, caller: &mut SystemCall) -> Result<(), ::error::Error> {
self.provider.finalize_change(caller)
.wait()
let data = self.provider.functions().finalize_change().input();
caller(self.contract_address, data)
.map(|_| ())
.map_err(::engines::EngineError::FailedSystemCall)
.map_err(Into::into)
}
fn genesis_epoch_data(&self, header: &Header, call: &Call) -> Result<Vec<u8>, String> {
prove_initial(&self.provider, header, call)
prove_initial(&self.provider, self.contract_address, header, call)
}
fn is_epoch_end(&self, _first: bool, _chain_head: &Header) -> Option<Vec<u8>> {
@@ -343,8 +324,9 @@ impl ValidatorSet for ValidatorSafeContract {
if first {
debug!(target: "engine", "signalling transition to fresh contract.");
let state_proof = Arc::new(StateProof {
contract_address: self.contract_address,
header: Mutex::new(header.clone()),
provider: self.provider.clone(),
provider: validator_set::ValidatorSet::default(),
});
return ::engines::EpochChange::Yes(::engines::Proof::WithState(state_proof as Arc<_>));
}
@@ -383,7 +365,7 @@ impl ValidatorSet for ValidatorSafeContract {
let (old_header, state_items) = decode_first_proof(&rlp)?;
let number = old_header.number();
let old_hash = old_header.hash();
let addresses = check_first_proof(machine, &self.provider, old_header, &state_items)
let addresses = check_first_proof(machine, &self.provider, self.contract_address, old_header, &state_items)
.map_err(::engines::EngineError::InsufficientProof)?;
trace!(target: "engine", "extracted epoch set at #{}: {} addresses",

View File

@@ -175,8 +175,8 @@ impl Engine<EthereumMachine> for Arc<Ethash> {
fn extra_info(&self, header: &Header) -> BTreeMap<String, String> {
if header.seal().len() == self.seal_fields() {
map![
"nonce".to_owned() => format!("0x{}", header.nonce().hex()),
"mixHash".to_owned() => format!("0x{}", header.mix_hash().hex())
"nonce".to_owned() => format!("0x{:x}", header.nonce()),
"mixHash".to_owned() => format!("0x{:x}", header.mix_hash())
]
} else {
BTreeMap::default()
@@ -384,9 +384,9 @@ impl Ethash {
let diff_inc = (header.timestamp() - parent.timestamp()) / increment_divisor;
if diff_inc <= threshold {
*parent.difficulty() + *parent.difficulty() / difficulty_bound_divisor * (threshold - diff_inc).into()
*parent.difficulty() + *parent.difficulty() / difficulty_bound_divisor * U256::from(threshold - diff_inc)
} else {
let multiplier = cmp::min(diff_inc - threshold, 99).into();
let multiplier: U256 = cmp::min(diff_inc - threshold, 99).into();
parent.difficulty().saturating_sub(
*parent.difficulty() / difficulty_bound_divisor * multiplier
)
@@ -474,6 +474,7 @@ mod tests {
use error::{BlockError, Error};
use header::Header;
use spec::Spec;
use engines::Engine;
use super::super::{new_morden, new_mcip3_test, new_homestead_test_machine};
use super::{Ethash, EthashParams, ecip1017_eras_block_reward};
use rlp;
@@ -849,4 +850,16 @@ mod tests {
let difficulty = ethash.calculate_difficulty(&header, &parent_header);
assert_eq!(U256::from(12543204905719u64), difficulty);
}
#[test]
fn test_extra_info() {
let machine = new_homestead_test_machine();
let ethparams = get_default_ethash_params();
let ethash = Ethash::new(&::std::env::temp_dir(), ethparams, machine, None);
let mut header = Header::default();
header.set_seal(vec![rlp::encode(&H256::from("b251bd2e0283d0658f2cadfdc8ca619b5de94eca5742725e2e757dd13ed7503d")).into_vec(), rlp::encode(&H64::zero()).into_vec()]);
let info = ethash.extra_info(&header);
assert_eq!(info["nonce"], "0x0000000000000000");
assert_eq!(info["mixHash"], "0xb251bd2e0283d0658f2cadfdc8ca619b5de94eca5742725e2e757dd13ed7503d");
}
}

View File

@@ -71,12 +71,10 @@ extern crate ethcore_transaction as transaction;
extern crate ethereum_types;
extern crate ethjson;
extern crate ethkey;
extern crate futures;
extern crate hardware_wallet;
extern crate hashdb;
extern crate itertools;
extern crate lru_cache;
extern crate native_contracts;
extern crate num_cpus;
extern crate num;
extern crate parity_machine;
@@ -99,6 +97,12 @@ extern crate util_error;
extern crate snappy;
extern crate migration;
extern crate ethabi;
#[macro_use]
extern crate ethabi_derive;
#[macro_use]
extern crate ethabi_contract;
#[macro_use]
extern crate rlp_derive;
extern crate rustc_hex;

View File

@@ -220,7 +220,7 @@ impl EthereumMachine {
let total_lower_limit = cmp::max(lower_limit, gas_floor_target);
let total_upper_limit = cmp::min(upper_limit, gas_ceil_target);
let gas_limit = cmp::max(gas_floor_target, cmp::min(total_upper_limit,
lower_limit + (header.gas_used().clone() * 6.into() / 5.into()) / bound_divisor));
lower_limit + (header.gas_used().clone() * 6u32 / 5.into()) / bound_divisor));
round_block_gas_limit(gas_limit, total_lower_limit, total_upper_limit)
};
// ensure that we are not violating protocol limits
@@ -384,7 +384,7 @@ impl EthereumMachine {
/// Additional params.
pub fn additional_params(&self) -> HashMap<String, String> {
hash_map![
"registrar".to_owned() => self.params.registrar.hex()
"registrar".to_owned() => format!("{:x}", self.params.registrar)
]
}
}

View File

@@ -647,7 +647,7 @@ impl Miner {
queue.set_gas_limit(gas_limit);
if let GasLimit::Auto = self.options.tx_queue_gas_limit {
// Set total tx queue gas limit to be 20x the block gas limit.
queue.set_total_gas_limit(gas_limit * 20.into());
queue.set_total_gas_limit(gas_limit * 20u32);
}
}
@@ -720,9 +720,6 @@ impl Miner {
}
}).unwrap_or(default_origin);
// try to install service transaction checker before appending transactions
self.service_transaction_action.update_from_chain_client(client);
let details_provider = TransactionDetailsProvider::new(client, &self.service_transaction_action);
match origin {
TransactionOrigin::Local | TransactionOrigin::RetractedBlock => {
@@ -838,7 +835,7 @@ impl MinerService for Miner {
fn sensible_gas_price(&self) -> U256 {
// 10% above our minimum.
*self.transaction_queue.read().minimal_gas_price() * 110.into() / 100.into()
*self.transaction_queue.read().minimal_gas_price() * 110u32 / 100.into()
}
fn sensible_gas_limit(&self) -> U256 {
@@ -1169,7 +1166,7 @@ impl MinerService for Miner {
let n = sealed.header().number();
let h = sealed.header().hash();
chain.import_sealed_block(sealed)?;
info!(target: "miner", "Submitted block imported OK. #{}: {}", Colour::White.bold().paint(format!("{}", n)), Colour::White.bold().paint(h.hex()));
info!(target: "miner", "Submitted block imported OK. #{}: {}", Colour::White.bold().paint(format!("{}", n)), Colour::White.bold().paint(format!("{:x}", h)));
Ok(())
})
}
@@ -1231,12 +1228,6 @@ enum ServiceTransactionAction {
}
impl ServiceTransactionAction {
pub fn update_from_chain_client(&self, client: &MiningBlockChainClient) {
if let ServiceTransactionAction::Check(ref checker) = *self {
checker.update_from_chain_client(&client);
}
}
pub fn check(&self, client: &MiningBlockChainClient, tx: &SignedTransaction) -> Result<bool, String> {
match *self {
ServiceTransactionAction::Refuse => Err("configured to refuse service transactions".to_owned()),

View File

@@ -173,8 +173,8 @@ impl StratumJobDispatcher {
let seed_hash = &self.seed_compute.lock().hash_block_number(number);
let seed_hash = H256::from_slice(&seed_hash[..]);
format!(
r#"["0x", "0x{}","0x{}","0x{}","0x{:x}"]"#,
pow_hash.hex(), seed_hash.hex(), target.hex(), number
r#"["0x", "0x{:x}","0x{:x}","0x{:x}","0x{:x}"]"#,
pow_hash, seed_hash, target, number
)
}

View File

@@ -156,12 +156,9 @@ impl LooseWriter {
// writing logic is the same for both kinds of chunks.
fn write_chunk(&mut self, hash: H256, chunk: &[u8]) -> io::Result<()> {
let mut file_path = self.dir.clone();
file_path.push(hash.hex());
let file_path = self.dir.join(format!("{:x}", hash));
let mut file = File::create(file_path)?;
file.write_all(chunk)?;
Ok(())
}
}
@@ -327,14 +324,10 @@ impl SnapshotReader for LooseReader {
}
fn chunk(&self, hash: H256) -> io::Result<Bytes> {
let mut path = self.dir.clone();
path.push(hash.hex());
let path = self.dir.join(format!("{:x}", hash));
let mut buf = Vec::new();
let mut file = File::open(&path)?;
file.read_to_end(&mut buf)?;
Ok(buf)
}
}

View File

@@ -181,8 +181,8 @@ pub fn chunk_secondary<'a>(mut chunker: Box<SnapshotComponents>, chain: &'a Bloc
let size = compressed.len();
writer.lock().write_block_chunk(hash, compressed)?;
trace!(target: "snapshot", "wrote secondary chunk. hash: {}, size: {}, uncompressed size: {}",
hash.hex(), size, raw_data.len());
trace!(target: "snapshot", "wrote secondary chunk. hash: {:x}, size: {}, uncompressed size: {}",
hash, size, raw_data.len());
progress.size.fetch_add(size, Ordering::SeqCst);
chunk_hashes.push(hash);

View File

@@ -23,8 +23,6 @@ use std::str::FromStr;
use account_provider::AccountProvider;
use client::{Client, BlockChainClient};
use ethkey::Secret;
use futures::Future;
use native_contracts::test_contracts::ValidatorSet;
use snapshot::tests::helpers as snapshot_helpers;
use spec::Spec;
use tests::helpers;
@@ -33,6 +31,8 @@ use transaction::{Transaction, Action, SignedTransaction};
use ethereum_types::Address;
use kvdb_memorydb;
use_contract!(test_validator_set, "ValidatorSet", "res/contracts/test_validator_set.json");
const PASS: &'static str = "";
const TRANSITION_BLOCK_1: usize = 2; // block at which the contract becomes activated.
const TRANSITION_BLOCK_2: usize = 10; // block at which the second contract activates.
@@ -56,7 +56,7 @@ lazy_static! {
/// Account with secrets keccak("1") is initially the validator.
/// Transitions to the contract at block 2, initially same validator set.
/// Create a new Spec with AuthorityRound which uses a contract at address 5 to determine the current validators using `getValidators`.
/// `native_contracts::test_contracts::ValidatorSet` provides a native wrapper for the ABi.
/// `test_validator_set::ValidatorSet` provides a native wrapper for the ABi.
fn spec_fixed_to_contract() -> Spec {
let data = include_bytes!("test_validator_contract.json");
Spec::load(&::std::env::temp_dir(), &data[..]).unwrap()
@@ -136,8 +136,7 @@ fn make_chain(accounts: Arc<AccountProvider>, blocks_beyond: usize, transitions:
vec![transaction]
};
let contract_1 = ValidatorSet::new(*CONTRACT_ADDR_1);
let contract_2 = ValidatorSet::new(*CONTRACT_ADDR_2);
let contract = test_validator_set::ValidatorSet::default();
// apply all transitions.
for transition in transitions {
@@ -160,34 +159,24 @@ fn make_chain(accounts: Arc<AccountProvider>, blocks_beyond: usize, transitions:
let pending = if manual {
trace!(target: "snapshot", "applying set transition at block #{}", num);
let contract = match num >= TRANSITION_BLOCK_2 {
true => &contract_2,
false => &contract_1,
let address = match num >= TRANSITION_BLOCK_2 {
true => &CONTRACT_ADDR_2 as &Address,
false => &CONTRACT_ADDR_1 as &Address,
};
let mut pending = Vec::new();
{
let mut exec = |addr, data| {
let mut nonce = nonce.borrow_mut();
let transaction = Transaction {
nonce: *nonce,
gas_price: 0.into(),
gas: 1_000_000.into(),
action: Action::Call(addr),
value: 0.into(),
data: data,
}.sign(&*RICH_SECRET, client.signing_chain_id());
let data = contract.functions().set_validators().input(new_set.clone());
let mut nonce = nonce.borrow_mut();
let transaction = Transaction {
nonce: *nonce,
gas_price: 0.into(),
gas: 1_000_000.into(),
action: Action::Call(*address),
value: 0.into(),
data,
}.sign(&*RICH_SECRET, client.signing_chain_id());
pending.push(transaction);
*nonce = *nonce + 1.into();
Ok(Vec::new())
};
contract.set_validators(&mut exec, new_set.clone()).wait().unwrap();
}
pending
*nonce = *nonce + 1.into();
vec![transaction]
} else {
make_useless_transactions()
};

View File

@@ -486,7 +486,7 @@ impl fmt::Debug for Account {
#[cfg(test)]
mod tests {
use rlp::{UntrustedRlp, RlpType, Compressible};
use ethereum_types::{H256, U256, Address};
use ethereum_types::{H256, Address};
use memorydb::MemoryDB;
use bytes::Bytes;
use super::*;
@@ -508,7 +508,7 @@ mod tests {
let mut db = AccountDBMut::new(&mut db, &Address::new());
let rlp = {
let mut a = Account::new_contract(69.into(), 0.into());
a.set_storage(H256::from(&U256::from(0x00u64)), H256::from(&U256::from(0x1234u64)));
a.set_storage(0x00u64.into(), 0x1234u64.into());
a.commit_storage(&Default::default(), &mut db).unwrap();
a.init_code(vec![]);
a.commit_code(&mut db);
@@ -516,9 +516,9 @@ mod tests {
};
let a = Account::from_rlp(&rlp);
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
assert_eq!(a.storage_at(&db.immutable(), &H256::from(&U256::from(0x00u64))).unwrap(), H256::from(&U256::from(0x1234u64)));
assert_eq!(a.storage_at(&db.immutable(), &H256::from(&U256::from(0x01u64))).unwrap(), H256::new());
assert_eq!(*a.storage_root().unwrap(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2".into());
assert_eq!(a.storage_at(&db.immutable(), &0x00u64.into()).unwrap(), 0x1234u64.into());
assert_eq!(a.storage_at(&db.immutable(), &0x01u64.into()).unwrap(), H256::default());
}
#[test]
@@ -548,7 +548,7 @@ mod tests {
a.set_storage(0.into(), 0x1234.into());
assert_eq!(a.storage_root(), None);
a.commit_storage(&Default::default(), &mut db).unwrap();
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
assert_eq!(*a.storage_root().unwrap(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2".into());
}
#[test]
@@ -562,7 +562,7 @@ mod tests {
a.commit_storage(&Default::default(), &mut db).unwrap();
a.set_storage(1.into(), 0.into());
a.commit_storage(&Default::default(), &mut db).unwrap();
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
assert_eq!(*a.storage_root().unwrap(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2".into());
}
#[test]
@@ -574,7 +574,7 @@ mod tests {
assert_eq!(a.code_filth, Filth::Dirty);
assert_eq!(a.code_size(), Some(3));
a.commit_code(&mut db);
assert_eq!(a.code_hash().hex(), "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb");
assert_eq!(a.code_hash(), "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb".into());
}
#[test]
@@ -586,16 +586,16 @@ mod tests {
assert_eq!(a.code_filth, Filth::Dirty);
a.commit_code(&mut db);
assert_eq!(a.code_filth, Filth::Clean);
assert_eq!(a.code_hash().hex(), "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb");
assert_eq!(a.code_hash(), "af231e631776a517ca23125370d542873eca1fb4d613ed9b5d5335a46ae5b7eb".into());
a.reset_code(vec![0x55]);
assert_eq!(a.code_filth, Filth::Dirty);
a.commit_code(&mut db);
assert_eq!(a.code_hash().hex(), "37bf2238b11b68cdc8382cece82651b59d3c3988873b6e0f33d79694aa45f1be");
assert_eq!(a.code_hash(), "37bf2238b11b68cdc8382cece82651b59d3c3988873b6e0f33d79694aa45f1be".into());
}
#[test]
fn rlpio() {
let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new());
let a = Account::new(69u8.into(), 0u8.into(), HashMap::new(), Bytes::new());
let b = Account::from_rlp(&a.rlp());
assert_eq!(a.balance(), b.balance());
assert_eq!(a.nonce(), b.nonce());
@@ -605,17 +605,17 @@ mod tests {
#[test]
fn new_account() {
let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new());
let a = Account::new(69u8.into(), 0u8.into(), HashMap::new(), Bytes::new());
assert_eq!(a.rlp().to_hex(), "f8448045a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
assert_eq!(a.balance(), &U256::from(69u8));
assert_eq!(a.nonce(), &U256::from(0u8));
assert_eq!(*a.balance(), 69u8.into());
assert_eq!(*a.nonce(), 0u8.into());
assert_eq!(a.code_hash(), KECCAK_EMPTY);
assert_eq!(a.storage_root().unwrap(), &KECCAK_NULL_RLP);
}
#[test]
fn create_account() {
let a = Account::new(U256::from(69u8), U256::from(0u8), HashMap::new(), Bytes::new());
let a = Account::new(69u8.into(), 0u8.into(), HashMap::new(), Bytes::new());
assert_eq!(a.rlp().to_hex(), "f8448045a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
}

View File

@@ -644,7 +644,7 @@ impl<B: Backend> State<B> {
/// Mutate storage of account `a` so that it is `value` for `key`.
pub fn set_storage(&mut self, a: &Address, key: H256, value: H256) -> trie::Result<()> {
trace!(target: "state", "set_storage({}:{} to {})", a, key.hex(), value.hex());
trace!(target: "state", "set_storage({}:{:x} to {:x})", a, key, value);
if self.storage_at(a, &key)? != value {
self.require(a, false)?.set_storage(key, value)
}
@@ -2085,7 +2085,7 @@ mod tests {
let a = Address::zero();
state.require(&a, false).unwrap();
state.commit().unwrap();
assert_eq!(state.root().hex(), "0ce23f3c809de377b008a4a3ee94a0834aac8bec1f86e28ffe4fdb5a15b0c785");
assert_eq!(*state.root(), "0ce23f3c809de377b008a4a3ee94a0834aac8bec1f86e28ffe4fdb5a15b0c785".into());
}
#[test]
@@ -2122,7 +2122,7 @@ mod tests {
fn create_empty() {
let mut state = get_temp_state();
state.commit().unwrap();
assert_eq!(state.root().hex(), "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421");
assert_eq!(*state.root(), "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421".into());
}
#[test]

View File

@@ -19,15 +19,15 @@
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use ethereum_types::{H256, Address};
use native_contracts::TransactAcl as Contract;
use client::{BlockChainClient, BlockId, ChainNotify};
use bytes::Bytes;
use parking_lot::Mutex;
use futures::{self, Future};
use spec::CommonParams;
use transaction::{Action, SignedTransaction};
use hash::KECCAK_EMPTY;
use_contract!(transact_acl, "TransactAcl", "res/contracts/tx_acl.json");
const MAX_CACHE_SIZE: usize = 4096;
mod tx_permissions {
@@ -41,7 +41,7 @@ mod tx_permissions {
/// Connection filter that uses a contract to manage permissions.
pub struct TransactionFilter {
contract: Mutex<Option<Contract>>,
contract: transact_acl::TransactAcl,
contract_address: Address,
permission_cache: Mutex<HashMap<(H256, Address), u32>>,
}
@@ -51,7 +51,7 @@ impl TransactionFilter {
pub fn from_params(params: &CommonParams) -> Option<TransactionFilter> {
params.transaction_permission_contract.map(|address|
TransactionFilter {
contract: Mutex::new(None),
contract: transact_acl::TransactAcl::default(),
contract_address: address,
permission_cache: Mutex::new(HashMap::new()),
}
@@ -79,23 +79,15 @@ impl TransactionFilter {
match cache.entry((*parent_hash, sender)) {
Entry::Occupied(entry) => *entry.get() & tx_type != 0,
Entry::Vacant(entry) => {
let mut contract = self.contract.lock();
if contract.is_none() {
*contract = Some(Contract::new(self.contract_address));
}
let permissions = match &*contract {
&Some(ref contract) => {
contract.allowed_tx_types(
|addr, data| futures::done(client.call_contract(BlockId::Hash(*parent_hash), addr, data)),
sender,
).wait().unwrap_or_else(|e| {
debug!("Error callling tx permissions contract: {:?}", e);
tx_permissions::NONE
})
}
_ => tx_permissions::NONE,
};
let contract_address = self.contract_address;
let permissions = self.contract.functions()
.allowed_tx_types()
.call(sender, &|data| client.call_contract(BlockId::Hash(*parent_hash), contract_address, data))
.map(|p| p.low_u32())
.unwrap_or_else(|e| {
debug!("Error callling tx permissions contract: {:?}", e);
tx_permissions::NONE
});
if len < MAX_CACHE_SIZE {
entry.insert(permissions);