[beta] Backports (#6497)
* Fix slow balances (#6471)
* Update token updates
* Update token info fetching
* Update logger
* Minor fixes to updates and notifications for balances
* Use Pubsub
* Fix timeout.
* Use pubsub for status.
* Fix signer subscription.
* Process tokens in chunks.
* Fix tokens loaded by chunks
* Linting
* Dispatch tokens asap
* Fix chunks processing.
* Better filter options
* Parallel log fetching.
* Fix signer polling.
* Fix initial block query.
* Token balances updates : the right(er) way
* Better tokens info fetching
* Fixes in token data fetching
* Only fetch what's needed (tokens)
* Fix linting issues
* Revert "Transaction permissioning (#6441)"
This reverts commit eed0e8b03a.
* Revert "Revert "Transaction permissioning (#6441)""
This reverts commit 8f96415e58dde652e5828706eb2639d43416f448.
* Update wasm-tests.
* Fixing balances fetching
* Fix requests tracking in UI
* Fix request watching
* Update the Logger
* PR Grumbles Fixes
* PR Grumbles fixes
* Linting...
* eth_call returns output of contract creations (#6420)
* eth_call returns output of contract creations
* Fix parameters order.
* Save outputs for light client as well.
* Don't accept transactions above block gas limit.
* Expose health status over RPC (#6274)
* Node-health to a separate crate.
* Initialize node_health outside of dapps.
* Expose health over RPC.
* Bring back 412 and fix JS.
* Add health to workspace and tests.
* Fix compilation without default features.
* Fix borked merge.
* Revert to generics to avoid virtual calls.
* Fix node-health tests.
* Add missing trailing comma.
* Fixing/removing failing JS tests.
* do not activate genesis epoch in immediate transition validator contract (#6349)
* Fix memory tracing.
* Add test to cover that.
* ensure balances of constructor accounts are kept
* test balance of spec-constructed account is kept
This commit is contained in:
@@ -36,6 +36,7 @@ use db::{self, Writable, Readable, CacheUpdatePolicy};
|
||||
use cache_manager::CacheManager;
|
||||
use encoded;
|
||||
use engines::epoch::{Transition as EpochTransition, PendingTransition as PendingEpochTransition};
|
||||
use rayon::prelude::*;
|
||||
|
||||
const LOG_BLOOMS_LEVELS: usize = 3;
|
||||
const LOG_BLOOMS_ELEMENTS_PER_INDEX: usize = 16;
|
||||
@@ -143,7 +144,7 @@ pub trait BlockProvider {
|
||||
|
||||
/// Returns logs matching given filter.
|
||||
fn logs<F>(&self, blocks: Vec<BlockNumber>, matches: F, limit: Option<usize>) -> Vec<LocalizedLogEntry>
|
||||
where F: Fn(&LogEntry) -> bool, Self: Sized;
|
||||
where F: Fn(&LogEntry) -> bool + Send + Sync, Self: Sized;
|
||||
}
|
||||
|
||||
macro_rules! otry {
|
||||
@@ -354,50 +355,56 @@ impl BlockProvider for BlockChain {
|
||||
}
|
||||
|
||||
fn logs<F>(&self, mut blocks: Vec<BlockNumber>, matches: F, limit: Option<usize>) -> Vec<LocalizedLogEntry>
|
||||
where F: Fn(&LogEntry) -> bool, Self: Sized {
|
||||
where F: Fn(&LogEntry) -> bool + Send + Sync, Self: Sized {
|
||||
// sort in reverse order
|
||||
blocks.sort_by(|a, b| b.cmp(a));
|
||||
|
||||
let mut log_index = 0;
|
||||
let mut logs = blocks.into_iter()
|
||||
.filter_map(|number| self.block_hash(number).map(|hash| (number, hash)))
|
||||
.filter_map(|(number, hash)| self.block_receipts(&hash).map(|r| (number, hash, r.receipts)))
|
||||
.filter_map(|(number, hash, receipts)| self.block_body(&hash).map(|ref b| (number, hash, receipts, b.transaction_hashes())))
|
||||
.flat_map(|(number, hash, mut receipts, mut hashes)| {
|
||||
if receipts.len() != hashes.len() {
|
||||
warn!("Block {} ({}) has different number of receipts ({}) to transactions ({}). Database corrupt?", number, hash, receipts.len(), hashes.len());
|
||||
assert!(false);
|
||||
}
|
||||
log_index = receipts.iter().fold(0, |sum, receipt| sum + receipt.logs.len());
|
||||
let mut logs = blocks
|
||||
.chunks(128)
|
||||
.flat_map(move |blocks_chunk| {
|
||||
blocks_chunk.into_par_iter()
|
||||
.filter_map(|number| self.block_hash(*number).map(|hash| (*number, hash)))
|
||||
.filter_map(|(number, hash)| self.block_receipts(&hash).map(|r| (number, hash, r.receipts)))
|
||||
.filter_map(|(number, hash, receipts)| self.block_body(&hash).map(|ref b| (number, hash, receipts, b.transaction_hashes())))
|
||||
.flat_map(|(number, hash, mut receipts, mut hashes)| {
|
||||
if receipts.len() != hashes.len() {
|
||||
warn!("Block {} ({}) has different number of receipts ({}) to transactions ({}). Database corrupt?", number, hash, receipts.len(), hashes.len());
|
||||
assert!(false);
|
||||
}
|
||||
let mut log_index = receipts.iter().fold(0, |sum, receipt| sum + receipt.logs.len());
|
||||
|
||||
let receipts_len = receipts.len();
|
||||
hashes.reverse();
|
||||
receipts.reverse();
|
||||
receipts.into_iter()
|
||||
.map(|receipt| receipt.logs)
|
||||
.zip(hashes)
|
||||
.enumerate()
|
||||
.flat_map(move |(index, (mut logs, tx_hash))| {
|
||||
let current_log_index = log_index;
|
||||
let no_of_logs = logs.len();
|
||||
log_index -= no_of_logs;
|
||||
|
||||
logs.reverse();
|
||||
logs.into_iter()
|
||||
let receipts_len = receipts.len();
|
||||
hashes.reverse();
|
||||
receipts.reverse();
|
||||
receipts.into_iter()
|
||||
.map(|receipt| receipt.logs)
|
||||
.zip(hashes)
|
||||
.enumerate()
|
||||
.map(move |(i, log)| LocalizedLogEntry {
|
||||
entry: log,
|
||||
block_hash: hash,
|
||||
block_number: number,
|
||||
transaction_hash: tx_hash,
|
||||
// iterating in reverse order
|
||||
transaction_index: receipts_len - index - 1,
|
||||
transaction_log_index: no_of_logs - i - 1,
|
||||
log_index: current_log_index - i - 1,
|
||||
.flat_map(move |(index, (mut logs, tx_hash))| {
|
||||
let current_log_index = log_index;
|
||||
let no_of_logs = logs.len();
|
||||
log_index -= no_of_logs;
|
||||
|
||||
logs.reverse();
|
||||
logs.into_iter()
|
||||
.enumerate()
|
||||
.map(move |(i, log)| LocalizedLogEntry {
|
||||
entry: log,
|
||||
block_hash: hash,
|
||||
block_number: number,
|
||||
transaction_hash: tx_hash,
|
||||
// iterating in reverse order
|
||||
transaction_index: receipts_len - index - 1,
|
||||
transaction_log_index: no_of_logs - i - 1,
|
||||
log_index: current_log_index - i - 1,
|
||||
})
|
||||
})
|
||||
.filter(|log_entry| matches(&log_entry.entry))
|
||||
.take(limit.unwrap_or(::std::usize::MAX))
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.filter(|log_entry| matches(&log_entry.entry))
|
||||
.take(limit.unwrap_or(::std::usize::MAX))
|
||||
.collect::<Vec<LocalizedLogEntry>>();
|
||||
logs.reverse();
|
||||
|
||||
@@ -24,7 +24,7 @@ use time::precise_time_ns;
|
||||
// util
|
||||
use util::{Bytes, PerfTimer, Itertools, Mutex, RwLock, MutexGuard, Hashable};
|
||||
use util::{journaldb, DBValue, TrieFactory, Trie};
|
||||
use util::{U256, H256, Address, H2048};
|
||||
use util::{U256, H256, Address};
|
||||
use util::trie::TrieSpec;
|
||||
use util::kvdb::*;
|
||||
|
||||
@@ -748,7 +748,7 @@ impl Client {
|
||||
self.factories.clone(),
|
||||
).expect("state known to be available for just-imported block; qed");
|
||||
|
||||
let options = TransactOptions { tracing: false, vm_tracing: false, check_nonce: false };
|
||||
let options = TransactOptions::with_no_tracing().dont_check_nonce().save_output_from_contract();
|
||||
let res = Executive::new(&mut state, &env_info, &*self.engine)
|
||||
.transact(&transaction, options);
|
||||
|
||||
@@ -912,7 +912,7 @@ impl Client {
|
||||
_ => {},
|
||||
}
|
||||
|
||||
let block_number = match self.block_number(id.clone()) {
|
||||
let block_number = match self.block_number(id) {
|
||||
Some(num) => num,
|
||||
None => return None,
|
||||
};
|
||||
@@ -1111,6 +1111,15 @@ impl Client {
|
||||
data: data,
|
||||
}.fake_sign(from)
|
||||
}
|
||||
|
||||
fn block_number_ref(&self, id: &BlockId) -> Option<BlockNumber> {
|
||||
match *id {
|
||||
BlockId::Number(number) => Some(number),
|
||||
BlockId::Hash(ref hash) => self.chain.read().block_number(hash),
|
||||
BlockId::Earliest => Some(0),
|
||||
BlockId::Latest | BlockId::Pending => Some(self.chain.read().best_block_number()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl snapshot::DatabaseRestore for Client {
|
||||
@@ -1143,7 +1152,9 @@ impl BlockChainClient for Client {
|
||||
let mut state = self.state_at(block).ok_or(CallError::StatePruned)?;
|
||||
let original_state = if analytics.state_diffing { Some(state.clone()) } else { None };
|
||||
|
||||
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
|
||||
let options = TransactOptions::new(analytics.transaction_tracing, analytics.vm_tracing)
|
||||
.dont_check_nonce()
|
||||
.save_output_from_contract();
|
||||
let mut ret = Executive::new(&mut state, &env_info, &*self.engine).transact_virtual(t, options)?;
|
||||
|
||||
// TODO gav move this into Executive.
|
||||
@@ -1166,7 +1177,7 @@ impl BlockChainClient for Client {
|
||||
// that's just a copy of the state.
|
||||
let original_state = self.state_at(block).ok_or(CallError::StatePruned)?;
|
||||
let sender = t.sender();
|
||||
let options = TransactOptions { tracing: true, vm_tracing: false, check_nonce: false };
|
||||
let options = TransactOptions::with_tracing().dont_check_nonce();
|
||||
|
||||
let cond = |gas| {
|
||||
let mut tx = t.as_unsigned().clone();
|
||||
@@ -1231,7 +1242,9 @@ impl BlockChainClient for Client {
|
||||
return Err(CallError::TransactionNotFound);
|
||||
}
|
||||
|
||||
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
|
||||
let options = TransactOptions::new(analytics.transaction_tracing, analytics.vm_tracing)
|
||||
.dont_check_nonce()
|
||||
.save_output_from_contract();
|
||||
const PROOF: &'static str = "Transactions fetched from blockchain; blockchain transactions are valid; qed";
|
||||
let rest = txs.split_off(address.index);
|
||||
for t in txs {
|
||||
@@ -1308,12 +1321,7 @@ impl BlockChainClient for Client {
|
||||
}
|
||||
|
||||
fn block_number(&self, id: BlockId) -> Option<BlockNumber> {
|
||||
match id {
|
||||
BlockId::Number(number) => Some(number),
|
||||
BlockId::Hash(ref hash) => self.chain.read().block_number(hash),
|
||||
BlockId::Earliest => Some(0),
|
||||
BlockId::Latest | BlockId::Pending => Some(self.chain.read().best_block_number()),
|
||||
}
|
||||
self.block_number_ref(&id)
|
||||
}
|
||||
|
||||
fn block_body(&self, id: BlockId) -> Option<encoded::Body> {
|
||||
@@ -1566,16 +1574,17 @@ impl BlockChainClient for Client {
|
||||
self.engine.additional_params().into_iter().collect()
|
||||
}
|
||||
|
||||
fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockId, to_block: BlockId) -> Option<Vec<BlockNumber>> {
|
||||
match (self.block_number(from_block), self.block_number(to_block)) {
|
||||
(Some(from), Some(to)) => Some(self.chain.read().blocks_with_bloom(bloom, from, to)),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
fn logs(&self, filter: Filter) -> Vec<LocalizedLogEntry> {
|
||||
let (from, to) = match (self.block_number_ref(&filter.from_block), self.block_number_ref(&filter.to_block)) {
|
||||
(Some(from), Some(to)) => (from, to),
|
||||
_ => return Vec::new(),
|
||||
};
|
||||
|
||||
let chain = self.chain.read();
|
||||
let blocks = filter.bloom_possibilities().iter()
|
||||
.filter_map(|bloom| self.blocks_with_bloom(bloom, filter.from_block.clone(), filter.to_block.clone()))
|
||||
.map(move |bloom| {
|
||||
chain.blocks_with_bloom(bloom, from, to)
|
||||
})
|
||||
.flat_map(|m| m)
|
||||
// remove duplicate elements
|
||||
.collect::<HashSet<u64>>()
|
||||
@@ -1894,7 +1903,7 @@ impl ProvingBlockChainClient for Client {
|
||||
let backend = state::backend::Proving::new(jdb.as_hashdb_mut());
|
||||
|
||||
let mut state = state.replace_backend(backend);
|
||||
let options = TransactOptions { tracing: false, vm_tracing: false, check_nonce: false };
|
||||
let options = TransactOptions::with_no_tracing().dont_check_nonce().save_output_from_contract();
|
||||
let res = Executive::new(&mut state, &env_info, &*self.engine).transact(&transaction, options);
|
||||
|
||||
match res {
|
||||
|
||||
@@ -486,10 +486,6 @@ impl BlockChainClient for TestBlockChainClient {
|
||||
self.receipts.read().get(&id).cloned()
|
||||
}
|
||||
|
||||
fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockId, _to_block: BlockId) -> Option<Vec<BlockNumber>> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn logs(&self, filter: Filter) -> Vec<LocalizedLogEntry> {
|
||||
let mut logs = self.logs.read().clone();
|
||||
let len = logs.len();
|
||||
|
||||
@@ -33,7 +33,7 @@ use trace::LocalizedTrace;
|
||||
use transaction::{LocalizedTransaction, PendingTransaction, SignedTransaction};
|
||||
use verification::queue::QueueInfo as BlockQueueInfo;
|
||||
|
||||
use util::{U256, Address, H256, H2048, Bytes, Itertools};
|
||||
use util::{U256, Address, H256, Bytes, Itertools};
|
||||
use util::hashdb::DBValue;
|
||||
|
||||
use types::ids::*;
|
||||
@@ -175,9 +175,6 @@ pub trait BlockChainClient : Sync + Send {
|
||||
/// Get the best block header.
|
||||
fn best_block_header(&self) -> encoded::Header;
|
||||
|
||||
/// Returns numbers of blocks containing given bloom.
|
||||
fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockId, to_block: BlockId) -> Option<Vec<BlockNumber>>;
|
||||
|
||||
/// Returns logs matching given filter.
|
||||
fn logs(&self, filter: Filter) -> Vec<LocalizedLogEntry>;
|
||||
|
||||
|
||||
@@ -538,7 +538,9 @@ impl Engine for AuthorityRound {
|
||||
let parent_hash = block.fields().header.parent_hash().clone();
|
||||
::engines::common::push_last_hash(block, last_hashes.clone(), self, &parent_hash)?;
|
||||
|
||||
if !epoch_begin { return Ok(()) }
|
||||
// with immediate transitions, we don't use the epoch mechanism anyway.
|
||||
// the genesis is always considered an epoch, but we ignore it intentionally.
|
||||
if self.immediate_transitions || !epoch_begin { return Ok(()) }
|
||||
|
||||
// genesis is never a new block, but might as well check.
|
||||
let header = block.fields().header.clone();
|
||||
|
||||
@@ -72,9 +72,75 @@ pub struct TransactOptions {
|
||||
pub vm_tracing: bool,
|
||||
/// Check transaction nonce before execution.
|
||||
pub check_nonce: bool,
|
||||
/// Records the output from init contract calls.
|
||||
pub output_from_init_contract: bool,
|
||||
}
|
||||
|
||||
pub fn executor<E>(engine: &E, vm_factory: &Factory, params: &ActionParams)
|
||||
impl TransactOptions {
|
||||
/// Create new `TransactOptions` with given tracer and VM tracer.
|
||||
pub fn new(tracing: bool, vm_tracing: bool) -> Self {
|
||||
TransactOptions {
|
||||
tracing,
|
||||
vm_tracing,
|
||||
check_nonce: true,
|
||||
output_from_init_contract: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Disables the nonce check
|
||||
pub fn dont_check_nonce(mut self) -> Self {
|
||||
self.check_nonce = false;
|
||||
self
|
||||
}
|
||||
|
||||
/// Saves the output from contract creation.
|
||||
pub fn save_output_from_contract(mut self) -> Self {
|
||||
self.output_from_init_contract = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Creates new `TransactOptions` with default tracing and VM tracing.
|
||||
pub fn with_tracing_and_vm_tracing() -> Self {
|
||||
TransactOptions {
|
||||
tracing: true,
|
||||
vm_tracing: true,
|
||||
check_nonce: true,
|
||||
output_from_init_contract: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates new `TransactOptions` with default tracing and no VM tracing.
|
||||
pub fn with_tracing() -> Self {
|
||||
TransactOptions {
|
||||
tracing: true,
|
||||
vm_tracing: false,
|
||||
check_nonce: true,
|
||||
output_from_init_contract: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates new `TransactOptions` with no tracing and default VM tracing.
|
||||
pub fn with_vm_tracing() -> Self {
|
||||
TransactOptions {
|
||||
tracing: false,
|
||||
vm_tracing: true,
|
||||
check_nonce: true,
|
||||
output_from_init_contract: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates new `TransactOptions` without any tracing.
|
||||
pub fn with_no_tracing() -> Self {
|
||||
TransactOptions {
|
||||
tracing: false,
|
||||
vm_tracing: false,
|
||||
check_nonce: true,
|
||||
output_from_init_contract: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn executor<E>(engine: &E, vm_factory: &Factory, params: &ActionParams)
|
||||
-> Box<evm::Evm> where E: Engine + ?Sized
|
||||
{
|
||||
if engine.supports_wasm() && params.code.as_ref().map_or(false, |code| code.len() > 4 && &code[0..4] == WASM_MAGIC_NUMBER) {
|
||||
@@ -137,14 +203,15 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
||||
/// This function should be used to execute transaction.
|
||||
pub fn transact(&'a mut self, t: &SignedTransaction, options: TransactOptions) -> Result<Executed, ExecutionError> {
|
||||
let check = options.check_nonce;
|
||||
let output = options.output_from_init_contract;
|
||||
match options.tracing {
|
||||
true => match options.vm_tracing {
|
||||
true => self.transact_with_tracer(t, check, ExecutiveTracer::default(), ExecutiveVMTracer::toplevel()),
|
||||
false => self.transact_with_tracer(t, check, ExecutiveTracer::default(), NoopVMTracer),
|
||||
true => self.transact_with_tracer(t, check, output, ExecutiveTracer::default(), ExecutiveVMTracer::toplevel()),
|
||||
false => self.transact_with_tracer(t, check, output, ExecutiveTracer::default(), NoopVMTracer),
|
||||
},
|
||||
false => match options.vm_tracing {
|
||||
true => self.transact_with_tracer(t, check, NoopTracer, ExecutiveVMTracer::toplevel()),
|
||||
false => self.transact_with_tracer(t, check, NoopTracer, NoopVMTracer),
|
||||
true => self.transact_with_tracer(t, check, output, NoopTracer, ExecutiveVMTracer::toplevel()),
|
||||
false => self.transact_with_tracer(t, check, output, NoopTracer, NoopVMTracer),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -169,6 +236,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
||||
&'a mut self,
|
||||
t: &SignedTransaction,
|
||||
check_nonce: bool,
|
||||
output_from_create: bool,
|
||||
mut tracer: T,
|
||||
mut vm_tracer: V
|
||||
) -> Result<Executed, ExecutionError> where T: Tracer, V: VMTracer {
|
||||
@@ -237,7 +305,8 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
||||
data: None,
|
||||
call_type: CallType::None,
|
||||
};
|
||||
(self.create(params, &mut substate, &mut tracer, &mut vm_tracer), vec![])
|
||||
let mut out = if output_from_create { Some(vec![]) } else { None };
|
||||
(self.create(params, &mut substate, &mut out, &mut tracer, &mut vm_tracer), out.unwrap_or_else(Vec::new))
|
||||
},
|
||||
Action::Call(ref address) => {
|
||||
let params = ActionParams {
|
||||
@@ -430,6 +499,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
||||
&mut self,
|
||||
params: ActionParams,
|
||||
substate: &mut Substate,
|
||||
output: &mut Option<Bytes>,
|
||||
tracer: &mut T,
|
||||
vm_tracer: &mut V,
|
||||
) -> evm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer {
|
||||
@@ -471,7 +541,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
||||
let mut subvmtracer = vm_tracer.prepare_subtrace(params.code.as_ref().expect("two ways into create (Externalities::create and Executive::transact_with_tracer); both place `Some(...)` `code` in `params`; qed"));
|
||||
|
||||
let res = {
|
||||
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract(trace_output.as_mut()), &mut subtracer, &mut subvmtracer)
|
||||
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract(output.as_mut().or(trace_output.as_mut())), &mut subtracer, &mut subvmtracer)
|
||||
};
|
||||
|
||||
vm_tracer.done_subtrace(subvmtracer);
|
||||
@@ -480,7 +550,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
|
||||
Ok(ref res) => tracer.trace_create(
|
||||
trace_info,
|
||||
gas - res.gas_left,
|
||||
trace_output,
|
||||
trace_output.map(|data| output.as_ref().map(|out| out.to_vec()).unwrap_or(data)),
|
||||
created,
|
||||
subtracer.traces()
|
||||
),
|
||||
@@ -641,7 +711,7 @@ mod tests {
|
||||
|
||||
let (gas_left, _) = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap()
|
||||
ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap()
|
||||
};
|
||||
|
||||
assert_eq!(gas_left, U256::from(79_975));
|
||||
@@ -699,7 +769,7 @@ mod tests {
|
||||
|
||||
let (gas_left, _) = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap()
|
||||
ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap()
|
||||
};
|
||||
|
||||
assert_eq!(gas_left, U256::from(62_976));
|
||||
@@ -866,7 +936,7 @@ mod tests {
|
||||
|
||||
let (gas_left, _) = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
ex.create(params.clone(), &mut substate, &mut tracer, &mut vm_tracer).unwrap()
|
||||
ex.create(params.clone(), &mut substate, &mut None, &mut tracer, &mut vm_tracer).unwrap()
|
||||
};
|
||||
|
||||
assert_eq!(gas_left, U256::from(96_776));
|
||||
@@ -951,7 +1021,7 @@ mod tests {
|
||||
|
||||
let (gas_left, _) = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap()
|
||||
ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap()
|
||||
};
|
||||
|
||||
assert_eq!(gas_left, U256::from(62_976));
|
||||
@@ -1002,7 +1072,7 @@ mod tests {
|
||||
|
||||
{
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap();
|
||||
ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap();
|
||||
}
|
||||
|
||||
assert_eq!(substate.contracts_created.len(), 1);
|
||||
@@ -1138,7 +1208,7 @@ mod tests {
|
||||
|
||||
let executed = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false };
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false, output_from_init_contract: false };
|
||||
ex.transact(&t, opts).unwrap()
|
||||
};
|
||||
|
||||
@@ -1175,7 +1245,7 @@ mod tests {
|
||||
|
||||
let res = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false };
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false, output_from_init_contract: false };
|
||||
ex.transact(&t, opts)
|
||||
};
|
||||
|
||||
@@ -1208,7 +1278,7 @@ mod tests {
|
||||
|
||||
let res = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false };
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false, output_from_init_contract: false };
|
||||
ex.transact(&t, opts)
|
||||
};
|
||||
|
||||
@@ -1241,7 +1311,7 @@ mod tests {
|
||||
|
||||
let res = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false };
|
||||
let opts = TransactOptions { check_nonce: true, tracing: false, vm_tracing: false, output_from_init_contract: false };
|
||||
ex.transact(&t, opts)
|
||||
};
|
||||
|
||||
@@ -1275,7 +1345,7 @@ mod tests {
|
||||
|
||||
let result = {
|
||||
let mut ex = Executive::new(&mut state, &info, &engine);
|
||||
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer)
|
||||
ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer)
|
||||
};
|
||||
|
||||
match result {
|
||||
|
||||
@@ -219,7 +219,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
|
||||
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth, self.static_flag);
|
||||
|
||||
// TODO: handle internal error separately
|
||||
match ex.create(params, self.substate, self.tracer, self.vm_tracer) {
|
||||
match ex.create(params, self.substate, &mut None, self.tracer, self.vm_tracer) {
|
||||
Ok((gas_left, _)) => {
|
||||
self.substate.contracts_created.push(address.clone());
|
||||
ContractCreateResult::Created(address, gas_left)
|
||||
|
||||
@@ -99,6 +99,7 @@ extern crate native_contracts;
|
||||
extern crate num_cpus;
|
||||
extern crate num;
|
||||
extern crate rand;
|
||||
extern crate rayon;
|
||||
extern crate rlp;
|
||||
extern crate rustc_hex;
|
||||
extern crate rustc_serialize;
|
||||
|
||||
@@ -742,7 +742,7 @@ impl MinerService for Miner {
|
||||
state.add_balance(&sender, &(needed_balance - balance), CleanupMode::NoEmpty)
|
||||
.map_err(ExecutionError::from)?;
|
||||
}
|
||||
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
|
||||
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false, output_from_init_contract: true };
|
||||
let mut ret = Executive::new(&mut state, &env_info, &*self.engine).transact(t, options)?;
|
||||
|
||||
// TODO gav move this into Executive.
|
||||
|
||||
@@ -506,8 +506,6 @@ pub struct AccountDetails {
|
||||
pub balance: U256,
|
||||
}
|
||||
|
||||
/// Transactions with `gas > (gas_limit + gas_limit * Factor(in percents))` are not imported to the queue.
|
||||
const GAS_LIMIT_HYSTERESIS: usize = 200; // (100/GAS_LIMIT_HYSTERESIS) %
|
||||
/// Transaction with the same (sender, nonce) can be replaced only if
|
||||
/// `new_gas_price > old_gas_price + old_gas_price >> SHIFT`
|
||||
const GAS_PRICE_BUMP_SHIFT: usize = 3; // 2 = 25%, 3 = 12.5%, 4 = 6.25%
|
||||
@@ -570,8 +568,8 @@ pub struct TransactionQueue {
|
||||
minimal_gas_price: U256,
|
||||
/// The maximum amount of gas any individual transaction may use.
|
||||
tx_gas_limit: U256,
|
||||
/// Current gas limit (block gas limit * factor). Transactions above the limit will not be accepted (default to !0)
|
||||
total_gas_limit: U256,
|
||||
/// Current gas limit (block gas limit). Transactions above the limit will not be accepted (default to !0)
|
||||
block_gas_limit: U256,
|
||||
/// Maximal time transaction may occupy the queue.
|
||||
/// When we reach `max_time_in_queue / 2^3` we re-validate
|
||||
/// account balance.
|
||||
@@ -631,7 +629,7 @@ impl TransactionQueue {
|
||||
TransactionQueue {
|
||||
strategy,
|
||||
minimal_gas_price: U256::zero(),
|
||||
total_gas_limit: !U256::zero(),
|
||||
block_gas_limit: !U256::zero(),
|
||||
tx_gas_limit,
|
||||
max_time_in_queue: DEFAULT_QUEUING_PERIOD,
|
||||
current,
|
||||
@@ -674,16 +672,10 @@ impl TransactionQueue {
|
||||
self.current.gas_price_entry_limit()
|
||||
}
|
||||
|
||||
/// Sets new gas limit. Transactions with gas slightly (`GAS_LIMIT_HYSTERESIS`) above the limit won't be imported.
|
||||
/// Sets new gas limit. Transactions with gas over the limit will not be accepted.
|
||||
/// Any transaction already imported to the queue is not affected.
|
||||
pub fn set_gas_limit(&mut self, gas_limit: U256) {
|
||||
let extra = gas_limit / U256::from(GAS_LIMIT_HYSTERESIS);
|
||||
|
||||
let total_gas_limit = match gas_limit.overflowing_add(extra) {
|
||||
(_, true) => !U256::zero(),
|
||||
(val, false) => val,
|
||||
};
|
||||
self.total_gas_limit = total_gas_limit;
|
||||
self.block_gas_limit = gas_limit;
|
||||
}
|
||||
|
||||
/// Sets new total gas limit.
|
||||
@@ -819,13 +811,13 @@ impl TransactionQueue {
|
||||
}));
|
||||
}
|
||||
|
||||
let gas_limit = cmp::min(self.tx_gas_limit, self.total_gas_limit);
|
||||
let gas_limit = cmp::min(self.tx_gas_limit, self.block_gas_limit);
|
||||
if tx.gas > gas_limit {
|
||||
trace!(target: "txqueue",
|
||||
"Dropping transaction above gas limit: {:?} ({} > min({}, {}))",
|
||||
tx.hash(),
|
||||
tx.gas,
|
||||
self.total_gas_limit,
|
||||
self.block_gas_limit,
|
||||
self.tx_gas_limit
|
||||
);
|
||||
return Err(Error::Transaction(TransactionError::GasLimitExceeded {
|
||||
@@ -1922,13 +1914,13 @@ pub mod test {
|
||||
// given
|
||||
let mut txq = TransactionQueue::default();
|
||||
txq.set_gas_limit(U256::zero());
|
||||
assert_eq!(txq.total_gas_limit, U256::zero());
|
||||
assert_eq!(txq.block_gas_limit, U256::zero());
|
||||
|
||||
// when
|
||||
txq.set_gas_limit(!U256::zero());
|
||||
|
||||
// then
|
||||
assert_eq!(txq.total_gas_limit, !U256::zero());
|
||||
assert_eq!(txq.block_gas_limit, !U256::zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1945,7 +1937,7 @@ pub mod test {
|
||||
|
||||
// then
|
||||
assert_eq!(unwrap_tx_err(res), TransactionError::GasLimitExceeded {
|
||||
limit: U256::from(50_250), // Should be 100.5% of set_gas_limit
|
||||
limit: U256::from(50_000),
|
||||
got: gas,
|
||||
});
|
||||
let stats = txq.status();
|
||||
|
||||
@@ -311,11 +311,10 @@ impl Spec {
|
||||
};
|
||||
|
||||
let mut substate = Substate::new();
|
||||
state.kill_account(&address);
|
||||
|
||||
{
|
||||
let mut exec = Executive::new(&mut state, &env_info, self.engine.as_ref());
|
||||
if let Err(e) = exec.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer) {
|
||||
if let Err(e) = exec.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer) {
|
||||
warn!(target: "spec", "Genesis constructor execution at {} failed: {}.", address, e);
|
||||
}
|
||||
}
|
||||
@@ -525,6 +524,9 @@ mod tests {
|
||||
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
||||
let state = State::from_existing(db.boxed_clone(), spec.state_root(), spec.engine.account_start_nonce(0), Default::default()).unwrap();
|
||||
let expected = H256::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap();
|
||||
assert_eq!(state.storage_at(&Address::from_str("0000000000000000000000000000000000000005").unwrap(), &H256::zero()).unwrap(), expected);
|
||||
let address = Address::from_str("0000000000000000000000000000000000000005").unwrap();
|
||||
|
||||
assert_eq!(state.storage_at(&address, &H256::zero()).unwrap(), expected);
|
||||
assert_eq!(state.balance(&address).unwrap(), 1.into());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,7 +642,7 @@ impl<B: Backend> State<B> {
|
||||
fn execute(&mut self, env_info: &EnvInfo, engine: &Engine, t: &SignedTransaction, tracing: bool, virt: bool)
|
||||
-> Result<Executed, ExecutionError>
|
||||
{
|
||||
let options = TransactOptions { tracing: tracing, vm_tracing: false, check_nonce: true };
|
||||
let options = TransactOptions { tracing: tracing, vm_tracing: false, check_nonce: true, output_from_init_contract: true };
|
||||
let mut e = Executive::new(self, env_info, engine);
|
||||
|
||||
match virt {
|
||||
|
||||
@@ -380,14 +380,13 @@ mod tests {
|
||||
self.numbers.get(&index).cloned()
|
||||
}
|
||||
|
||||
fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockNumber, _to_block: BlockNumber) -> Vec<BlockNumber> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn block_receipts(&self, _hash: &H256) -> Option<BlockReceipts> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockNumber, _to_block: BlockNumber) -> Vec<BlockNumber> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn logs<F>(&self, _blocks: Vec<BlockNumber>, _matches: F, _limit: Option<usize>) -> Vec<LocalizedLogEntry>
|
||||
where F: Fn(&LogEntry) -> bool, Self: Sized {
|
||||
|
||||
Reference in New Issue
Block a user