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:
@@ -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 {
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()),
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
};
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user