new ethabi (#9511)

* new ethabi migration in progress

* parity migrated to new ethabi

* migrated secred-store to new ethabi

* bump ethabi to 6.0

* fixed review suggestions
This commit is contained in:
Marek Kotewicz
2018-09-13 11:04:39 +02:00
committed by GitHub
parent 7dfb5ff5bd
commit ef4a61c769
23 changed files with 458 additions and 575 deletions

View File

@@ -86,7 +86,7 @@ pub use types::block_status::BlockStatus;
pub use blockchain::CacheSize as BlockChainCacheSize;
pub use verification::QueueInfo as BlockQueueInfo;
use_contract!(registry, "Registry", "res/contracts/registrar.json");
use_contract!(registry, "res/contracts/registrar.json");
const MAX_ANCIENT_BLOCKS_QUEUE_SIZE: usize = 4096;
// Max number of blocks imported at once.
@@ -232,8 +232,6 @@ pub struct Client {
/// An action to be done if a mode/spec_name change happens
on_user_defaults_change: Mutex<Option<Box<FnMut(Option<Mode>) + 'static + Send>>>,
/// Link to a registry object useful for looking up names
registrar: registry::Registry,
registrar_address: Option<Address>,
/// A closure to call when we want to restart the client
@@ -776,7 +774,6 @@ impl Client {
factories: factories,
history: history,
on_user_defaults_change: Mutex::new(None),
registrar: registry::Registry::default(),
registrar_address,
exit_handler: Mutex::new(None),
importer,
@@ -1365,17 +1362,17 @@ impl BlockChainTrait for Client {}
impl RegistryInfo for Client {
fn registry_address(&self, name: String, block: BlockId) -> Option<Address> {
use ethabi::FunctionOutputDecoder;
let address = self.registrar_address?;
self.registrar.functions()
.get_address()
.call(keccak(name.as_bytes()), "A", &|data| self.call_contract(block, address, data))
.ok()
.and_then(|a| if a.is_zero() {
None
} else {
Some(a)
})
let (data, decoder) = registry::functions::get_address::call(keccak(name.as_bytes()), "A");
let value = decoder.decode(&self.call_contract(block, address, data).ok()?).ok()?;
if value.is_zero() {
None
} else {
Some(value)
}
}
}

View File

@@ -30,7 +30,7 @@ use trace;
use types::BlockNumber;
use super::{SystemOrCodeCall, SystemOrCodeCallKind};
use_contract!(block_reward_contract, "BlockReward", "res/contracts/block_reward.json");
use_contract!(block_reward_contract, "res/contracts/block_reward.json");
/// The kind of block reward.
/// Depending on the consensus engine the allocated block reward might have
@@ -81,7 +81,6 @@ impl Into<trace::RewardType> for RewardKind {
#[derive(PartialEq, Debug)]
pub struct BlockRewardContract {
kind: SystemOrCodeCallKind,
block_reward_contract: block_reward_contract::BlockReward,
}
impl BlockRewardContract {
@@ -89,7 +88,6 @@ impl BlockRewardContract {
pub fn new(kind: SystemOrCodeCallKind) -> BlockRewardContract {
BlockRewardContract {
kind,
block_reward_contract: block_reward_contract::BlockReward::default(),
}
}
@@ -114,9 +112,7 @@ impl BlockRewardContract {
beneficiaries: &[(Address, RewardKind)],
caller: &mut SystemOrCodeCall,
) -> Result<Vec<(Address, U256)>, Error> {
let reward = self.block_reward_contract.functions().reward();
let input = reward.input(
let input = block_reward_contract::functions::reward::encode_input(
beneficiaries.iter().map(|&(address, _)| H160::from(address)),
beneficiaries.iter().map(|&(_, ref reward_kind)| u16::from(*reward_kind)),
);

View File

@@ -30,13 +30,12 @@ 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");
use_contract!(validator_report, "res/contracts/validator_report.json");
/// A validator contract with reporting.
pub struct ValidatorContract {
contract_address: Address,
validators: ValidatorSafeContract,
provider: validator_report::ValidatorReport,
client: RwLock<Option<Weak<EngineClient>>>, // TODO [keorn]: remove
}
@@ -45,7 +44,6 @@ impl ValidatorContract {
ValidatorContract {
contract_address,
validators: ValidatorSafeContract::new(contract_address),
provider: validator_report::ValidatorReport::default(),
client: RwLock::new(None),
}
}
@@ -111,7 +109,7 @@ impl ValidatorSet for ValidatorContract {
}
fn report_malicious(&self, address: &Address, _set_block: BlockNumber, block: BlockNumber, proof: Bytes) {
let data = self.provider.functions().report_malicious().input(*address, block, proof);
let data = validator_report::functions::report_malicious::encode_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),
@@ -119,7 +117,7 @@ impl ValidatorSet for ValidatorContract {
}
fn report_benign(&self, address: &Address, _set_block: BlockNumber, block: BlockNumber) {
let data = self.provider.functions().report_benign().input(*address, block);
let data = validator_report::functions::report_benign::encode_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

@@ -33,8 +33,9 @@ use std::sync::{Weak, Arc};
use super::{SystemCall, ValidatorSet};
use super::simple_list::SimpleList;
use unexpected::Mismatch;
use ethabi::FunctionOutputDecoder;
use_contract!(validator_set, "ValidatorSet", "res/contracts/validator_set.json");
use_contract!(validator_set, "res/contracts/validator_set.json");
const MEMOIZE_CAPACITY: usize = 500;
@@ -50,12 +51,11 @@ lazy_static! {
struct StateProof {
contract_address: Address,
header: Header,
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.contract_address, &self.header, caller)
prove_initial(self.contract_address, &self.header, caller)
}
fn check_proof(&self, machine: &EthereumMachine, proof: &[u8]) -> Result<(), String> {
@@ -65,7 +65,7 @@ impl ::engines::StateDependentProof<EthereumMachine> for StateProof {
return Err("wrong header in proof".into());
}
check_first_proof(machine, &self.provider, self.contract_address, header, &state_items).map(|_| ())
check_first_proof(machine, self.contract_address, header, &state_items).map(|_| ())
}
}
@@ -73,7 +73,6 @@ impl ::engines::StateDependentProof<EthereumMachine> for StateProof {
pub struct ValidatorSafeContract {
contract_address: Address,
validators: RwLock<MemoryLruCache<H256, SimpleList>>,
provider: validator_set::ValidatorSet,
client: RwLock<Option<Weak<EngineClient>>>, // TODO [keorn]: remove
}
@@ -89,7 +88,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: &validator_set::ValidatorSet, contract_address: Address, old_header: Header, state_items: &[DBValue])
fn check_first_proof(machine: &EthereumMachine, contract_address: Address, old_header: Header, state_items: &[DBValue])
-> Result<Vec<Address>, String>
{
use transaction::{Action, Transaction};
@@ -114,31 +113,31 @@ fn check_first_proof(machine: &EthereumMachine, provider: &validator_set::Valida
// check state proof using given machine.
let number = old_header.number();
provider.functions().get_validators().call(&|data| {
let from = Address::default();
let tx = Transaction {
nonce: machine.account_start_nonce(number),
action: Action::Call(contract_address),
gas: PROVIDED_GAS.into(),
gas_price: U256::default(),
value: U256::default(),
data,
}.fake_sign(from);
let (data, decoder) = validator_set::functions::get_validators::call();
let res = ::state::check_proof(
state_items,
*old_header.state_root(),
&tx,
machine,
&env_info,
);
let from = Address::default();
let tx = Transaction {
nonce: machine.account_start_nonce(number),
action: Action::Call(contract_address),
gas: PROVIDED_GAS.into(),
gas_price: U256::default(),
value: U256::default(),
data,
}.fake_sign(from);
match res {
::state::ProvedExecution::BadProof => Err("Bad proof".into()),
::state::ProvedExecution::Failed(e) => Err(format!("Failed call: {}", e)),
::state::ProvedExecution::Complete(e) => Ok(e.output),
}
}).map_err(|err| err.to_string())
let res = ::state::check_proof(
state_items,
*old_header.state_root(),
&tx,
machine,
&env_info,
);
match res {
::state::ProvedExecution::BadProof => Err("Bad proof".into()),
::state::ProvedExecution::Failed(e) => Err(format!("Failed call: {}", e)),
::state::ProvedExecution::Complete(e) => decoder.decode(&e.output).map_err(|e| e.to_string()),
}
}
fn decode_first_proof(rlp: &Rlp) -> Result<(Header, Vec<DBValue>), ::error::Error> {
@@ -167,32 +166,26 @@ fn decode_proof(rlp: &Rlp) -> Result<(Header, Vec<Receipt>), ::error::Error> {
// given a provider and caller, generate proof. this will just be a state proof
// of `getValidators`.
fn prove_initial(provider: &validator_set::ValidatorSet, contract_address: Address, header: &Header, caller: &Call) -> Result<Vec<u8>, String> {
fn prove_initial(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 = |data| {
let (result, proof) = caller(contract_address, data)?;
*epoch_proof.borrow_mut() = Some(encode_first_proof(header, &proof));
Ok(result)
};
provider.functions().get_validators().call(&caller)
.map_err(|err| err.to_string())
let validators = {
let (data, decoder) = validator_set::functions::get_validators::call();
let (value, proof) = caller(contract_address, data)?;
*epoch_proof.borrow_mut() = Some(encode_first_proof(header, &proof));
decoder.decode(&value).map_err(|e| e.to_string())?
};
res.map(|validators| {
let proof = epoch_proof.into_inner().expect("epoch_proof always set after call; qed");
let proof = epoch_proof.into_inner().expect("epoch_proof always set after call; qed");
trace!(target: "engine", "obtained proof for initial set: {} validators, {} bytes",
validators.len(), proof.len());
trace!(target: "engine", "obtained proof for initial set: {} validators, {} bytes",
validators.len(), proof.len());
info!(target: "engine", "Signal for switch to contract-based validator set.");
info!(target: "engine", "Initial contract validators: {:?}", validators);
info!(target: "engine", "Signal for switch to contract-based validator set.");
info!(target: "engine", "Initial contract validators: {:?}", validators);
proof
})
Ok(proof)
}
impl ValidatorSafeContract {
@@ -200,7 +193,6 @@ impl ValidatorSafeContract {
ValidatorSafeContract {
contract_address,
validators: RwLock::new(MemoryLruCache::new(MEMOIZE_CAPACITY)),
provider: validator_set::ValidatorSet::default(),
client: RwLock::new(None),
}
}
@@ -208,8 +200,11 @@ impl ValidatorSafeContract {
/// Queries the state and gets the set of validators.
fn get_list(&self, caller: &Call) -> Option<SimpleList> {
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) {
let (data, decoder) = validator_set::functions::get_validators::call();
let value = caller(contract_address, data).and_then(|x| decoder.decode(&x.0).map_err(|e| e.to_string()));
match value {
Ok(new) => {
debug!(target: "engine", "Set of validators obtained: {:?}", new);
Some(SimpleList::new(new))
@@ -259,7 +254,6 @@ impl ValidatorSafeContract {
log.topics[1] == *header.parent_hash()
};
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.
@@ -269,7 +263,7 @@ impl ValidatorSafeContract {
.flat_map(|r| r.logs.iter())
.filter(move |l| check_log(l))
.filter_map(|log| {
event.parse_log((log.topics.clone(), log.data.clone()).into()).ok()
validator_set::events::initiate_change::parse_log((log.topics.clone(), log.data.clone()).into()).ok()
});
// only last log is taken into account
@@ -296,7 +290,7 @@ impl ValidatorSet for ValidatorSafeContract {
}
fn on_epoch_begin(&self, _first: bool, _header: &Header, caller: &mut SystemCall) -> Result<(), ::error::Error> {
let data = self.provider.functions().finalize_change().input();
let data = validator_set::functions::finalize_change::encode_input();
caller(self.contract_address, data)
.map(|_| ())
.map_err(::engines::EngineError::FailedSystemCall)
@@ -304,7 +298,7 @@ impl ValidatorSet for ValidatorSafeContract {
}
fn genesis_epoch_data(&self, header: &Header, call: &Call) -> Result<Vec<u8>, String> {
prove_initial(&self.provider, self.contract_address, header, call)
prove_initial(self.contract_address, header, call)
}
fn is_epoch_end(&self, _first: bool, _chain_head: &Header) -> Option<Vec<u8>> {
@@ -322,7 +316,6 @@ impl ValidatorSet for ValidatorSafeContract {
let state_proof = Arc::new(StateProof {
contract_address: self.contract_address,
header: header.clone(),
provider: validator_set::ValidatorSet::default(),
});
return ::engines::EpochChange::Yes(::engines::Proof::WithState(state_proof as Arc<_>));
}
@@ -361,7 +354,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, self.contract_address, old_header, &state_items)
let addresses = check_first_proof(machine, self.contract_address, old_header, &state_items)
.map_err(::engines::EngineError::InsufficientProof)?;
trace!(target: "engine", "extracted epoch set at #{}: {} addresses",

View File

@@ -18,16 +18,15 @@
use client::{RegistryInfo, CallContract, BlockId};
use transaction::SignedTransaction;
use ethabi::FunctionOutputDecoder;
use_contract!(service_transaction, "ServiceTransaction", "res/contracts/service_transaction.json");
use_contract!(service_transaction, "res/contracts/service_transaction.json");
const SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME: &'static str = "service_transaction_checker";
/// Service transactions checker.
#[derive(Default, Clone)]
pub struct ServiceTransactionChecker {
contract: service_transaction::ServiceTransaction,
}
pub struct ServiceTransactionChecker;
impl ServiceTransactionChecker {
/// Checks if given address is whitelisted to send service transactions.
@@ -45,9 +44,8 @@ impl ServiceTransactionChecker {
trace!(target: "txqueue", "[{:?}] Checking service transaction checker contract from {}", hash, sender);
self.contract.functions()
.certified()
.call(sender, &|data| client.call_contract(BlockId::Latest, address, data))
.map_err(|e| e.to_string())
let (data, decoder) = service_transaction::functions::certified::call(sender);
let value = client.call_contract(BlockId::Latest, address, data)?;
decoder.decode(&value).map_err(|e| e.to_string())
}
}

View File

@@ -32,7 +32,7 @@ use tempdir::TempDir;
use ethereum_types::Address;
use test_helpers;
use_contract!(test_validator_set, "ValidatorSet", "res/contracts/test_validator_set.json");
use_contract!(test_validator_set, "res/contracts/test_validator_set.json");
const PASS: &'static str = "";
const TRANSITION_BLOCK_1: usize = 2; // block at which the contract becomes activated.
@@ -135,8 +135,6 @@ fn make_chain(accounts: Arc<AccountProvider>, blocks_beyond: usize, transitions:
vec![transaction]
};
let contract = test_validator_set::ValidatorSet::default();
// apply all transitions.
for transition in transitions {
let (num, manual, new_set) = match transition {
@@ -163,7 +161,7 @@ fn make_chain(accounts: Arc<AccountProvider>, blocks_beyond: usize, transitions:
false => &CONTRACT_ADDR_1 as &Address,
};
let data = contract.functions().set_validators().input(new_set.clone());
let data = test_validator_set::functions::set_validators::encode_input(new_set.clone());
let mut nonce = nonce.borrow_mut();
let transaction = Transaction {
nonce: *nonce,

View File

@@ -18,6 +18,7 @@
use ethereum_types::{H256, U256, Address};
use lru_cache::LruCache;
use ethabi::FunctionOutputDecoder;
use client::{BlockInfo, CallContract, BlockId};
use parking_lot::Mutex;
@@ -26,8 +27,8 @@ use transaction::{Action, SignedTransaction};
use types::BlockNumber;
use hash::KECCAK_EMPTY;
use_contract!(transact_acl_deprecated, "TransactAclDeprecated", "res/contracts/tx_acl_deprecated.json");
use_contract!(transact_acl, "TransactAcl", "res/contracts/tx_acl.json");
use_contract!(transact_acl_deprecated, "res/contracts/tx_acl_deprecated.json");
use_contract!(transact_acl, "res/contracts/tx_acl.json");
const MAX_CACHE_SIZE: usize = 4096;
@@ -42,8 +43,6 @@ mod tx_permissions {
/// Connection filter that uses a contract to manage permissions.
pub struct TransactionFilter {
contract_deprecated: transact_acl_deprecated::TransactAclDeprecated,
contract: transact_acl::TransactAcl,
contract_address: Address,
transition_block: BlockNumber,
permission_cache: Mutex<LruCache<(H256, Address), u32>>,
@@ -55,8 +54,6 @@ impl TransactionFilter {
pub fn from_params(params: &CommonParams) -> Option<TransactionFilter> {
params.transaction_permission_contract.map(|address|
TransactionFilter {
contract_deprecated: transact_acl_deprecated::TransactAclDeprecated::default(),
contract: transact_acl::TransactAcl::default(),
contract_address: address,
transition_block: params.transaction_permission_contract_transition,
permission_cache: Mutex::new(LruCache::new(MAX_CACHE_SIZE)),
@@ -91,10 +88,8 @@ impl TransactionFilter {
let contract_address = self.contract_address;
let contract_version = contract_version_cache.get_mut(parent_hash).and_then(|v| *v).or_else(|| {
self.contract.functions()
.contract_version()
.call(&|data| client.call_contract(BlockId::Hash(*parent_hash), contract_address, data))
.ok()
let (data, decoder) = transact_acl::functions::contract_version::call();
decoder.decode(&client.call_contract(BlockId::Hash(*parent_hash), contract_address, data).ok()?).ok()
});
contract_version_cache.insert(*parent_hash, contract_version);
@@ -104,14 +99,16 @@ impl TransactionFilter {
let version_u64 = version.low_u64();
trace!(target: "tx_filter", "Version of tx permission contract: {}", version);
match version_u64 {
2 => self.contract.functions()
.allowed_tx_types()
.call(sender, to, value, &|data| client.call_contract(BlockId::Hash(*parent_hash), contract_address, data))
.map(|(p, f)| (p.low_u32(), f))
.unwrap_or_else(|e| {
error!(target: "tx_filter", "Error calling tx permissions contract: {:?}", e);
(tx_permissions::NONE, true)
}),
2 => {
let (data, decoder) = transact_acl::functions::allowed_tx_types::call(sender, to, value);
client.call_contract(BlockId::Hash(*parent_hash), contract_address, data)
.and_then(|value| decoder.decode(&value).map_err(|e| e.to_string()))
.map(|(p, f)| (p.low_u32(), f))
.unwrap_or_else(|e| {
error!(target: "tx_filter", "Error calling tx permissions contract: {:?}", e);
(tx_permissions::NONE, true)
})
},
_ => {
error!(target: "tx_filter", "Unknown version of tx permissions contract is used");
(tx_permissions::NONE, true)
@@ -120,14 +117,14 @@ impl TransactionFilter {
},
None => {
trace!(target: "tx_filter", "Fallback to the deprecated version of tx permission contract");
(self.contract_deprecated.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| {
error!(target: "tx_filter", "Error calling tx permissions contract: {:?}", e);
tx_permissions::NONE
}), true)
let (data, decoder) = transact_acl_deprecated::functions::allowed_tx_types::call(sender);
(client.call_contract(BlockId::Hash(*parent_hash), contract_address, data)
.and_then(|value| decoder.decode(&value).map_err(|e| e.to_string()))
.map(|p| p.low_u32())
.unwrap_or_else(|e| {
error!(target: "tx_filter", "Error calling tx permissions contract: {:?}", e);
tx_permissions::NONE
}), true)
}
};