Supporting blockid in eth_call and trace_call/trace_raw (#1837)
* Supporting blockid in eth_call and trace_call/trace_raw * Nicer state diff handling * Purging deref.deref
This commit is contained in:
@@ -15,7 +15,6 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::collections::{HashSet, HashMap, VecDeque};
|
||||
use std::ops::Deref;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::path::{Path};
|
||||
use std::fmt;
|
||||
@@ -35,7 +34,7 @@ use util::kvdb::*;
|
||||
|
||||
// other
|
||||
use views::{BlockView, HeaderView, BodyView};
|
||||
use error::{ImportError, ExecutionError, ReplayError, BlockError, ImportResult};
|
||||
use error::{ImportError, ExecutionError, CallError, BlockError, ImportResult};
|
||||
use header::BlockNumber;
|
||||
use state::State;
|
||||
use spec::Spec;
|
||||
@@ -272,7 +271,7 @@ impl Client {
|
||||
}
|
||||
|
||||
fn check_and_close_block(&self, block: &PreverifiedBlock) -> Result<LockedBlock, ()> {
|
||||
let engine = self.engine.deref().deref();
|
||||
let engine = &**self.engine;
|
||||
let header = &block.header;
|
||||
|
||||
// Check the block isn't so old we won't be able to enact it.
|
||||
@@ -283,7 +282,7 @@ impl Client {
|
||||
}
|
||||
|
||||
// Verify Block Family
|
||||
let verify_family_result = self.verifier.verify_block_family(header, &block.bytes, engine, self.chain.deref());
|
||||
let verify_family_result = self.verifier.verify_block_family(header, &block.bytes, engine, &*self.chain);
|
||||
if let Err(e) = verify_family_result {
|
||||
warn!(target: "client", "Stage 3 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
|
||||
return Err(());
|
||||
@@ -639,8 +638,8 @@ impl Client {
|
||||
}
|
||||
|
||||
impl BlockChainClient for Client {
|
||||
fn call(&self, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, ExecutionError> {
|
||||
let header = self.block_header(BlockID::Latest).unwrap();
|
||||
fn call(&self, t: &SignedTransaction, block: BlockID, analytics: CallAnalytics) -> Result<Executed, CallError> {
|
||||
let header = try!(self.block_header(block).ok_or(CallError::StatePruned));
|
||||
let view = HeaderView::new(&header);
|
||||
let last_hashes = self.build_last_hashes(view.hash());
|
||||
let env_info = EnvInfo {
|
||||
@@ -653,7 +652,9 @@ impl BlockChainClient for Client {
|
||||
gas_limit: U256::max_value(),
|
||||
};
|
||||
// that's just a copy of the state.
|
||||
let mut state = self.state();
|
||||
let mut state = try!(self.state_at(block).ok_or(CallError::StatePruned));
|
||||
let original_state = if analytics.state_diffing { Some(state.clone()) } else { None };
|
||||
|
||||
let sender = try!(t.sender().map_err(|e| {
|
||||
let message = format!("Transaction malformed: {:?}", e);
|
||||
ExecutionError::TransactionMalformed(message)
|
||||
@@ -665,26 +666,23 @@ impl BlockChainClient for Client {
|
||||
state.add_balance(&sender, &(needed_balance - balance));
|
||||
}
|
||||
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
|
||||
let mut ret = Executive::new(&mut state, &env_info, self.engine.deref().deref(), &self.vm_factory).transact(t, options);
|
||||
let mut ret = try!(Executive::new(&mut state, &env_info, &**self.engine, &self.vm_factory).transact(t, options));
|
||||
|
||||
// TODO gav move this into Executive.
|
||||
if analytics.state_diffing {
|
||||
if let Ok(ref mut x) = ret {
|
||||
x.state_diff = Some(state.diff_from(self.state()));
|
||||
}
|
||||
}
|
||||
ret
|
||||
ret.state_diff = original_state.map(|original| state.diff_from(original));
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
fn replay(&self, id: TransactionID, analytics: CallAnalytics) -> Result<Executed, ReplayError> {
|
||||
let address = try!(self.transaction_address(id).ok_or(ReplayError::TransactionNotFound));
|
||||
let header_data = try!(self.block_header(BlockID::Hash(address.block_hash)).ok_or(ReplayError::StatePruned));
|
||||
let body_data = try!(self.block_body(BlockID::Hash(address.block_hash)).ok_or(ReplayError::StatePruned));
|
||||
let mut state = try!(self.state_at_beginning(BlockID::Hash(address.block_hash)).ok_or(ReplayError::StatePruned));
|
||||
fn replay(&self, id: TransactionID, analytics: CallAnalytics) -> Result<Executed, CallError> {
|
||||
let address = try!(self.transaction_address(id).ok_or(CallError::TransactionNotFound));
|
||||
let header_data = try!(self.block_header(BlockID::Hash(address.block_hash)).ok_or(CallError::StatePruned));
|
||||
let body_data = try!(self.block_body(BlockID::Hash(address.block_hash)).ok_or(CallError::StatePruned));
|
||||
let mut state = try!(self.state_at_beginning(BlockID::Hash(address.block_hash)).ok_or(CallError::StatePruned));
|
||||
let txs = BodyView::new(&body_data).transactions();
|
||||
|
||||
if address.index >= txs.len() {
|
||||
return Err(ReplayError::TransactionNotFound);
|
||||
return Err(CallError::TransactionNotFound);
|
||||
}
|
||||
|
||||
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
|
||||
@@ -700,20 +698,18 @@ impl BlockChainClient for Client {
|
||||
gas_limit: view.gas_limit(),
|
||||
};
|
||||
for t in txs.iter().take(address.index) {
|
||||
match Executive::new(&mut state, &env_info, self.engine.deref().deref(), &self.vm_factory).transact(t, Default::default()) {
|
||||
match Executive::new(&mut state, &env_info, &**self.engine, &self.vm_factory).transact(t, Default::default()) {
|
||||
Ok(x) => { env_info.gas_used = env_info.gas_used + x.gas_used; }
|
||||
Err(ee) => { return Err(ReplayError::Execution(ee)) }
|
||||
Err(ee) => { return Err(CallError::Execution(ee)) }
|
||||
}
|
||||
}
|
||||
let t = &txs[address.index];
|
||||
let orig = state.clone();
|
||||
let mut ret = Executive::new(&mut state, &env_info, self.engine.deref().deref(), &self.vm_factory).transact(t, options);
|
||||
if analytics.state_diffing {
|
||||
if let Ok(ref mut x) = ret {
|
||||
x.state_diff = Some(state.diff_from(orig));
|
||||
}
|
||||
}
|
||||
ret.map_err(ReplayError::Execution)
|
||||
|
||||
let original_state = if analytics.state_diffing { Some(state.clone()) } else { None };
|
||||
let mut ret = try!(Executive::new(&mut state, &env_info, &**self.engine, &self.vm_factory).transact(t, options));
|
||||
ret.state_diff = original_state.map(|original| state.diff_from(original));
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
fn keep_alive(&self) {
|
||||
@@ -1002,7 +998,7 @@ impl BlockChainClient for Client {
|
||||
|
||||
impl MiningBlockChainClient for Client {
|
||||
fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock {
|
||||
let engine = self.engine.deref().deref();
|
||||
let engine = &**self.engine;
|
||||
let h = self.chain.best_block_hash();
|
||||
|
||||
let mut open_block = OpenBlock::new(
|
||||
|
||||
@@ -37,7 +37,7 @@ use spec::Spec;
|
||||
use block_queue::BlockQueueInfo;
|
||||
use block::{OpenBlock, SealedBlock};
|
||||
use executive::Executed;
|
||||
use error::{ExecutionError, ReplayError};
|
||||
use error::CallError;
|
||||
use trace::LocalizedTrace;
|
||||
|
||||
/// Test client.
|
||||
@@ -61,7 +61,7 @@ pub struct TestBlockChainClient {
|
||||
/// Code.
|
||||
pub code: RwLock<HashMap<Address, Bytes>>,
|
||||
/// Execution result.
|
||||
pub execution_result: RwLock<Option<Executed>>,
|
||||
pub execution_result: RwLock<Option<Result<Executed, CallError>>>,
|
||||
/// Transaction receipts.
|
||||
pub receipts: RwLock<HashMap<TransactionID, LocalizedReceipt>>,
|
||||
/// Block queue size.
|
||||
@@ -125,7 +125,7 @@ impl TestBlockChainClient {
|
||||
}
|
||||
|
||||
/// Set the execution result.
|
||||
pub fn set_execution_result(&self, result: Executed) {
|
||||
pub fn set_execution_result(&self, result: Result<Executed, CallError>) {
|
||||
*self.execution_result.write() = Some(result);
|
||||
}
|
||||
|
||||
@@ -292,12 +292,12 @@ impl MiningBlockChainClient for TestBlockChainClient {
|
||||
}
|
||||
|
||||
impl BlockChainClient for TestBlockChainClient {
|
||||
fn call(&self, _t: &SignedTransaction, _analytics: CallAnalytics) -> Result<Executed, ExecutionError> {
|
||||
Ok(self.execution_result.read().clone().unwrap())
|
||||
fn call(&self, _t: &SignedTransaction, _block: BlockID, _analytics: CallAnalytics) -> Result<Executed, CallError> {
|
||||
self.execution_result.read().clone().unwrap()
|
||||
}
|
||||
|
||||
fn replay(&self, _id: TransactionID, _analytics: CallAnalytics) -> Result<Executed, ReplayError> {
|
||||
Ok(self.execution_result.read().clone().unwrap())
|
||||
fn replay(&self, _id: TransactionID, _analytics: CallAnalytics) -> Result<Executed, CallError> {
|
||||
self.execution_result.read().clone().unwrap()
|
||||
}
|
||||
|
||||
fn block_total_difficulty(&self, _id: BlockID) -> Option<U256> {
|
||||
|
||||
@@ -26,7 +26,7 @@ use transaction::{LocalizedTransaction, SignedTransaction};
|
||||
use log_entry::LocalizedLogEntry;
|
||||
use filter::Filter;
|
||||
use views::{BlockView};
|
||||
use error::{ImportResult, ExecutionError, ReplayError};
|
||||
use error::{ImportResult, CallError};
|
||||
use receipt::LocalizedReceipt;
|
||||
use trace::LocalizedTrace;
|
||||
use evm::Factory as EvmFactory;
|
||||
@@ -154,11 +154,10 @@ pub trait BlockChainClient : Sync + Send {
|
||||
fn logs(&self, filter: Filter) -> Vec<LocalizedLogEntry>;
|
||||
|
||||
/// Makes a non-persistent transaction call.
|
||||
// TODO: should be able to accept blockchain location for call.
|
||||
fn call(&self, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, ExecutionError>;
|
||||
fn call(&self, t: &SignedTransaction, block: BlockID, analytics: CallAnalytics) -> Result<Executed, CallError>;
|
||||
|
||||
/// Replays a given transaction for inspection.
|
||||
fn replay(&self, t: TransactionID, analytics: CallAnalytics) -> Result<Executed, ReplayError>;
|
||||
fn replay(&self, t: TransactionID, analytics: CallAnalytics) -> Result<Executed, CallError>;
|
||||
|
||||
/// Returns traces matching given filter.
|
||||
fn filter_traces(&self, filter: TraceFilter) -> Option<Vec<LocalizedTrace>>;
|
||||
|
||||
Reference in New Issue
Block a user