TypedTransaction (EIP-2718) and Optional access list (EIP-2930) (#135)

This commit is contained in:
rakita
2020-12-10 16:42:05 +01:00
committed by GitHub
parent 3f01b69084
commit ea3efd926e
83 changed files with 1858 additions and 805 deletions

View File

@@ -48,10 +48,10 @@ use verification::PreverifiedBlock;
use vm::{EnvInfo, LastHashes};
use hash::keccak;
use rlp::{encode_list, Encodable, RlpStream};
use rlp::{encode_list, RlpStream};
use types::{
header::{ExtendedHeader, Header},
receipt::{Receipt, TransactionOutcome},
receipt::{TransactionOutcome, TypedReceipt},
transaction::{Error as TransactionError, SignedTransaction},
};
@@ -99,7 +99,7 @@ pub struct ExecutedBlock {
/// Uncles.
pub uncles: Vec<Header>,
/// Transaction receipts.
pub receipts: Vec<Receipt>,
pub receipts: Vec<TypedReceipt>,
/// Hashes of already executed transactions.
pub transactions_set: HashSet<H256>,
/// Underlaying state.
@@ -253,7 +253,7 @@ impl<'x> OpenBlock<'x> {
&mut self,
t: SignedTransaction,
h: Option<H256>,
) -> Result<&Receipt, Error> {
) -> Result<&TypedReceipt, Error> {
if self.block.transactions_set.contains(&t.hash()) {
return Err(TransactionError::AlreadyImported.into());
}
@@ -360,13 +360,13 @@ impl<'x> OpenBlock<'x> {
// t_nb 8.5.3 fill open block header with all other fields
s.block.header.set_transactions_root(ordered_trie_root(
s.block.transactions.iter().map(|e| e.rlp_bytes()),
s.block.transactions.iter().map(|e| e.encode()),
));
let uncle_bytes = encode_list(&s.block.uncles);
s.block.header.set_uncles_hash(keccak(&uncle_bytes));
s.block.header.set_state_root(s.block.state.root().clone());
s.block.header.set_receipts_root(ordered_trie_root(
s.block.receipts.iter().map(|r| r.rlp_bytes()),
s.block.receipts.iter().map(|r| r.encode()),
));
s.block
.header
@@ -453,7 +453,7 @@ impl LockedBlock {
receipt.outcome = TransactionOutcome::Unknown;
}
self.block.header.set_receipts_root(ordered_trie_root(
self.block.receipts.iter().map(|r| r.rlp_bytes()),
self.block.receipts.iter().map(|r| r.encode()),
));
}
@@ -503,7 +503,7 @@ impl SealedBlock {
pub fn rlp_bytes(&self) -> Bytes {
let mut block_rlp = RlpStream::new_list(3);
block_rlp.append(&self.block.header);
block_rlp.append_list(&self.block.transactions);
SignedTransaction::rlp_append_list(&mut block_rlp, &self.block.transactions);
block_rlp.append_list(&self.block.uncles);
block_rlp.out()
}

View File

@@ -41,7 +41,7 @@ use itertools::Itertools;
use kvdb::{DBTransaction, DBValue, KeyValueDB};
use parking_lot::{Mutex, RwLock};
use rand::OsRng;
use rlp::PayloadInfo;
use rlp::{PayloadInfo, Rlp};
use rustc_hex::FromHex;
use trie::{Trie, TrieFactory, TrieSpec};
use types::{
@@ -51,8 +51,11 @@ use types::{
filter::Filter,
header::{ExtendedHeader, Header},
log_entry::LocalizedLogEntry,
receipt::{LocalizedReceipt, Receipt},
transaction::{self, Action, LocalizedTransaction, SignedTransaction, UnverifiedTransaction},
receipt::{LocalizedReceipt, TypedReceipt},
transaction::{
self, Action, LocalizedTransaction, SignedTransaction, TypedTransaction,
UnverifiedTransaction,
},
BlockNumber,
};
use vm::{EnvInfo, LastHashes};
@@ -524,7 +527,8 @@ impl Importer {
db: &dyn KeyValueDB,
chain: &BlockChain,
) -> EthcoreResult<()> {
let receipts = ::rlp::decode_list(receipts_bytes);
let receipts = TypedReceipt::decode_rlp_list(&Rlp::new(receipts_bytes))
.unwrap_or_else(|e| panic!("Receipt bytes should be valid: {:?}", e));
let _import_lock = self.import_lock.lock();
{
@@ -714,7 +718,7 @@ impl Importer {
&self,
header: &Header,
block_bytes: &[u8],
receipts: &[Receipt],
receipts: &[TypedReceipt],
state_db: &StateDB,
client: &Client,
) -> EthcoreResult<Option<PendingTransition>> {
@@ -1436,7 +1440,7 @@ impl Client {
data: Bytes,
) -> SignedTransaction {
let from = Address::default();
transaction::Transaction {
TypedTransaction::Legacy(transaction::Transaction {
nonce: self
.nonce(&from, block_id)
.unwrap_or_else(|| self.engine.account_start_nonce(0)),
@@ -1445,7 +1449,7 @@ impl Client {
gas_price: U256::default(),
value: U256::default(),
data: data,
}
})
.fake_sign(from)
}
@@ -1889,7 +1893,7 @@ impl Call for Client {
let exec = |gas| {
let mut tx = t.as_unsigned().clone();
tx.gas = gas;
tx.tx_mut().gas = gas;
let tx = tx.fake_sign(sender);
let mut clone = state.clone();
@@ -1920,6 +1924,7 @@ impl Call for Client {
}
}
let lower = t
.tx()
.gas_required(&self.engine.schedule(env_info.number))
.into();
if cond(lower) {
@@ -2571,18 +2576,18 @@ impl BlockChainClient for Client {
} else {
self.importer.miner.sensible_gas_price()
};
let transaction = transaction::Transaction {
let transaction = TypedTransaction::Legacy(transaction::Transaction {
nonce: self.latest_nonce(&authoring_params.author),
action: Action::Call(address),
gas: self.importer.miner.sensible_gas_limit(),
gas_price,
value: U256::zero(),
data: data,
};
});
let chain_id = self.engine.signing_chain_id(&self.latest_env_info());
let signature = self
.engine
.sign(transaction.hash(chain_id))
.sign(transaction.signature_hash(chain_id))
.map_err(|e| transaction::Error::InvalidSignature(e.to_string()))?;
let signed = SignedTransaction::new(transaction.with_signature(signature, chain_id))?;
self.importer
@@ -2602,10 +2607,15 @@ impl IoClient for Client {
self.queue_transactions
.queue(&self.io_channel.read(), len, move |client| {
trace_time!("import_queued_transactions");
let best_block_number = client.best_block_header().number();
let txs: Vec<UnverifiedTransaction> = transactions
.iter()
.filter_map(|bytes| client.engine.decode_transaction(bytes).ok())
.filter_map(|bytes| {
client
.engine
.decode_transaction(bytes, best_block_number)
.ok()
})
.collect();
client.notify(|notify| {
@@ -2954,7 +2964,7 @@ impl ProvingBlockChainClient for Client {
_ => return None,
};
env_info.gas_limit = transaction.gas.clone();
env_info.gas_limit = transaction.tx().gas.clone();
let mut jdb = self.state_db.read().journal_db().boxed_clone();
state::prove_transaction_virtual(
@@ -3112,7 +3122,7 @@ impl ImportExportBlocks for Client {
fn transaction_receipt(
machine: &::machine::EthereumMachine,
mut tx: LocalizedTransaction,
receipt: Receipt,
receipt: TypedReceipt,
prior_gas_used: U256,
prior_no_of_logs: usize,
) -> LocalizedReceipt {
@@ -3121,27 +3131,31 @@ fn transaction_receipt(
let block_hash = tx.block_hash;
let block_number = tx.block_number;
let transaction_index = tx.transaction_index;
let transaction_type = tx.tx_type();
let receipt = receipt.receipt().clone();
LocalizedReceipt {
from: sender,
to: match tx.action {
to: match tx.tx().action {
Action::Create => None,
Action::Call(ref address) => Some(address.clone().into()),
},
transaction_hash: transaction_hash,
transaction_index: transaction_index,
transaction_type: transaction_type,
block_hash: block_hash,
block_number: block_number,
cumulative_gas_used: receipt.gas_used,
gas_used: receipt.gas_used - prior_gas_used,
contract_address: match tx.action {
contract_address: match tx.tx().action {
Action::Call(_) => None,
Action::Create => Some(
contract_address(
machine.create_address_scheme(block_number),
&sender,
&tx.nonce,
&tx.data,
&tx.tx().nonce,
&tx.tx().data,
)
.0,
),
@@ -3161,7 +3175,7 @@ fn transaction_receipt(
})
.collect(),
log_bloom: receipt.log_bloom,
outcome: receipt.outcome,
outcome: receipt.outcome.clone(),
}
}
@@ -3457,8 +3471,8 @@ mod tests {
use hash::keccak;
use types::{
log_entry::{LocalizedLogEntry, LogEntry},
receipt::{LocalizedReceipt, Receipt, TransactionOutcome},
transaction::{Action, LocalizedTransaction, Transaction},
receipt::{LegacyReceipt, LocalizedReceipt, TransactionOutcome, TypedReceipt},
transaction::{Action, LocalizedTransaction, Transaction, TypedTransaction},
};
// given
@@ -3470,14 +3484,14 @@ mod tests {
let block_hash = 5.into();
let state_root = 99.into();
let gas_used = 10.into();
let raw_tx = Transaction {
let raw_tx = TypedTransaction::Legacy(Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 21000.into(),
action: Action::Call(10.into()),
value: 0.into(),
data: vec![],
};
});
let tx1 = raw_tx.clone().sign(secret, None);
let transaction = LocalizedTransaction {
signed: tx1.clone().into(),
@@ -3498,12 +3512,12 @@ mod tests {
data: vec![],
},
];
let receipt = Receipt {
let receipt = TypedReceipt::Legacy(LegacyReceipt {
outcome: TransactionOutcome::StateRoot(state_root),
gas_used: gas_used,
log_bloom: Default::default(),
logs: logs.clone(),
};
});
// when
let receipt = transaction_receipt(&machine, transaction, receipt, 5.into(), 1);
@@ -3513,12 +3527,13 @@ mod tests {
receipt,
LocalizedReceipt {
from: tx1.sender().into(),
to: match tx1.action {
to: match tx1.tx().action {
Action::Create => None,
Action::Call(ref address) => Some(address.clone().into()),
},
transaction_hash: tx1.hash(),
transaction_index: 1,
transaction_type: tx1.tx_type(),
block_hash: block_hash,
block_number: block_number,
cumulative_gas_used: gas_used,

View File

@@ -281,7 +281,7 @@ impl<'a> EvmTestClient<'a> {
tracer: T,
vm_tracer: V,
) -> std::result::Result<TransactSuccess<T::Output, V::Output>, TransactErr> {
let initial_gas = transaction.gas;
let initial_gas = transaction.tx().gas;
// Verify transaction
let is_ok = transaction.verify_basic(true, None);
if let Err(error) = is_ok {
@@ -342,18 +342,18 @@ impl<'a> EvmTestClient<'a> {
Ok(result) => Ok(TransactSuccess {
state_root,
gas_left: initial_gas - result.receipt.gas_used,
outcome: result.receipt.outcome,
outcome: result.receipt.outcome.clone(),
output: result.output,
trace: result.trace,
vm_trace: result.vm_trace,
logs: result.receipt.logs,
contract_address: if let transaction::Action::Create = transaction.action {
logs: result.receipt.logs.clone(),
contract_address: if let transaction::Action::Create = transaction.tx().action {
Some(
executive::contract_address(
scheme,
&transaction.sender(),
&transaction.nonce,
&transaction.data,
&transaction.tx().nonce,
&transaction.tx().data,
)
.0,
)

View File

@@ -36,7 +36,7 @@ use itertools::Itertools;
use kvdb::DBValue;
use kvdb_memorydb;
use parking_lot::RwLock;
use rlp::{Rlp, RlpStream};
use rlp::RlpStream;
use rustc_hex::FromHex;
use types::{
basic_account::BasicAccount,
@@ -45,8 +45,11 @@ use types::{
header::Header,
log_entry::LocalizedLogEntry,
pruning_info::PruningInfo,
receipt::{LocalizedReceipt, Receipt, TransactionOutcome},
transaction::{self, Action, LocalizedTransaction, SignedTransaction, Transaction},
receipt::{LegacyReceipt, LocalizedReceipt, TransactionOutcome, TypedReceipt},
transaction::{
self, Action, LocalizedTransaction, SignedTransaction, Transaction, TypedTransaction,
TypedTxId,
},
view,
views::BlockView,
BlockNumber,
@@ -296,16 +299,16 @@ impl TestBlockChainClient {
for _ in 0..num_transactions {
// Update nonces value
let tx = Transaction {
let tx = TypedTransaction::Legacy(Transaction {
action: Action::Create,
value: U256::from(100),
data: "3331600055".from_hex().unwrap(),
gas: U256::from(100_000),
gas_price: U256::from(200_000_000_000u64),
nonce: nonce,
};
});
let signed_tx = tx.sign(keypair.secret(), None);
txs.append(&signed_tx);
signed_tx.rlp_append(&mut txs);
nonce += U256::one();
}
@@ -369,14 +372,14 @@ impl TestBlockChainClient {
/// Inserts a transaction with given gas price to miners transactions queue.
pub fn insert_transaction_with_gas_price_to_queue(&self, gas_price: U256) -> H256 {
let keypair = Random.generate().unwrap();
let tx = Transaction {
let tx = TypedTransaction::Legacy(Transaction {
action: Action::Create,
value: U256::from(100),
data: "3331600055".from_hex().unwrap(),
gas: U256::from(100_000),
gas_price: gas_price,
nonce: U256::zero(),
};
});
let signed_tx = tx.sign(keypair.secret(), None);
self.set_balance(signed_tx.sender(), 10_000_000_000_000_000_000u64.into());
let hash = signed_tx.hash();
@@ -938,10 +941,13 @@ impl BlockChainClient for TestBlockChainClient {
fn block_receipts(&self, hash: &H256) -> Option<BlockReceipts> {
// starts with 'f' ?
if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") {
let receipt = BlockReceipts::new(vec![Receipt::new(
TransactionOutcome::StateRoot(H256::zero()),
U256::zero(),
vec![],
let receipt = BlockReceipts::new(vec![TypedReceipt::new(
TypedTxId::Legacy,
LegacyReceipt::new(
TransactionOutcome::StateRoot(H256::zero()),
U256::zero(),
vec![],
),
)]);
return Some(receipt);
}
@@ -1027,16 +1033,20 @@ impl BlockChainClient for TestBlockChainClient {
}
fn transact_contract(&self, address: Address, data: Bytes) -> Result<(), transaction::Error> {
let transaction = Transaction {
let transaction = TypedTransaction::Legacy(Transaction {
nonce: self.latest_nonce(&self.miner.authoring_params().author),
action: Action::Call(address),
gas: self.spec.gas_limit,
gas_price: U256::zero(),
value: U256::default(),
data: data,
};
});
let chain_id = Some(self.spec.chain_id());
let sig = self.spec.engine.sign(transaction.hash(chain_id)).unwrap();
let sig = self
.spec
.engine
.sign(transaction.signature_hash(chain_id))
.unwrap();
let signed = SignedTransaction::new(transaction.with_signature(sig, chain_id)).unwrap();
self.miner.import_own_transaction(self, signed.into())
}
@@ -1051,7 +1061,7 @@ impl IoClient for TestBlockChainClient {
// import right here
let txs = transactions
.into_iter()
.filter_map(|bytes| Rlp::new(&bytes).as_val().ok())
.filter_map(|bytes| TypedTransaction::decode(&bytes).ok())
.collect();
self.miner.import_external_transactions(self, txs);
}

View File

@@ -1765,7 +1765,7 @@ mod tests {
use test_helpers::{generate_dummy_client_with_spec, get_temp_state_db, TestNotify};
use types::{
header::Header,
transaction::{Action, Transaction},
transaction::{Action, Transaction, TypedTransaction},
};
fn aura<F>(f: F) -> Arc<AuthorityRound>
@@ -2287,14 +2287,14 @@ mod tests {
)
.unwrap();
b2.push_transaction(
Transaction {
TypedTransaction::Legacy(Transaction {
action: Action::Create,
nonce: U256::from(0),
gas_price: U256::from(3000),
gas: U256::from(53_000),
value: U256::from(1),
data: vec![],
}
})
.fake_sign(addr2),
None,
)

View File

@@ -605,8 +605,10 @@ pub trait EthEngine: Engine<::machine::EthereumMachine> {
fn decode_transaction(
&self,
transaction: &[u8],
best_block_number: BlockNumber,
) -> Result<UnverifiedTransaction, transaction::Error> {
self.machine().decode_transaction(transaction)
let schedule = self.schedule(best_block_number);
self.machine().decode_transaction(transaction, &schedule)
}
}

View File

@@ -25,7 +25,7 @@ use kvdb::DBValue;
use memory_cache::MemoryLruCache;
use parking_lot::RwLock;
use rlp::{Rlp, RlpStream};
use types::{header::Header, ids::BlockId, log_entry::LogEntry, receipt::Receipt};
use types::{header::Header, ids::BlockId, log_entry::LogEntry, receipt::TypedReceipt};
use unexpected::Mismatch;
use super::{simple_list::SimpleList, SystemCall, ValidatorSet};
@@ -91,7 +91,7 @@ fn check_first_proof(
old_header: Header,
state_items: &[DBValue],
) -> Result<Vec<Address>, String> {
use types::transaction::{Action, Transaction};
use types::transaction::{Action, Transaction, TypedTransaction};
// TODO: match client contract_call_tx more cleanly without duplication.
const PROVIDED_GAS: u64 = 50_000_000;
@@ -116,14 +116,14 @@ fn check_first_proof(
let (data, decoder) = validator_set::functions::get_validators::call();
let from = Address::default();
let tx = Transaction {
let tx = TypedTransaction::Legacy(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 res = ::state::check_proof(
@@ -161,14 +161,15 @@ fn decode_first_proof(rlp: &Rlp) -> Result<(Header, Vec<DBValue>), ::error::Erro
// inter-contract proofs are a header and receipts.
// checking will involve ensuring that the receipts match the header and
// extracting the validator set from the receipts.
fn encode_proof(header: &Header, receipts: &[Receipt]) -> Bytes {
fn encode_proof(header: &Header, receipts: &[TypedReceipt]) -> Bytes {
let mut stream = RlpStream::new_list(2);
stream.append(header).append_list(receipts);
stream.append(header);
TypedReceipt::rlp_append_list(&mut stream, receipts);
stream.drain()
}
fn decode_proof(rlp: &Rlp) -> Result<(Header, Vec<Receipt>), ::error::Error> {
Ok((rlp.val_at(0)?, rlp.list_at(1)?))
fn decode_proof(rlp: &Rlp) -> Result<(Header, Vec<TypedReceipt>), ::error::Error> {
Ok((rlp.val_at(0)?, TypedReceipt::decode_rlp_list(&rlp.at(1)?)?))
}
// given a provider and caller, generate proof. this will just be a state proof
@@ -265,7 +266,7 @@ impl ValidatorSafeContract {
&self,
bloom: Bloom,
header: &Header,
receipts: &[Receipt],
receipts: &[TypedReceipt],
) -> Option<SimpleList> {
let check_log = |log: &LogEntry| {
log.address == self.contract_address
@@ -406,7 +407,7 @@ impl ValidatorSet for ValidatorSafeContract {
// ensure receipts match header.
// TODO: optimize? these were just decoded.
let found_root = ::triehash::ordered_trie_root(receipts.iter().map(::rlp::encode));
let found_root = ::triehash::ordered_trie_root(receipts.iter().map(|r| r.encode()));
if found_root != *old_header.receipts_root() {
return Err(::error::BlockError::InvalidReceiptsRoot(Mismatch {
expected: *old_header.receipts_root(),
@@ -491,7 +492,7 @@ mod tests {
use test_helpers::{generate_dummy_client_with_spec, generate_dummy_client_with_spec_and_data};
use types::{
ids::BlockId,
transaction::{Action, Transaction},
transaction::{Action, Transaction, TypedTransaction},
};
use verification::queue::kind::blocks::Unverified;
@@ -537,7 +538,7 @@ mod tests {
client.miner().set_author(miner::Author::Sealer(signer));
// Remove "1" validator.
let tx = Transaction {
let tx = TypedTransaction::Legacy(Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 500_000.into(),
@@ -546,7 +547,7 @@ mod tests {
data: "bfc708a000000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1"
.from_hex()
.unwrap(),
}
})
.sign(&s0, Some(chain_id));
client
.miner()
@@ -555,7 +556,7 @@ mod tests {
EngineClient::update_sealing(&*client, ForceUpdateSealing::No);
assert_eq!(client.chain_info().best_block_number, 1);
// Add "1" validator back in.
let tx = Transaction {
let tx = TypedTransaction::Legacy(Transaction {
nonce: 1.into(),
gas_price: 0.into(),
gas: 500_000.into(),
@@ -564,7 +565,7 @@ mod tests {
data: "4d238c8e00000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1"
.from_hex()
.unwrap(),
}
})
.sign(&s0, Some(chain_id));
client
.miner()
@@ -582,14 +583,14 @@ mod tests {
// Switch back to the added validator, since the state is updated.
let signer = Box::new((tap.clone(), v1, "".into()));
client.miner().set_author(miner::Author::Sealer(signer));
let tx = Transaction {
let tx = TypedTransaction::Legacy(Transaction {
nonce: 2.into(),
gas_price: 0.into(),
gas: 21000.into(),
action: Action::Call(Address::default()),
value: 0.into(),
data: Vec::new(),
}
})
.sign(&s0, Some(chain_id));
client
.miner()

View File

@@ -28,7 +28,7 @@ use state::{Backend as StateBackend, CleanupMode, State, Substate};
use std::{cmp, sync::Arc};
use trace::{self, Tracer, VMTracer};
use transaction_ext::Transaction;
use types::transaction::{Action, SignedTransaction};
use types::transaction::{Action, SignedTransaction, TypedTransaction};
use vm::{
self, AccessList, ActionParams, ActionValue, CleanDustMode, CreateContractAddress, EnvInfo,
ResumeCall, ResumeCreate, ReturnData, Schedule, TrapError,
@@ -1109,7 +1109,10 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
{
let sender = t.sender();
let balance = self.state.balance(&sender)?;
let needed_balance = t.value.saturating_add(t.gas.saturating_mul(t.gas_price));
let needed_balance = t
.tx()
.value
.saturating_add(t.tx().gas.saturating_mul(t.tx().gas_price));
if balance < needed_balance {
// give the sender a sufficient balance
self.state
@@ -1132,16 +1135,51 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
T: Tracer,
V: VMTracer,
{
let schedule = self.schedule;
// check if particualar transaction type is enabled at this block number in schedule
match t.as_unsigned() {
TypedTransaction::AccessList(_) => {
if !schedule.eip2930 {
return Err(ExecutionError::TransactionMalformed(
"OptionalAccessList EIP-2930 or EIP-2929 not enabled".into(),
));
}
}
TypedTransaction::Legacy(_) => (), //legacy transactions are allways valid
};
let sender = t.sender();
let nonce = self.state.nonce(&sender)?;
let schedule = self.schedule;
let base_gas_required = U256::from(t.gas_required(&schedule));
let mut base_gas_required = U256::from(t.tx().gas_required(&schedule));
if t.gas < base_gas_required {
let mut access_list = AccessList::new(schedule.eip2929);
if schedule.eip2929 {
for (address, _) in self.machine.builtins() {
access_list.insert_address(*address);
}
if schedule.eip2930 {
// optional access list
if let TypedTransaction::AccessList(al_tx) = t.as_unsigned() {
for item in al_tx.access_list.iter() {
access_list.insert_address(item.0);
base_gas_required += vm::schedule::EIP2930_ACCESS_LIST_ADDRESS_COST.into();
for key in item.1.iter() {
access_list.insert_storage_key(item.0, *key);
base_gas_required +=
vm::schedule::EIP2930_ACCESS_LIST_STORAGE_KEY_COST.into();
}
}
}
}
}
if t.tx().gas < base_gas_required {
return Err(ExecutionError::NotEnoughBaseGas {
required: base_gas_required,
got: t.gas,
got: t.tx().gas,
});
}
@@ -1153,29 +1191,29 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
return Err(ExecutionError::SenderMustExist);
}
let init_gas = t.gas - base_gas_required;
let init_gas = t.tx().gas - base_gas_required;
// validate transaction nonce
if check_nonce && t.nonce != nonce {
if check_nonce && t.tx().nonce != nonce {
return Err(ExecutionError::InvalidNonce {
expected: nonce,
got: t.nonce,
got: t.tx().nonce,
});
}
// validate if transaction fits into given block
if self.info.gas_used + t.gas > self.info.gas_limit {
if self.info.gas_used + t.tx().gas > self.info.gas_limit {
return Err(ExecutionError::BlockGasLimitReached {
gas_limit: self.info.gas_limit,
gas_used: self.info.gas_used,
gas: t.gas,
gas: t.tx().gas,
});
}
// TODO: we might need bigints here, or at least check overflows.
let balance = self.state.balance(&sender)?;
let gas_cost = t.gas.full_mul(t.gas_price);
let total_cost = U512::from(t.value) + gas_cost;
let gas_cost = t.tx().gas.full_mul(t.tx().gas_price);
let total_cost = U512::from(t.tx().value) + gas_cost;
// avoid unaffordable transactions
let balance512 = U512::from(balance);
@@ -1186,13 +1224,6 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
});
}
let mut access_list = AccessList::new(schedule.eip2929);
if schedule.eip2929 {
for (address, _) in self.machine.builtins() {
access_list.insert_address(*address);
}
}
let mut substate = Substate::from_access_list(&access_list);
// NOTE: there can be no invalid transactions from this point.
@@ -1205,13 +1236,13 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
&mut substate.to_cleanup_mode(&schedule),
)?;
let (result, output) = match t.action {
let (result, output) = match t.tx().action {
Action::Create => {
let (new_address, code_hash) = contract_address(
self.machine.create_address_scheme(self.info.number),
&sender,
&nonce,
&t.data,
&t.tx().data,
);
let params = ActionParams {
code_address: new_address.clone(),
@@ -1220,9 +1251,9 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
sender: sender.clone(),
origin: sender.clone(),
gas: init_gas,
gas_price: t.gas_price,
value: ActionValue::Transfer(t.value),
code: Some(Arc::new(t.data.clone())),
gas_price: t.tx().gas_price,
value: ActionValue::Transfer(t.tx().value),
code: Some(Arc::new(t.tx().data.clone())),
data: None,
call_type: CallType::None,
params_type: vm::ParamsType::Embedded,
@@ -1242,11 +1273,11 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
sender: sender.clone(),
origin: sender.clone(),
gas: init_gas,
gas_price: t.gas_price,
value: ActionValue::Transfer(t.value),
gas_price: t.tx().gas_price,
value: ActionValue::Transfer(t.tx().value),
code: self.state.code(address)?,
code_hash: self.state.code_hash(address)?,
data: Some(t.data.clone()),
data: Some(t.tx().data.clone()),
call_type: CallType::Call,
params_type: vm::ParamsType::Separate,
access_list: access_list,
@@ -1445,12 +1476,12 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
Ok(FinalizationResult { gas_left, .. }) => gas_left,
_ => 0.into(),
};
let refunded = cmp::min(refunds_bound, (t.gas - gas_left_prerefund) >> 1);
let refunded = cmp::min(refunds_bound, (t.tx().gas - gas_left_prerefund) >> 1);
let gas_left = gas_left_prerefund + refunded;
let gas_used = t.gas.saturating_sub(gas_left);
let (refund_value, overflow_1) = gas_left.overflowing_mul(t.gas_price);
let (fees_value, overflow_2) = gas_used.overflowing_mul(t.gas_price);
let gas_used = t.tx().gas.saturating_sub(gas_left);
let (refund_value, overflow_1) = gas_left.overflowing_mul(t.tx().gas_price);
let (fees_value, overflow_2) = gas_used.overflowing_mul(t.tx().gas_price);
if overflow_1 || overflow_2 {
return Err(ExecutionError::TransactionMalformed(
"U256 Overflow".to_string(),
@@ -1458,7 +1489,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
}
trace!("exec::finalize: t.gas={}, sstore_refunds={}, suicide_refunds={}, refunds_bound={}, gas_left_prerefund={}, refunded={}, gas_left={}, gas_used={}, refund_value={}, fees_value={}\n",
t.gas, sstore_refunds, suicide_refunds, refunds_bound, gas_left_prerefund, refunded, gas_left, gas_used, refund_value, fees_value);
t.tx().gas, sstore_refunds, suicide_refunds, refunds_bound, gas_left_prerefund, refunded, gas_left, gas_used, refund_value, fees_value);
let sender = t.sender();
trace!(
@@ -1487,7 +1518,11 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
// perform garbage-collection
let min_balance = if schedule.kill_dust != CleanDustMode::Off {
Some(U256::from(schedule.tx_gas).overflowing_mul(t.gas_price).0)
Some(
U256::from(schedule.tx_gas)
.overflowing_mul(t.tx().gas_price)
.0,
)
} else {
None
};
@@ -1502,10 +1537,10 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
Err(vm::Error::Internal(msg)) => Err(ExecutionError::Internal(msg)),
Err(exception) => Ok(Executed {
exception: Some(exception),
gas: t.gas,
gas_used: t.gas,
gas: t.tx().gas,
gas_used: t.tx().gas,
refunded: U256::zero(),
cumulative_gas_used: self.info.gas_used + t.gas,
cumulative_gas_used: self.info.gas_used + t.tx().gas,
logs: vec![],
contracts_created: vec![],
output: output,
@@ -1519,7 +1554,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
} else {
Some(vm::Error::Reverted)
},
gas: t.gas,
gas: t.tx().gas,
gas_used: gas_used,
refunded: refunded,
cumulative_gas_used: self.info.gas_used + gas_used,
@@ -1551,7 +1586,7 @@ mod tests {
trace, ExecutiveTracer, ExecutiveVMTracer, FlatTrace, MemoryDiff, NoopTracer, NoopVMTracer,
StorageDiff, Tracer, VMExecutedOperation, VMOperation, VMTrace, VMTracer,
};
use types::transaction::{Action, Transaction};
use types::transaction::{Action, Transaction, TypedTransaction};
use vm::{ActionParams, ActionValue, CallType, CreateContractAddress, EnvInfo};
fn make_frontier_machine(max_depth: usize) -> EthereumMachine {
@@ -2445,14 +2480,14 @@ mod tests {
evm_test_ignore! {test_transact_simple: test_transact_simple_int}
fn test_transact_simple(factory: Factory) {
let keypair = Random.generate().unwrap();
let t = Transaction {
let t = TypedTransaction::Legacy(Transaction {
action: Action::Create,
value: U256::from(17),
data: "3331600055".from_hex().unwrap(),
gas: U256::from(100_000),
gas_price: U256::zero(),
nonce: U256::zero(),
}
})
.sign(keypair.secret(), None);
let sender = t.sender();
let contract = contract_address(
@@ -2496,14 +2531,14 @@ mod tests {
evm_test! {test_transact_invalid_nonce: test_transact_invalid_nonce_int}
fn test_transact_invalid_nonce(factory: Factory) {
let keypair = Random.generate().unwrap();
let t = Transaction {
let t = TypedTransaction::Legacy(Transaction {
action: Action::Create,
value: U256::from(17),
data: "3331600055".from_hex().unwrap(),
gas: U256::from(100_000),
gas_price: U256::zero(),
nonce: U256::one(),
}
})
.sign(keypair.secret(), None);
let sender = t.sender();
@@ -2535,14 +2570,14 @@ mod tests {
evm_test! {test_transact_gas_limit_reached: test_transact_gas_limit_reached_int}
fn test_transact_gas_limit_reached(factory: Factory) {
let keypair = Random.generate().unwrap();
let t = Transaction {
let t = TypedTransaction::Legacy(Transaction {
action: Action::Create,
value: U256::from(17),
data: "3331600055".from_hex().unwrap(),
gas: U256::from(80_001),
gas_price: U256::zero(),
nonce: U256::zero(),
}
})
.sign(keypair.secret(), None);
let sender = t.sender();
@@ -2580,14 +2615,14 @@ mod tests {
evm_test! {test_not_enough_cash: test_not_enough_cash_int}
fn test_not_enough_cash(factory: Factory) {
let keypair = Random.generate().unwrap();
let t = Transaction {
let t = TypedTransaction::Legacy(Transaction {
action: Action::Create,
value: U256::from(18),
data: "3331600055".from_hex().unwrap(),
gas: U256::from(100_000),
gas_price: U256::one(),
nonce: U256::zero(),
}
})
.sign(keypair.secret(), None);
let sender = t.sender();

View File

@@ -17,10 +17,12 @@
use super::test_common::*;
use client::EvmTestClient;
use ethjson;
use rlp::Rlp;
use std::path::Path;
use transaction_ext::Transaction;
use types::{header::Header, transaction::UnverifiedTransaction};
use types::{
header::Header,
transaction::{TypedTransaction, UnverifiedTransaction},
};
pub fn json_transaction_test<H: FnMut(&str, HookType)>(
path: &Path,
@@ -65,8 +67,7 @@ pub fn json_transaction_test<H: FnMut(&str, HookType)>(
};
let rlp: Vec<u8> = test.rlp.clone().into();
let res = Rlp::new(&rlp)
.as_val()
let res = TypedTransaction::decode(&rlp)
.map_err(::error::Error::from)
.and_then(|t: UnverifiedTransaction| {
let mut header: Header = Default::default();
@@ -74,12 +75,13 @@ pub fn json_transaction_test<H: FnMut(&str, HookType)>(
header.set_number(BLOCK_NUMBER);
let minimal = t
.tx()
.gas_required(&spec.engine.schedule(header.number()))
.into();
if t.gas < minimal {
if t.tx().gas < minimal {
return Err(::types::transaction::Error::InsufficientGas {
minimal,
got: t.gas,
got: t.tx().gas,
}
.into());
}

View File

@@ -23,11 +23,11 @@ use std::{
};
use ethereum_types::{Address, H256, U256};
use rlp::Rlp;
use types::{
header::Header,
transaction::{
self, SignedTransaction, UnverifiedTransaction, SYSTEM_ADDRESS, UNSIGNED_SENDER,
self, SignedTransaction, TypedTransaction, UnverifiedTransaction, SYSTEM_ADDRESS,
UNSIGNED_SENDER,
},
BlockNumber,
};
@@ -455,17 +455,27 @@ impl EthereumMachine {
pub fn decode_transaction(
&self,
transaction: &[u8],
schedule: &Schedule,
) -> Result<UnverifiedTransaction, transaction::Error> {
let rlp = Rlp::new(&transaction);
if rlp.as_raw().len() > self.params().max_transaction_size {
if transaction.len() > self.params().max_transaction_size {
debug!(
"Rejected oversized transaction of {} bytes",
rlp.as_raw().len()
transaction.len()
);
return Err(transaction::Error::TooBig);
}
rlp.as_val()
.map_err(|e| transaction::Error::InvalidRlp(e.to_string()))
let tx = TypedTransaction::decode(transaction)
.map_err(|e| transaction::Error::InvalidRlp(e.to_string()))?;
match tx.tx_type() {
transaction::TypedTxId::AccessList if schedule.eip2930 => {
return Err(transaction::Error::TransactionTypeNotEnabled)
}
_ => (),
};
Ok(tx)
}
}
@@ -476,7 +486,7 @@ pub struct AuxiliaryData<'a> {
/// The full block bytes, including the header.
pub bytes: Option<&'a [u8]>,
/// The block receipts.
pub receipts: Option<&'a [::types::receipt::Receipt]>,
pub receipts: Option<&'a [::types::receipt::TypedReceipt]>,
}
/// Type alias for a function we can make calls through synchronously.
@@ -550,7 +560,7 @@ mod tests {
fn should_disallow_unsigned_transactions() {
let rlp = "ea80843b9aca0083015f90948921ebb5f79e9e3920abe571004d0b1d5119c154865af3107a400080038080";
let transaction: UnverifiedTransaction =
::rlp::decode(&::rustc_hex::FromHex::from_hex(rlp).unwrap()).unwrap();
TypedTransaction::decode(&::rustc_hex::FromHex::from_hex(rlp).unwrap()).unwrap();
let spec = ::ethereum::new_ropsten_test();
let ethparams = get_default_ethash_extensions();

View File

@@ -1195,15 +1195,16 @@ impl miner::MinerService for Miner {
let receipt = &receipts[index];
RichReceipt {
from: tx.sender(),
to: match tx.action {
to: match tx.tx().action {
Action::Create => None,
Action::Call(ref address) => Some(*address),
},
transaction_hash: tx.hash(),
transaction_type: tx.tx_type(),
transaction_index: index,
cumulative_gas_used: receipt.gas_used,
gas_used: receipt.gas_used - prev_gas,
contract_address: match tx.action {
contract_address: match tx.tx().action {
Action::Call(_) => None,
Action::Create => {
let sender = tx.sender();
@@ -1212,8 +1213,8 @@ impl miner::MinerService for Miner {
self.engine
.create_address_scheme(pending.header.number()),
&sender,
&tx.nonce,
&tx.data,
&tx.tx().nonce,
&tx.tx().data,
)
.0,
)
@@ -1509,7 +1510,7 @@ mod tests {
use client::{ChainInfo, EachBlockWith, ImportSealedBlock, TestBlockChainClient};
use miner::{MinerService, PendingOrdering};
use test_helpers::{generate_dummy_client, generate_dummy_client_with_spec};
use types::transaction::Transaction;
use types::transaction::{Transaction, TypedTransaction};
#[test]
fn should_prepare_block_to_seal() {
@@ -1583,14 +1584,14 @@ mod tests {
fn transaction_with_chain_id(chain_id: u64) -> SignedTransaction {
let keypair = Random.generate().unwrap();
Transaction {
TypedTransaction::Legacy(Transaction {
action: Action::Create,
value: U256::zero(),
data: "3331600055".from_hex().unwrap(),
gas: U256::from(100_000),
gas_price: U256::zero(),
nonce: U256::zero(),
}
})
.sign(keypair.secret(), Some(chain_id))
}

View File

@@ -195,7 +195,8 @@ where
&self,
transaction: &[u8],
) -> Result<UnverifiedTransaction, transaction::Error> {
self.engine.decode_transaction(transaction)
let number = self.chain.best_block_header().number();
self.engine.decode_transaction(transaction, number)
}
}

View File

@@ -21,7 +21,7 @@ use ethereum_types::H256;
use hash::keccak;
use rlp::{DecoderError, Rlp, RlpStream};
use triehash::ordered_trie_root;
use types::{block::Block, header::Header, views::BlockView};
use types::{block::Block, header::Header, transaction::TypedTransaction, views::BlockView};
const HEADER_FIELDS: usize = 8;
const BLOCK_FIELDS: usize = 2;
@@ -62,9 +62,9 @@ impl AbridgedBlock {
.append(&header.extra_data());
// write block values.
stream
.append_list(&block_view.transactions())
.append_list(&block_view.uncles());
TypedTransaction::rlp_append_list(&mut stream, &block_view.transactions());
stream.append_list(&block_view.uncles());
// write seal fields.
for field in seal_fields {
@@ -97,10 +97,17 @@ impl AbridgedBlock {
header.set_timestamp(rlp.val_at(6)?);
header.set_extra_data(rlp.val_at(7)?);
let transactions = rlp.list_at(8)?;
let transactions = TypedTransaction::decode_rlp_list(&rlp.at(8)?)?;
let uncles: Vec<Header> = rlp.list_at(9)?;
header.set_transactions_root(ordered_trie_root(rlp.at(8)?.iter().map(|r| r.as_raw())));
header.set_transactions_root(ordered_trie_root(rlp.at(8)?.iter().map(|r| {
if r.is_list() {
r.as_raw()
} else {
// We already checked if list is valid with decode_rlp_list above
r.data().expect("To raw rlp list to be valid")
}
})));
header.set_receipts_root(receipts_root);
let mut uncles_rlp = RlpStream::new();
@@ -131,7 +138,7 @@ mod tests {
use ethereum_types::{Address, H256, U256};
use types::{
block::Block,
transaction::{Action, Transaction},
transaction::{Action, Transaction, TypedTransaction},
view,
views::BlockView,
};
@@ -165,24 +172,24 @@ mod tests {
fn with_transactions() {
let mut b = Block::default();
let t1 = Transaction {
let t1 = TypedTransaction::Legacy(Transaction {
action: Action::Create,
nonce: U256::from(42),
gas_price: U256::from(3000),
gas: U256::from(50_000),
value: U256::from(1),
data: b"Hello!".to_vec(),
}
})
.fake_sign(Address::from(0x69));
let t2 = Transaction {
let t2 = TypedTransaction::Legacy(Transaction {
action: Action::Create,
nonce: U256::from(88),
gas_price: U256::from(12345),
gas: U256::from(300000),
value: U256::from(1000000000),
data: "Eep!".into(),
}
})
.fake_sign(Address::from(0x55));
b.transactions.push(t1.into());
@@ -191,7 +198,7 @@ mod tests {
let receipts_root = b.header.receipts_root().clone();
b.header
.set_transactions_root(::triehash::ordered_trie_root(
b.transactions.iter().map(::rlp::encode),
b.transactions.iter().map(|tx| tx.encode()),
));
let encoded = encode_block(&b);

View File

@@ -36,7 +36,9 @@ use ethereum_types::{H256, U256};
use itertools::{Itertools, Position};
use kvdb::KeyValueDB;
use rlp::{Rlp, RlpStream};
use types::{encoded, header::Header, ids::BlockId, receipt::Receipt};
use types::{
encoded, header::Header, ids::BlockId, receipt::TypedReceipt, transaction::TypedTransaction,
};
/// Snapshot creation and restoration for PoA chains.
/// Chunk format:
@@ -114,9 +116,9 @@ impl SnapshotComponents for PoaSnapshot {
rlps.push({
let mut stream = RlpStream::new_list(5);
stream.append(&block.header);
TypedTransaction::rlp_append_list(&mut stream, &block.transactions);
stream
.append(&block.header)
.append_list(&block.transactions)
.append_list(&block.uncles)
.append(&receipts)
.append(&parent_td);
@@ -349,11 +351,11 @@ impl Rebuilder for ChunkRebuilder {
let last_rlp = rlp.at(num_items - 1)?;
let block = Block {
header: last_rlp.val_at(0)?,
transactions: last_rlp.list_at(1)?,
transactions: TypedTransaction::decode_rlp_list(&last_rlp.at(1)?)?,
uncles: last_rlp.list_at(2)?,
};
let block_data = block.rlp_bytes();
let receipts: Vec<Receipt> = last_rlp.list_at(3)?;
let receipts = TypedReceipt::decode_rlp_list(&last_rlp.at(3)?)?;
{
let hash = block.header.hash();

View File

@@ -291,8 +291,15 @@ impl Rebuilder for PowRebuilder {
let pair = rlp.at(idx)?;
let abridged_rlp = pair.at(0)?.as_raw().to_owned();
let abridged_block = AbridgedBlock::from_raw(abridged_rlp);
let receipts: Vec<::types::receipt::Receipt> = pair.list_at(1)?;
let receipts_root = ordered_trie_root(pair.at(1)?.iter().map(|r| r.as_raw()));
let receipts = ::types::receipt::TypedReceipt::decode_rlp_list(&pair.at(1)?)?;
let receipts_root = ordered_trie_root(pair.at(1)?.iter().map(|r| {
if r.is_list() {
r.as_raw()
} else {
// We have allready checked validity by decoding rlp list in line above
r.data().expect("Expect for raw receipts list to be valid.")
}
}));
let block = abridged_block.to_block(parent_hash, cur_number, receipts_root)?;
let block_bytes = encoded::Block::new(block.rlp_bytes());

View File

@@ -25,7 +25,7 @@ use snapshot::tests::helpers as snapshot_helpers;
use spec::Spec;
use tempdir::TempDir;
use test_helpers::generate_dummy_client_with_spec;
use types::transaction::{Action, SignedTransaction, Transaction};
use types::transaction::{Action, SignedTransaction, Transaction, TypedTransaction};
use ethereum_types::Address;
use test_helpers;
@@ -128,14 +128,14 @@ fn make_chain(
// and force sealing.
let make_useless_transactions = || {
let mut nonce = nonce.borrow_mut();
let transaction = Transaction {
let transaction = TypedTransaction::Legacy(Transaction {
nonce: *nonce,
gas_price: 1.into(),
gas: 21_000.into(),
action: Action::Call(Address::new()),
value: 1.into(),
data: Vec::new(),
}
})
.sign(&*RICH_SECRET, client.signing_chain_id());
*nonce = *nonce + 1;
@@ -171,14 +171,14 @@ fn make_chain(
let data =
test_validator_set::functions::set_validators::encode_input(new_set.clone());
let mut nonce = nonce.borrow_mut();
let transaction = Transaction {
let transaction = TypedTransaction::Legacy(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());
*nonce = *nonce + 1;

View File

@@ -301,7 +301,7 @@ fn recover_aborted_recovery() {
generate_dummy_client_with_spec_and_data(Spec::new_null, NUM_BLOCKS, 5, &gas_prices);
let spec = Spec::new_null();
let tempdir = TempDir::new("").unwrap();
let tempdir = TempDir::new("oe_snapshot").unwrap();
let db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS);
let client_db = new_db();
let client2 = Client::new(

View File

@@ -137,6 +137,8 @@ pub struct CommonParams {
pub eip2315_transition: BlockNumber,
/// Number of first block where EIP-2929 rules begin.
pub eip2929_transition: BlockNumber,
/// Number of first block where EIP-2930 rules begin.
pub eip2930_transition: BlockNumber,
/// Number of first block where dust cleanup rules (EIP-168 and EIP169) begin.
pub dust_protection_transition: BlockNumber,
/// Nonce cap increase per block. Nonce cap is only checked if dust protection is enabled.
@@ -212,6 +214,7 @@ impl CommonParams {
schedule.eip1706 = block_number >= self.eip1706_transition;
schedule.have_subs = block_number >= self.eip2315_transition;
schedule.eip2929 = block_number >= self.eip2929_transition;
schedule.eip2930 = block_number >= self.eip2930_transition;
if block_number >= self.eip1884_transition {
schedule.have_selfbalance = true;
@@ -370,6 +373,9 @@ impl From<ethjson::spec::Params> for CommonParams {
eip2929_transition: p
.eip2929_transition
.map_or_else(BlockNumber::max_value, Into::into),
eip2930_transition: p
.eip2930_transition
.map_or_else(BlockNumber::max_value, Into::into),
dust_protection_transition: p
.dust_protection_transition
.map_or_else(BlockNumber::max_value, Into::into),
@@ -956,7 +962,7 @@ impl Spec {
/// initialize genesis epoch data, using in-memory database for
/// constructor.
pub fn genesis_epoch_data(&self) -> Result<Vec<u8>, String> {
use types::transaction::{Action, Transaction};
use types::transaction::{Action, Transaction, TypedTransaction};
let genesis = self.genesis_header();
@@ -983,14 +989,14 @@ impl Spec {
};
let from = Address::default();
let tx = Transaction {
let tx = TypedTransaction::Legacy(Transaction {
nonce: self.engine.account_start_nonce(0),
action: Action::Call(a),
gas: U256::max_value(),
gas_price: U256::default(),
value: U256::default(),
data: d,
}
})
.fake_sign(from);
let res = ::state::prove_transaction_virtual(

View File

@@ -38,10 +38,11 @@ use state_db::StateDB;
use trace::{self, FlatTrace, VMTrace};
use types::{
basic_account::BasicAccount,
receipt::{Receipt, TransactionOutcome},
receipt::{LegacyReceipt, TransactionOutcome, TypedReceipt},
state_diff::StateDiff,
transaction::SignedTransaction,
};
use vm::EnvInfo;
use bytes::Bytes;
@@ -63,7 +64,7 @@ pub use self::{account::Account, backend::Backend, substate::Substate};
/// Used to return information about an `State::apply` operation.
pub struct ApplyOutcome<T, V> {
/// The receipt for the applied transaction.
pub receipt: Receipt,
pub receipt: TypedReceipt,
/// The output of the applied transaction.
pub output: Bytes,
/// The trace for the applied transaction, empty if tracing was not produced.
@@ -955,7 +956,10 @@ impl<B: Backend> State<B> {
};
let output = e.output;
let receipt = Receipt::new(outcome, e.cumulative_gas_used, e.logs);
let receipt = TypedReceipt::new(
t.tx_type(),
LegacyReceipt::new(outcome, e.cumulative_gas_used, e.logs),
);
trace!(target: "state", "Transaction receipt: {:?}", receipt);
Ok(ApplyOutcome {
@@ -1602,7 +1606,7 @@ mod tests {
info.gas_limit = 1_000_000.into();
let machine = make_frontier_machine(5);
let t = Transaction {
let t = TypedTransaction::Legacy(Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 100_000.into(),
@@ -1610,7 +1614,7 @@ mod tests {
value: 100.into(),
data: FromHex::from_hex("601080600c6000396000f3006000355415600957005b60203560003555")
.unwrap(),
}
})
.sign(&secret(), None);
state
@@ -1667,14 +1671,14 @@ mod tests {
info.gas_limit = 1_000_000.into();
let machine = make_frontier_machine(5);
let t = Transaction {
let t = TypedTransaction::Legacy(Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 100_000.into(),
action: Action::Create,
value: 100.into(),
data: FromHex::from_hex("5b600056").unwrap(),
}
})
.sign(&secret(), None);
state
@@ -1706,14 +1710,14 @@ mod tests {
info.gas_limit = 1_000_000.into();
let machine = make_frontier_machine(5);
let t = Transaction {
let t = TypedTransaction::Legacy(Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 100_000.into(),
action: Action::Call(0xa.into()),
value: 100.into(),
data: vec![],
}
})
.sign(&secret(), None);
state
@@ -1753,14 +1757,14 @@ mod tests {
info.gas_limit = 1_000_000.into();
let machine = make_frontier_machine(5);
let t = Transaction {
let t = TypedTransaction::Legacy(Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 100_000.into(),
action: Action::Call(0xa.into()),
value: 100.into(),
data: vec![],
}
})
.sign(&secret(), None);
state
@@ -1797,14 +1801,14 @@ mod tests {
info.gas_limit = 1_000_000.into();
let machine = Spec::new_test_machine();
let t = Transaction {
let t = TypedTransaction::Legacy(Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 100_000.into(),
action: Action::Call(0x1.into()),
value: 0.into(),
data: vec![],
}
})
.sign(&secret(), None);
let result = state.apply(&info, &machine, &t, true).unwrap();
@@ -1839,14 +1843,14 @@ mod tests {
info.gas_limit = 1_000_000.into();
let machine = Spec::new_test_machine();
let t = Transaction {
let t = TypedTransaction::Legacy(Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 100_000.into(),
action: Action::Call(0xa.into()),
value: 0.into(),
data: vec![],
}
})
.sign(&secret(), None);
state
@@ -1887,14 +1891,14 @@ mod tests {
info.gas_limit = 1_000_000.into();
let machine = Spec::new_test_machine();
let t = Transaction {
let t = TypedTransaction::Legacy(Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 100_000.into(),
action: Action::Call(0xa.into()),
value: 0.into(),
data: vec![],
}
})
.sign(&secret(), None);
state
@@ -1957,14 +1961,14 @@ mod tests {
info.number = 0x789b0;
let machine = Spec::new_test_machine();
let t = Transaction {
let t = TypedTransaction::Legacy(Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 100_000.into(),
action: Action::Call(0xa.into()),
value: 0.into(),
data: vec![],
}
})
.sign(&secret(), None);
state
@@ -2029,14 +2033,14 @@ mod tests {
info.gas_limit = 1_000_000.into();
let machine = make_frontier_machine(5);
let t = Transaction {
let t = TypedTransaction::Legacy(Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 100_000.into(),
action: Action::Call(0xa.into()),
value: 100.into(),
data: vec![],
}
})
.sign(&secret(), None);
state
@@ -2073,14 +2077,14 @@ mod tests {
info.gas_limit = 1_000_000.into();
let machine = make_frontier_machine(5);
let t = Transaction {
let t = TypedTransaction::Legacy(Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 100_000.into(),
action: Action::Call(0xa.into()),
value: 100.into(),
data: vec![],
}
})
.sign(&secret(), None);
state
@@ -2145,14 +2149,14 @@ mod tests {
info.gas_limit = 1_000_000.into();
let machine = make_frontier_machine(5);
let t = Transaction {
let t = TypedTransaction::Legacy(Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 100_000.into(),
action: Action::Call(0xa.into()),
value: 100.into(),
data: vec![],
}
})
.sign(&secret(), None);
state
@@ -2210,14 +2214,14 @@ mod tests {
info.gas_limit = 1_000_000.into();
let machine = make_frontier_machine(5);
let t = Transaction {
let t = TypedTransaction::Legacy(Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 100_000.into(),
action: Action::Call(0xa.into()),
value: 100.into(),
data: vec![],
}
})
.sign(&secret(), None);
state
@@ -2260,14 +2264,14 @@ mod tests {
info.gas_limit = 1_000_000.into();
let machine = make_frontier_machine(5);
let t = Transaction {
let t = TypedTransaction::Legacy(Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 100_000.into(),
action: Action::Call(0xa.into()),
value: 100.into(),
data: vec![], //600480600b6000396000f35b600056
}
})
.sign(&secret(), None);
state
@@ -2328,14 +2332,14 @@ mod tests {
info.gas_limit = 1_000_000.into();
let machine = make_frontier_machine(5);
let t = Transaction {
let t = TypedTransaction::Legacy(Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 100_000.into(),
action: Action::Call(0xa.into()),
value: 100.into(),
data: vec![],
}
})
.sign(&secret(), None);
state
@@ -2421,14 +2425,14 @@ mod tests {
info.gas_limit = 1_000_000.into();
let machine = make_frontier_machine(5);
let t = Transaction {
let t = TypedTransaction::Legacy(Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 100_000.into(),
action: Action::Call(0xa.into()),
value: 100.into(),
data: vec![], //600480600b6000396000f35b600056
}
})
.sign(&secret(), None);
state
@@ -2512,14 +2516,14 @@ mod tests {
info.gas_limit = 1_000_000.into();
let machine = make_frontier_machine(5);
let t = Transaction {
let t = TypedTransaction::Legacy(Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 100_000.into(),
action: Action::Call(0xa.into()),
value: 100.into(),
data: vec![],
}
})
.sign(&secret(), None);
state

View File

@@ -36,7 +36,7 @@ use tempdir::TempDir;
use types::{
encoded,
header::Header,
transaction::{Action, SignedTransaction, Transaction},
transaction::{Action, SignedTransaction, Transaction, TypedTransaction},
view,
views::BlockView,
};
@@ -104,7 +104,7 @@ pub fn create_test_block_with_data(
rlp.append(header);
rlp.begin_list(transactions.len());
for t in transactions {
rlp.append_raw(&rlp::encode(t), 1);
t.rlp_append(&mut rlp);
}
rlp.append_list(&uncles);
rlp.out()
@@ -197,14 +197,14 @@ where
// first block we don't have any balance, so can't send any transactions.
for _ in 0..txs_per_block {
b.push_transaction(
Transaction {
TypedTransaction::Legacy(Transaction {
nonce: n.into(),
gas_price: tx_gas_prices[n % tx_gas_prices.len()],
gas: 100000.into(),
action: Action::Create,
data: vec![],
value: U256::zero(),
}
})
.sign(kp.secret(), Some(test_spec.chain_id())),
None,
)

View File

@@ -45,7 +45,7 @@ use types::{
data_format::DataFormat,
filter::Filter,
ids::BlockId,
transaction::{Action, Condition, PendingTransaction, Transaction},
transaction::{Action, Condition, PendingTransaction, Transaction, TypedTransaction},
view,
views::BlockView,
};
@@ -362,26 +362,26 @@ fn does_not_propagate_delayed_transactions() {
let key = KeyPair::from_secret(keccak("test").into()).unwrap();
let secret = key.secret();
let tx0 = PendingTransaction::new(
Transaction {
TypedTransaction::Legacy(Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 21000.into(),
action: Action::Call(Address::default()),
value: 0.into(),
data: Vec::new(),
}
})
.sign(secret, None),
Some(Condition::Number(2)),
);
let tx1 = PendingTransaction::new(
Transaction {
TypedTransaction::Legacy(Transaction {
nonce: 1.into(),
gas_price: 0.into(),
gas: 21000.into(),
action: Action::Call(Address::default()),
value: 0.into(),
data: Vec::new(),
}
})
.sign(secret, None),
None,
);
@@ -443,14 +443,14 @@ fn transaction_proof() {
client.import_sealed_block(b).unwrap(); // account change is in the journal overlay
}
let transaction = Transaction {
let transaction = TypedTransaction::Legacy(Transaction {
nonce: 0.into(),
gas_price: 0.into(),
gas: 21000.into(),
action: Action::Call(Address::default()),
value: 5.into(),
data: Vec::new(),
}
})
.fake_sign(address);
let proof = client

View File

@@ -29,7 +29,7 @@ use test_helpers::{self, get_temp_state_db};
use trace::{trace::Action::Reward, LocalizedTrace, RewardType};
use types::{
header::Header,
transaction::{Action, Transaction},
transaction::{Action, Transaction, TypedTransaction},
view,
views::BlockView,
};
@@ -171,14 +171,14 @@ fn can_trace_block_and_uncle_reward() {
for _ in 0..1 {
block
.push_transaction(
Transaction {
TypedTransaction::Legacy(Transaction {
nonce: n.into(),
gas_price: 10000.into(),
gas: 100000.into(),
action: Action::Create,
data: vec![],
value: U256::zero(),
}
})
.sign(kp.secret(), Some(spec.network_id())),
None,
)

View File

@@ -83,7 +83,7 @@ impl TransactionFilter {
let mut permission_cache = self.permission_cache.lock();
let mut contract_version_cache = self.contract_version_cache.lock();
let (tx_type, to) = match transaction.action {
let (tx_type, to) = match transaction.tx().action {
Action::Create => (tx_permissions::CREATE, Address::new()),
Action::Call(address) => {
if client
@@ -98,7 +98,7 @@ impl TransactionFilter {
};
let sender = transaction.sender();
let value = transaction.value;
let value = transaction.tx().value;
let key = (*parent_hash, sender);
if let Some(permissions) = permission_cache.get_mut(&key) {
@@ -181,7 +181,7 @@ mod test {
use std::sync::Arc;
use tempdir::TempDir;
use test_helpers;
use types::transaction::{Action, Transaction};
use types::transaction::{Action, Transaction, TypedTransaction};
/// Contract code: https://gist.github.com/VladLupashevskyi/84f18eabb1e4afadf572cf92af3e7e7f
#[test]
@@ -230,28 +230,30 @@ mod test {
.unwrap();
let filter = TransactionFilter::from_params(spec.params()).unwrap();
let mut basic_tx = Transaction::default();
basic_tx.action = Action::Call(Address::from("d41c057fd1c78805aac12b0a94a405c0461a6fbb"));
let create_tx = Transaction::default();
let mut call_tx = Transaction::default();
call_tx.action = Action::Call(Address::from("0000000000000000000000000000000000000005"));
let mut basic_tx_with_ether_and_to_key7 = Transaction::default();
basic_tx_with_ether_and_to_key7.action =
let mut basic_tx = TypedTransaction::Legacy(Transaction::default());
basic_tx.tx_mut().action =
Action::Call(Address::from("d41c057fd1c78805aac12b0a94a405c0461a6fbb"));
basic_tx_with_ether_and_to_key7.value = U256::from(123123);
let mut call_tx_with_ether = Transaction::default();
call_tx_with_ether.action =
let create_tx = TypedTransaction::Legacy(Transaction::default());
let mut call_tx = TypedTransaction::Legacy(Transaction::default());
call_tx.tx_mut().action =
Action::Call(Address::from("0000000000000000000000000000000000000005"));
call_tx_with_ether.value = U256::from(123123);
let mut basic_tx_to_key6 = Transaction::default();
basic_tx_to_key6.action =
let mut basic_tx_with_ether_and_to_key7 = TypedTransaction::Legacy(Transaction::default());
basic_tx_with_ether_and_to_key7.tx_mut().action =
Action::Call(Address::from("d41c057fd1c78805aac12b0a94a405c0461a6fbb"));
basic_tx_with_ether_and_to_key7.tx_mut().value = U256::from(123123);
let mut call_tx_with_ether = TypedTransaction::Legacy(Transaction::default());
call_tx_with_ether.tx_mut().action =
Action::Call(Address::from("0000000000000000000000000000000000000005"));
call_tx_with_ether.tx_mut().value = U256::from(123123);
let mut basic_tx_to_key6 = TypedTransaction::Legacy(Transaction::default());
basic_tx_to_key6.tx_mut().action =
Action::Call(Address::from("e57bfe9f44b819898f47bf37e5af72a0783e1141"));
let mut basic_tx_with_ether_and_to_key6 = Transaction::default();
basic_tx_with_ether_and_to_key6.action =
let mut basic_tx_with_ether_and_to_key6 = TypedTransaction::Legacy(Transaction::default());
basic_tx_with_ether_and_to_key6.tx_mut().action =
Action::Call(Address::from("e57bfe9f44b819898f47bf37e5af72a0783e1141"));
basic_tx_with_ether_and_to_key6.value = U256::from(123123);
basic_tx_with_ether_and_to_key6.tx_mut().value = U256::from(123123);
let genesis = client.block_hash(BlockId::Latest).unwrap();
let block_number = 1;
@@ -444,11 +446,13 @@ mod test {
.unwrap();
let filter = TransactionFilter::from_params(spec.params()).unwrap();
let mut basic_tx = Transaction::default();
basic_tx.action = Action::Call(Address::from("000000000000000000000000000000000000032"));
let create_tx = Transaction::default();
let mut call_tx = Transaction::default();
call_tx.action = Action::Call(Address::from("0000000000000000000000000000000000000005"));
let mut basic_tx = TypedTransaction::Legacy(Transaction::default());
basic_tx.tx_mut().action =
Action::Call(Address::from("000000000000000000000000000000000000032"));
let create_tx = TypedTransaction::Legacy(Transaction::default());
let mut call_tx = TypedTransaction::Legacy(Transaction::default());
call_tx.tx_mut().action =
Action::Call(Address::from("0000000000000000000000000000000000000005"));
let genesis = client.block_hash(BlockId::Latest).unwrap();
let block_number = 1;

View File

@@ -80,7 +80,10 @@ pub mod blocks {
use engines::EthEngine;
use error::{BlockError, Error, ErrorKind};
use types::{header::Header, transaction::UnverifiedTransaction};
use types::{
header::Header,
transaction::{TypedTransaction, UnverifiedTransaction},
};
use verification::{verify_block_basic, verify_block_unordered, PreverifiedBlock};
use bytes::Bytes;
@@ -151,7 +154,7 @@ pub mod blocks {
let (header, transactions, uncles) = {
let rlp = Rlp::new(&bytes);
let header = rlp.val_at(0)?;
let transactions = rlp.list_at(1)?;
let transactions = TypedTransaction::decode_rlp_list(&rlp.at(1)?)?;
let uncles = rlp.list_at(2)?;
(header, transactions, uncles)
};

View File

@@ -133,7 +133,7 @@ pub fn verify_block_unordered(
let t = engine.verify_transaction_unordered(t, &header)?;
// t_nb 5.3.2 check if nonce is more then max nonce (EIP-168 and EIP169)
if let Some(max_nonce) = nonce_cap {
if t.nonce >= max_nonce {
if t.tx().nonce >= max_nonce {
return Err(BlockError::TooManyTransactions(t.sender()).into());
}
}
@@ -493,7 +493,16 @@ fn verify_parent(header: &Header, parent: &Header, engine: &dyn EthEngine) -> Re
fn verify_block_integrity(block: &Unverified) -> Result<(), Error> {
let block_rlp = Rlp::new(&block.bytes);
let tx = block_rlp.at(1)?;
let expected_root = ordered_trie_root(tx.iter().map(|r| r.as_raw()));
let expected_root = ordered_trie_root(tx.iter().map(|r| {
if r.is_list() {
r.as_raw()
} else {
// This is already checked in Unverified structure and that is why we are okay to asume that data is valid.
r.data().expect(
"Unverified block should already check if raw list of transactions is valid",
)
}
}));
if &expected_root != block.header.transactions_root() {
bail!(BlockError::InvalidTransactionsRoot(Mismatch {
expected: expected_root,
@@ -531,7 +540,7 @@ mod tests {
use types::{
encoded,
log_entry::{LocalizedLogEntry, LogEntry},
transaction::{Action, SignedTransaction, Transaction, UnverifiedTransaction},
transaction::{Action, SignedTransaction, Transaction, TypedTransaction},
};
fn check_ok(result: Result<(), Error>) {
@@ -764,34 +773,34 @@ mod tests {
let keypair = Random.generate().unwrap();
let tr1 = Transaction {
let tr1 = TypedTransaction::Legacy(Transaction {
action: Action::Create,
value: U256::from(0),
data: Bytes::new(),
gas: U256::from(30_000),
gas_price: U256::from(40_000),
nonce: U256::one(),
}
})
.sign(keypair.secret(), None);
let tr2 = Transaction {
let tr2 = TypedTransaction::Legacy(Transaction {
action: Action::Create,
value: U256::from(0),
data: Bytes::new(),
gas: U256::from(30_000),
gas_price: U256::from(40_000),
nonce: U256::from(2),
}
})
.sign(keypair.secret(), None);
let tr3 = Transaction {
let tr3 = TypedTransaction::Legacy(Transaction {
action: Action::Call(0x0.into()),
value: U256::from(0),
data: Bytes::new(),
gas: U256::from(30_000),
gas_price: U256::from(0),
nonce: U256::zero(),
}
})
.null_sign(0);
let good_transactions = [tr1.clone(), tr2.clone()];
@@ -834,16 +843,10 @@ mod tests {
let mut uncles_rlp = RlpStream::new();
uncles_rlp.append_list(&good_uncles);
let good_uncles_hash = keccak(uncles_rlp.as_raw());
let good_transactions_root = ordered_trie_root(
good_transactions
.iter()
.map(|t| ::rlp::encode::<UnverifiedTransaction>(t)),
);
let eip86_transactions_root = ordered_trie_root(
eip86_transactions
.iter()
.map(|t| ::rlp::encode::<UnverifiedTransaction>(t)),
);
let good_transactions_root =
ordered_trie_root(good_transactions.iter().map(|t| t.encode()));
let eip86_transactions_root =
ordered_trie_root(eip86_transactions.iter().map(|t| t.encode()));
let mut parent = good.clone();
parent.set_number(9);
@@ -1114,14 +1117,14 @@ mod tests {
let keypair = Random.generate().unwrap();
let bad_transactions: Vec<_> = (0..3)
.map(|i| {
Transaction {
TypedTransaction::Legacy(Transaction {
action: Action::Create,
value: U256::zero(),
data: Vec::new(),
gas: 0.into(),
gas_price: U256::zero(),
nonce: i.into(),
}
})
.sign(keypair.secret(), None)
})
.collect();