TypedTransaction (EIP-2718) and Optional access list (EIP-2930) (#135)
This commit is contained in:
parent
3f01b69084
commit
ea3efd926e
14
Cargo.lock
generated
14
Cargo.lock
generated
@ -447,6 +447,9 @@ dependencies = [
|
||||
"rlp 0.3.0",
|
||||
"rlp_derive",
|
||||
"rustc-hex 1.0.0",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"unexpected",
|
||||
]
|
||||
|
||||
@ -4274,6 +4277,17 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_repr"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dc6b7951b17b051f3210b063f12cc17320e2fe30ae05b0fe2a3abb068551c76"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.20",
|
||||
"quote 1.0.7",
|
||||
"syn 1.0.40",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.8.1"
|
||||
|
@ -34,7 +34,7 @@ use common_types::{
|
||||
},
|
||||
header::{ExtendedHeader, Header},
|
||||
log_entry::{LocalizedLogEntry, LogEntry},
|
||||
receipt::Receipt,
|
||||
receipt::TypedReceipt,
|
||||
transaction::LocalizedTransaction,
|
||||
tree_route::TreeRoute,
|
||||
view,
|
||||
@ -460,13 +460,13 @@ impl BlockProvider for BlockChain {
|
||||
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 mut log_index = receipts.iter().fold(0, |sum, receipt| sum + receipt.receipt().logs.len());
|
||||
|
||||
let receipts_len = receipts.len();
|
||||
hashes.reverse();
|
||||
receipts.reverse();
|
||||
receipts.into_iter()
|
||||
.map(|receipt| receipt.logs)
|
||||
.map(|receipt| receipt.receipt().logs.clone())
|
||||
.zip(hashes)
|
||||
.enumerate()
|
||||
.flat_map(move |(index, (mut logs, tx_hash))| {
|
||||
@ -895,7 +895,7 @@ impl BlockChain {
|
||||
&self,
|
||||
batch: &mut DBTransaction,
|
||||
block: encoded::Block,
|
||||
receipts: Vec<Receipt>,
|
||||
receipts: Vec<TypedReceipt>,
|
||||
parent_td: Option<U256>,
|
||||
is_best: bool,
|
||||
is_ancient: bool,
|
||||
@ -1265,7 +1265,7 @@ impl BlockChain {
|
||||
&self,
|
||||
batch: &mut DBTransaction,
|
||||
block: encoded::Block,
|
||||
receipts: Vec<Receipt>,
|
||||
receipts: Vec<TypedReceipt>,
|
||||
extras: ExtrasInsert,
|
||||
) -> ImportRoute {
|
||||
let parent_hash = block.header_view().parent_hash();
|
||||
@ -1283,7 +1283,7 @@ impl BlockChain {
|
||||
&self,
|
||||
batch: &mut DBTransaction,
|
||||
block: encoded::Block,
|
||||
receipts: Vec<Receipt>,
|
||||
receipts: Vec<TypedReceipt>,
|
||||
route: TreeRoute,
|
||||
extras: ExtrasInsert,
|
||||
) -> ImportRoute {
|
||||
@ -1659,7 +1659,7 @@ impl BlockChain {
|
||||
/// This function returns modified block receipts.
|
||||
fn prepare_block_receipts_update(
|
||||
&self,
|
||||
receipts: Vec<Receipt>,
|
||||
receipts: Vec<TypedReceipt>,
|
||||
info: &BlockInfo,
|
||||
) -> HashMap<H256, BlockReceipts> {
|
||||
let mut block_receipts = HashMap::new();
|
||||
@ -1921,8 +1921,8 @@ mod tests {
|
||||
|
||||
use crate::generator::{BlockBuilder, BlockGenerator, BlockOptions};
|
||||
use common_types::{
|
||||
receipt::{Receipt, TransactionOutcome},
|
||||
transaction::{Action, Transaction},
|
||||
receipt::{LegacyReceipt, TransactionOutcome, TypedReceipt},
|
||||
transaction::{Action, Transaction, TypedTransaction},
|
||||
};
|
||||
use ethkey::Secret;
|
||||
use keccak_hash::keccak;
|
||||
@ -1975,7 +1975,7 @@ mod tests {
|
||||
db: &Arc<dyn BlockChainDB>,
|
||||
bc: &BlockChain,
|
||||
block: encoded::Block,
|
||||
receipts: Vec<Receipt>,
|
||||
receipts: Vec<TypedReceipt>,
|
||||
) -> ImportRoute {
|
||||
insert_block_commit(db, bc, block, receipts, true)
|
||||
}
|
||||
@ -1984,7 +1984,7 @@ mod tests {
|
||||
db: &Arc<dyn BlockChainDB>,
|
||||
bc: &BlockChain,
|
||||
block: encoded::Block,
|
||||
receipts: Vec<Receipt>,
|
||||
receipts: Vec<TypedReceipt>,
|
||||
commit: bool,
|
||||
) -> ImportRoute {
|
||||
let mut batch = db.key_value().transaction();
|
||||
@ -2000,7 +2000,7 @@ mod tests {
|
||||
batch: &mut DBTransaction,
|
||||
bc: &BlockChain,
|
||||
block: encoded::Block,
|
||||
receipts: Vec<Receipt>,
|
||||
receipts: Vec<TypedReceipt>,
|
||||
) -> ImportRoute {
|
||||
let fork_choice = {
|
||||
let header = block.header_view();
|
||||
@ -2157,7 +2157,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_fork_transaction_addresses() {
|
||||
let t1 = Transaction {
|
||||
let t1 = TypedTransaction::Legacy(Transaction {
|
||||
nonce: 0.into(),
|
||||
gas_price: 0.into(),
|
||||
gas: 100_000.into(),
|
||||
@ -2166,7 +2166,7 @@ mod tests {
|
||||
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
}
|
||||
})
|
||||
.sign(&secret(), None);
|
||||
|
||||
let t1_hash = t1.hash();
|
||||
@ -2211,7 +2211,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_overwriting_transaction_addresses() {
|
||||
let t1 = Transaction {
|
||||
let t1 = TypedTransaction::Legacy(Transaction {
|
||||
nonce: 0.into(),
|
||||
gas_price: 0.into(),
|
||||
gas: 100_000.into(),
|
||||
@ -2220,10 +2220,10 @@ mod tests {
|
||||
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
}
|
||||
})
|
||||
.sign(&secret(), None);
|
||||
|
||||
let t2 = Transaction {
|
||||
let t2 = TypedTransaction::Legacy(Transaction {
|
||||
nonce: 1.into(),
|
||||
gas_price: 0.into(),
|
||||
gas: 100_000.into(),
|
||||
@ -2232,10 +2232,10 @@ mod tests {
|
||||
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
}
|
||||
})
|
||||
.sign(&secret(), None);
|
||||
|
||||
let t3 = Transaction {
|
||||
let t3 = TypedTransaction::Legacy(Transaction {
|
||||
nonce: 2.into(),
|
||||
gas_price: 0.into(),
|
||||
gas: 100_000.into(),
|
||||
@ -2244,7 +2244,7 @@ mod tests {
|
||||
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
}
|
||||
})
|
||||
.sign(&secret(), None);
|
||||
|
||||
let genesis = BlockBuilder::genesis();
|
||||
@ -2509,7 +2509,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_logs() {
|
||||
let t1 = Transaction {
|
||||
let t1 = TypedTransaction::Legacy(Transaction {
|
||||
nonce: 0.into(),
|
||||
gas_price: 0.into(),
|
||||
gas: 100_000.into(),
|
||||
@ -2518,9 +2518,9 @@ mod tests {
|
||||
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
}
|
||||
})
|
||||
.sign(&secret(), None);
|
||||
let t2 = Transaction {
|
||||
let t2 = TypedTransaction::Legacy(Transaction {
|
||||
nonce: 0.into(),
|
||||
gas_price: 0.into(),
|
||||
gas: 100_000.into(),
|
||||
@ -2529,9 +2529,9 @@ mod tests {
|
||||
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
}
|
||||
})
|
||||
.sign(&secret(), None);
|
||||
let t3 = Transaction {
|
||||
let t3 = TypedTransaction::Legacy(Transaction {
|
||||
nonce: 0.into(),
|
||||
gas_price: 0.into(),
|
||||
gas: 100_000.into(),
|
||||
@ -2540,9 +2540,9 @@ mod tests {
|
||||
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
}
|
||||
})
|
||||
.sign(&secret(), None);
|
||||
let t4 = Transaction {
|
||||
let t4 = TypedTransaction::Legacy(Transaction {
|
||||
nonce: 0.into(),
|
||||
gas_price: 0.into(),
|
||||
gas: 100_000.into(),
|
||||
@ -2551,7 +2551,7 @@ mod tests {
|
||||
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
||||
.from_hex()
|
||||
.unwrap(),
|
||||
}
|
||||
})
|
||||
.sign(&secret(), None);
|
||||
let tx_hash1 = t1.hash();
|
||||
let tx_hash2 = t2.hash();
|
||||
@ -2580,7 +2580,7 @@ mod tests {
|
||||
&bc,
|
||||
b1.last().encoded(),
|
||||
vec![
|
||||
Receipt {
|
||||
TypedReceipt::Legacy(LegacyReceipt {
|
||||
outcome: TransactionOutcome::StateRoot(H256::default()),
|
||||
gas_used: 10_000.into(),
|
||||
log_bloom: Default::default(),
|
||||
@ -2596,8 +2596,8 @@ mod tests {
|
||||
data: vec![2],
|
||||
},
|
||||
],
|
||||
},
|
||||
Receipt {
|
||||
}),
|
||||
TypedReceipt::Legacy(LegacyReceipt {
|
||||
outcome: TransactionOutcome::StateRoot(H256::default()),
|
||||
gas_used: 10_000.into(),
|
||||
log_bloom: Default::default(),
|
||||
@ -2606,14 +2606,14 @@ mod tests {
|
||||
topics: vec![],
|
||||
data: vec![3],
|
||||
}],
|
||||
},
|
||||
}),
|
||||
],
|
||||
);
|
||||
insert_block(
|
||||
&db,
|
||||
&bc,
|
||||
b2.last().encoded(),
|
||||
vec![Receipt {
|
||||
vec![TypedReceipt::Legacy(LegacyReceipt {
|
||||
outcome: TransactionOutcome::StateRoot(H256::default()),
|
||||
gas_used: 10_000.into(),
|
||||
log_bloom: Default::default(),
|
||||
@ -2622,13 +2622,13 @@ mod tests {
|
||||
topics: vec![],
|
||||
data: vec![4],
|
||||
}],
|
||||
}],
|
||||
})],
|
||||
);
|
||||
insert_block(
|
||||
&db,
|
||||
&bc,
|
||||
b3.last().encoded(),
|
||||
vec![Receipt {
|
||||
vec![TypedReceipt::Legacy(LegacyReceipt {
|
||||
outcome: TransactionOutcome::StateRoot(H256::default()),
|
||||
gas_used: 10_000.into(),
|
||||
log_bloom: Default::default(),
|
||||
@ -2637,7 +2637,7 @@ mod tests {
|
||||
topics: vec![],
|
||||
data: vec![5],
|
||||
}],
|
||||
}],
|
||||
})],
|
||||
);
|
||||
|
||||
// when
|
||||
|
@ -22,17 +22,16 @@ use std::collections::VecDeque;
|
||||
use common_types::{
|
||||
encoded,
|
||||
header::Header,
|
||||
transaction::{Action, SignedTransaction, Transaction},
|
||||
transaction::{Action, SignedTransaction, Transaction, TypedTransaction},
|
||||
view,
|
||||
views::BlockView,
|
||||
};
|
||||
use keccak_hash::keccak;
|
||||
use rlp::encode;
|
||||
use rlp_derive::RlpEncodable;
|
||||
use rlp::{encode, RlpStream};
|
||||
use triehash_ethereum::ordered_trie_root;
|
||||
|
||||
/// Helper structure, used for encoding blocks.
|
||||
#[derive(Default, Clone, RlpEncodable)]
|
||||
#[derive(Default, Clone)]
|
||||
pub struct Block {
|
||||
/// Block header
|
||||
pub header: Header,
|
||||
@ -42,6 +41,15 @@ pub struct Block {
|
||||
pub uncles: Vec<Header>,
|
||||
}
|
||||
|
||||
impl rlp::Encodable for Block {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(3);
|
||||
s.append(&self.header);
|
||||
SignedTransaction::rlp_append_list(s, &self.transactions);
|
||||
s.append_list(&self.uncles);
|
||||
}
|
||||
}
|
||||
|
||||
impl Block {
|
||||
/// Get a copy of the header
|
||||
#[inline]
|
||||
@ -154,14 +162,14 @@ impl BlockBuilder {
|
||||
let data = std::iter::repeat_with(|| rand::random::<u8>())
|
||||
.take(data_len as usize)
|
||||
.collect::<Vec<_>>();
|
||||
Transaction {
|
||||
TypedTransaction::Legacy(Transaction {
|
||||
nonce: 0.into(),
|
||||
gas_price: 0.into(),
|
||||
gas: 100_000.into(),
|
||||
action: Action::Create,
|
||||
value: 100.into(),
|
||||
data,
|
||||
}
|
||||
})
|
||||
.sign(&keccak("").into(), None)
|
||||
})
|
||||
.take(count);
|
||||
@ -205,7 +213,7 @@ impl BlockBuilder {
|
||||
let metadata = get_metadata();
|
||||
let block_number = parent_number + 1;
|
||||
let transactions = metadata.transactions;
|
||||
let transactions_root = ordered_trie_root(transactions.iter().map(rlp::encode));
|
||||
let transactions_root = ordered_trie_root(transactions.iter().map(|tx| tx.encode()));
|
||||
|
||||
block.header.set_parent_hash(parent_hash);
|
||||
block.header.set_number(block_number);
|
||||
|
@ -18,12 +18,14 @@
|
||||
|
||||
use std::{io::Write, ops};
|
||||
|
||||
use common_types::{engines::epoch::Transition as EpochTransition, receipt::Receipt, BlockNumber};
|
||||
use common_types::{
|
||||
engines::epoch::Transition as EpochTransition, receipt::TypedReceipt, BlockNumber,
|
||||
};
|
||||
use ethereum_types::{H256, H264, U256};
|
||||
use heapsize::HeapSizeOf;
|
||||
use kvdb::PREFIX_LEN as DB_PREFIX_LEN;
|
||||
use rlp;
|
||||
use rlp_derive::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper};
|
||||
use rlp_derive::{RlpDecodable, RlpEncodable};
|
||||
|
||||
use crate::db::Key;
|
||||
|
||||
@ -235,15 +237,27 @@ impl HeapSizeOf for TransactionAddress {
|
||||
}
|
||||
|
||||
/// Contains all block receipts.
|
||||
#[derive(Clone, RlpEncodableWrapper, RlpDecodableWrapper)]
|
||||
#[derive(Clone)]
|
||||
pub struct BlockReceipts {
|
||||
/// Block receipts
|
||||
pub receipts: Vec<Receipt>,
|
||||
pub receipts: Vec<TypedReceipt>,
|
||||
}
|
||||
|
||||
impl rlp::Encodable for BlockReceipts {
|
||||
fn rlp_append(&self, s: &mut rlp::RlpStream) {
|
||||
TypedReceipt::rlp_append_list(s, &self.receipts);
|
||||
}
|
||||
}
|
||||
|
||||
impl rlp::Decodable for BlockReceipts {
|
||||
fn decode(rlp: &rlp::Rlp) -> Result<Self, rlp::DecoderError> {
|
||||
Ok(BlockReceipts::new(TypedReceipt::decode_rlp_list(rlp)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockReceipts {
|
||||
/// Create new block receipts wrapper.
|
||||
pub fn new(receipts: Vec<Receipt>) -> Self {
|
||||
pub fn new(receipts: Vec<TypedReceipt>) -> Self {
|
||||
BlockReceipts { receipts: receipts }
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,8 @@
|
||||
"eip1884Transition": "0x0",
|
||||
"eip2028Transition": "0x0",
|
||||
"eip2315Transition": "0x0",
|
||||
"eip2929Transition": "0x0"
|
||||
"eip2929Transition": "0x0",
|
||||
"eip2930Transition": "0x0"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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(
|
||||
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);
|
||||
}
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -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(
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
};
|
||||
|
@ -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();
|
||||
|
@ -762,7 +762,7 @@ mod tests {
|
||||
use triehash_ethereum::ordered_trie_root;
|
||||
use types::{
|
||||
header::Header as BlockHeader,
|
||||
transaction::{SignedTransaction, Transaction},
|
||||
transaction::{SignedTransaction, Transaction, TypedTransaction},
|
||||
};
|
||||
|
||||
fn dummy_header(number: u64, parent_hash: H256) -> BlockHeader {
|
||||
@ -778,7 +778,7 @@ mod tests {
|
||||
|
||||
fn dummy_signed_tx() -> SignedTransaction {
|
||||
let keypair = Random.generate().unwrap();
|
||||
Transaction::default().sign(keypair.secret(), None)
|
||||
TypedTransaction::Legacy(Transaction::default()).sign(keypair.secret(), None)
|
||||
}
|
||||
|
||||
fn import_headers(
|
||||
@ -949,8 +949,16 @@ mod tests {
|
||||
::rlp::EMPTY_LIST_RLP.to_vec()
|
||||
};
|
||||
|
||||
let txs = encode_list(&[dummy_signed_tx()]);
|
||||
let tx_root = ordered_trie_root(Rlp::new(&txs).iter().map(|r| r.as_raw()));
|
||||
let mut rlp_strem = RlpStream::new();
|
||||
SignedTransaction::rlp_append_list(&mut rlp_strem, &[dummy_signed_tx()]);
|
||||
let txs = rlp_strem.drain();
|
||||
let tx_root = ordered_trie_root(Rlp::new(&txs).iter().map(|r| {
|
||||
if r.is_list() {
|
||||
r.as_raw()
|
||||
} else {
|
||||
r.data().expect("It is expected that raw rlp list is valid")
|
||||
}
|
||||
}));
|
||||
|
||||
let mut rlp = RlpStream::new_list(2);
|
||||
rlp.append_raw(&txs, 1);
|
||||
@ -1019,14 +1027,20 @@ mod tests {
|
||||
// Construct the receipts. Receipt root for the first two blocks is the same.
|
||||
//
|
||||
// The RLP-encoded integers are clearly not receipts, but the BlockDownloader treats
|
||||
// all receipts as byte blobs, so it does not matter.
|
||||
// all receipts as byte blobs, so it does not matter. It is just important that they are
|
||||
// represended as list (0xc1) so that they passes as legacy list
|
||||
let receipts_rlp = if i < 2 {
|
||||
encode_list(&[0u32])
|
||||
vec![0xC1, 0]
|
||||
} else {
|
||||
encode_list(&[i as u32])
|
||||
vec![0xC1, i as u8]
|
||||
};
|
||||
let receipts_root =
|
||||
ordered_trie_root(Rlp::new(&receipts_rlp).iter().map(|r| r.as_raw()));
|
||||
let receipts_root = ordered_trie_root(Rlp::new(&receipts_rlp).iter().map(|r| {
|
||||
if r.is_list() {
|
||||
r.as_raw()
|
||||
} else {
|
||||
r.data().expect("expect proper test data")
|
||||
}
|
||||
}));
|
||||
receipts.push(receipts_rlp);
|
||||
|
||||
// Construct the block header.
|
||||
|
@ -23,7 +23,10 @@ use network;
|
||||
use rlp::{DecoderError, Rlp, RlpStream};
|
||||
use std::collections::{hash_map, BTreeMap, HashMap, HashSet};
|
||||
use triehash_ethereum::ordered_trie_root;
|
||||
use types::{header::Header as BlockHeader, transaction::UnverifiedTransaction};
|
||||
use types::{
|
||||
header::Header as BlockHeader,
|
||||
transaction::{TypedTransaction, UnverifiedTransaction},
|
||||
};
|
||||
|
||||
known_heap_size!(0, HeaderId);
|
||||
|
||||
@ -65,7 +68,7 @@ impl SyncBody {
|
||||
|
||||
let result = SyncBody {
|
||||
transactions_bytes: transactions_rlp.as_raw().to_vec(),
|
||||
transactions: transactions_rlp.as_list()?,
|
||||
transactions: TypedTransaction::decode_rlp_list(&transactions_rlp)?,
|
||||
uncles_bytes: uncles_rlp.as_raw().to_vec(),
|
||||
uncles: uncles_rlp.as_list()?,
|
||||
};
|
||||
@ -454,11 +457,14 @@ impl BlockCollection {
|
||||
|
||||
fn insert_body(&mut self, body: SyncBody) -> Result<H256, network::Error> {
|
||||
let header_id = {
|
||||
let tx_root = ordered_trie_root(
|
||||
Rlp::new(&body.transactions_bytes)
|
||||
.iter()
|
||||
.map(|r| r.as_raw()),
|
||||
);
|
||||
let tx_root = ordered_trie_root(Rlp::new(&body.transactions_bytes).iter().map(|r| {
|
||||
if r.is_list() {
|
||||
r.as_raw()
|
||||
} else {
|
||||
// this list is already decoded and passed validation, for this we are okay to expect proper data
|
||||
r.data().expect("Expect raw transaction list to be valid")
|
||||
}
|
||||
}));
|
||||
let uncles = keccak(&body.uncles_bytes);
|
||||
HeaderId {
|
||||
transactions_root: tx_root,
|
||||
@ -491,7 +497,22 @@ impl BlockCollection {
|
||||
fn insert_receipt(&mut self, r: Bytes) -> Result<Vec<H256>, network::Error> {
|
||||
let receipt_root = {
|
||||
let receipts = Rlp::new(&r);
|
||||
ordered_trie_root(receipts.iter().map(|r| r.as_raw()))
|
||||
//check receipts data before calculating trie root
|
||||
let mut temp_receipts: Vec<&[u8]> = Vec::new();
|
||||
for receipt_byte in receipts.iter() {
|
||||
if receipt_byte.is_list() {
|
||||
temp_receipts.push(receipt_byte.as_raw())
|
||||
} else {
|
||||
temp_receipts.push(
|
||||
receipt_byte
|
||||
.data()
|
||||
.map_err(|e| network::ErrorKind::Rlp(e))?,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// calculate trie root and use it as hash
|
||||
ordered_trie_root(temp_receipts.iter())
|
||||
};
|
||||
self.downloading_receipts.remove(&receipt_root);
|
||||
match self.receipt_ids.entry(receipt_root) {
|
||||
|
@ -837,9 +837,12 @@ impl SyncHandler {
|
||||
let item_count = r.item_count()?;
|
||||
trace!(target: "sync", "{:02} -> Transactions ({} entries)", peer_id, item_count);
|
||||
let mut transactions = Vec::with_capacity(item_count);
|
||||
for i in 0..item_count {
|
||||
let rlp = r.at(i)?;
|
||||
let tx = rlp.as_raw().to_vec();
|
||||
for i in r.iter() {
|
||||
let tx = if i.is_list() {
|
||||
i.as_raw().to_vec() // legacy transaction. just add it raw
|
||||
} else {
|
||||
i.data()?.to_vec() // typed transaction. remove header from start and send only payload.
|
||||
};
|
||||
transactions.push(tx);
|
||||
}
|
||||
io.chain().queue_transactions(transactions, peer_id);
|
||||
|
@ -21,7 +21,7 @@ use ethereum_types::H256;
|
||||
use fastmap::H256FastSet;
|
||||
use network::{client_version::ClientCapabilities, PeerId};
|
||||
use rand::Rng;
|
||||
use rlp::{Encodable, RlpStream};
|
||||
use rlp::RlpStream;
|
||||
use sync_io::SyncIo;
|
||||
use types::{blockchain_info::BlockChainInfo, transaction::SignedTransaction, BlockNumber};
|
||||
|
||||
@ -121,7 +121,7 @@ impl SyncPropagator {
|
||||
let (transactions, service_transactions): (Vec<_>, Vec<_>) = transactions
|
||||
.iter()
|
||||
.map(|tx| tx.signed())
|
||||
.partition(|tx| !tx.gas_price.is_zero());
|
||||
.partition(|tx| !tx.tx().gas_price.is_zero());
|
||||
|
||||
// usual transactions could be propagated to all peers
|
||||
let mut affected_peers = HashSet::new();
|
||||
@ -171,7 +171,7 @@ impl SyncPropagator {
|
||||
let all_transactions_rlp = {
|
||||
let mut packet = RlpStream::new_list(transactions.len());
|
||||
for tx in &transactions {
|
||||
packet.append(&**tx);
|
||||
tx.rlp_append(&mut packet);
|
||||
}
|
||||
packet.out()
|
||||
};
|
||||
@ -238,13 +238,8 @@ impl SyncPropagator {
|
||||
for tx in &transactions {
|
||||
let hash = tx.hash();
|
||||
if to_send.contains(&hash) {
|
||||
let mut transaction = RlpStream::new();
|
||||
tx.rlp_append(&mut transaction);
|
||||
let appended = packet.append_raw_checked(
|
||||
&transaction.drain(),
|
||||
1,
|
||||
MAX_TRANSACTION_PACKET_SIZE,
|
||||
);
|
||||
let appended =
|
||||
packet.append_raw_checked(&tx.encode(), 1, MAX_TRANSACTION_PACKET_SIZE);
|
||||
if !appended {
|
||||
// Maximal packet size reached just proceed with sending
|
||||
debug!(target: "sync", "Transaction packet size limit reached. Sending incomplete set of {}/{} transactions.", pushed, to_send.len());
|
||||
@ -373,6 +368,7 @@ mod tests {
|
||||
use rlp::Rlp;
|
||||
use std::collections::VecDeque;
|
||||
use tests::{helpers::TestIo, snapshot::TestSnapshotService};
|
||||
use types::transaction::TypedTransaction;
|
||||
|
||||
use super::{
|
||||
super::{tests::*, *},
|
||||
@ -707,7 +703,9 @@ mod tests {
|
||||
return None;
|
||||
}
|
||||
|
||||
rlp.at(0).ok().and_then(|r| r.as_val().ok())
|
||||
rlp.at(0)
|
||||
.ok()
|
||||
.and_then(|r| TypedTransaction::decode_rlp(&r).ok())
|
||||
})
|
||||
.collect();
|
||||
assert_eq!(sent_transactions.len(), 2);
|
||||
|
@ -26,18 +26,18 @@ use ethkey::{KeyPair, Secret};
|
||||
use hash::keccak;
|
||||
use io::{IoChannel, IoHandler};
|
||||
use std::sync::Arc;
|
||||
use types::transaction::{Action, PendingTransaction, Transaction};
|
||||
use types::transaction::{Action, PendingTransaction, Transaction, TypedTransaction};
|
||||
use SyncConfig;
|
||||
|
||||
fn new_tx(secret: &Secret, nonce: U256, chain_id: u64) -> PendingTransaction {
|
||||
let signed = Transaction {
|
||||
let signed = TypedTransaction::Legacy(Transaction {
|
||||
nonce: nonce.into(),
|
||||
gas_price: 0.into(),
|
||||
gas: 21000.into(),
|
||||
action: Action::Call(Address::default()),
|
||||
value: 0.into(),
|
||||
data: Vec::new(),
|
||||
}
|
||||
})
|
||||
.sign(secret, Some(chain_id));
|
||||
PendingTransaction::new(signed, None)
|
||||
}
|
||||
|
@ -14,6 +14,9 @@ parity-bytes = "0.1"
|
||||
rlp = { version = "0.3.0", features = ["ethereum"] }
|
||||
rlp_derive = { path = "../../util/rlp-derive" }
|
||||
unexpected = { path = "../../util/unexpected" }
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
serde_repr = "0.1"
|
||||
|
||||
[dev-dependencies]
|
||||
rustc-hex = "1.0"
|
||||
|
@ -35,7 +35,7 @@ use bytes::Bytes;
|
||||
|
||||
use header::Header;
|
||||
use rlp::{Decodable, DecoderError, Rlp, RlpStream};
|
||||
use transaction::UnverifiedTransaction;
|
||||
use transaction::{TypedTransaction, UnverifiedTransaction};
|
||||
|
||||
/// A block, encoded as it is on the block chain.
|
||||
#[derive(Default, Debug, Clone, PartialEq)]
|
||||
@ -53,7 +53,7 @@ impl Block {
|
||||
pub fn rlp_bytes(&self) -> Bytes {
|
||||
let mut block_rlp = RlpStream::new_list(3);
|
||||
block_rlp.append(&self.header);
|
||||
block_rlp.append_list(&self.transactions);
|
||||
TypedTransaction::rlp_append_list(&mut block_rlp, &self.transactions);
|
||||
block_rlp.append_list(&self.uncles);
|
||||
block_rlp.out()
|
||||
}
|
||||
@ -69,7 +69,7 @@ impl Decodable for Block {
|
||||
}
|
||||
Ok(Block {
|
||||
header: rlp.val_at(0)?,
|
||||
transactions: rlp.list_at(1)?,
|
||||
transactions: TypedTransaction::decode_rlp_list(&rlp.at(1)?)?,
|
||||
uncles: rlp.list_at(2)?,
|
||||
})
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ extern crate heapsize;
|
||||
extern crate keccak_hash as hash;
|
||||
extern crate parity_bytes as bytes;
|
||||
extern crate rlp;
|
||||
extern crate serde_repr;
|
||||
extern crate unexpected;
|
||||
|
||||
#[macro_use]
|
||||
|
@ -16,9 +16,14 @@
|
||||
|
||||
//! Receipt
|
||||
|
||||
use super::transaction::TypedTxId;
|
||||
use ethereum_types::{Address, Bloom, H160, H256, U256};
|
||||
use heapsize::HeapSizeOf;
|
||||
use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream};
|
||||
use rlp::{DecoderError, Rlp, RlpStream};
|
||||
use std::{
|
||||
convert::TryInto,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
use log_entry::{LocalizedLogEntry, LogEntry};
|
||||
use BlockNumber;
|
||||
@ -36,7 +41,7 @@ pub enum TransactionOutcome {
|
||||
|
||||
/// Information describing execution of a transaction.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Receipt {
|
||||
pub struct LegacyReceipt {
|
||||
/// The total gas used in the block following execution of the transaction.
|
||||
pub gas_used: U256,
|
||||
/// The OR-wide combination of all logs' blooms for this transaction.
|
||||
@ -47,10 +52,9 @@ pub struct Receipt {
|
||||
pub outcome: TransactionOutcome,
|
||||
}
|
||||
|
||||
impl Receipt {
|
||||
/// Create a new receipt.
|
||||
impl LegacyReceipt {
|
||||
pub fn new(outcome: TransactionOutcome, gas_used: U256, logs: Vec<LogEntry>) -> Self {
|
||||
Self {
|
||||
LegacyReceipt {
|
||||
gas_used,
|
||||
log_bloom: logs.iter().fold(Bloom::default(), |mut b, l| {
|
||||
b.accrue_bloom(&l.bloom());
|
||||
@ -60,10 +64,32 @@ impl Receipt {
|
||||
outcome,
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
||||
match rlp.item_count()? {
|
||||
3 => Ok(LegacyReceipt {
|
||||
outcome: TransactionOutcome::Unknown,
|
||||
gas_used: rlp.val_at(0)?,
|
||||
log_bloom: rlp.val_at(1)?,
|
||||
logs: rlp.list_at(2)?,
|
||||
}),
|
||||
4 => Ok(LegacyReceipt {
|
||||
gas_used: rlp.val_at(1)?,
|
||||
log_bloom: rlp.val_at(2)?,
|
||||
logs: rlp.list_at(3)?,
|
||||
outcome: {
|
||||
let first = rlp.at(0)?;
|
||||
if first.is_data() && first.data()?.len() <= 1 {
|
||||
TransactionOutcome::StatusCode(first.as_val()?)
|
||||
} else {
|
||||
TransactionOutcome::StateRoot(first.as_val()?)
|
||||
}
|
||||
},
|
||||
}),
|
||||
_ => Err(DecoderError::RlpIncorrectListLen),
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for Receipt {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
pub fn rlp_append(&self, s: &mut RlpStream) {
|
||||
match self.outcome {
|
||||
TransactionOutcome::Unknown => {
|
||||
s.begin_list(3);
|
||||
@ -83,42 +109,142 @@ impl Encodable for Receipt {
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for Receipt {
|
||||
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
||||
if rlp.item_count()? == 3 {
|
||||
Ok(Receipt {
|
||||
outcome: TransactionOutcome::Unknown,
|
||||
gas_used: rlp.val_at(0)?,
|
||||
log_bloom: rlp.val_at(1)?,
|
||||
logs: rlp.list_at(2)?,
|
||||
})
|
||||
} else {
|
||||
Ok(Receipt {
|
||||
gas_used: rlp.val_at(1)?,
|
||||
log_bloom: rlp.val_at(2)?,
|
||||
logs: rlp.list_at(3)?,
|
||||
outcome: {
|
||||
let first = rlp.at(0)?;
|
||||
if first.is_data() && first.data()?.len() <= 1 {
|
||||
TransactionOutcome::StatusCode(first.as_val()?)
|
||||
} else {
|
||||
TransactionOutcome::StateRoot(first.as_val()?)
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum TypedReceipt {
|
||||
Legacy(LegacyReceipt),
|
||||
AccessList(LegacyReceipt),
|
||||
}
|
||||
|
||||
impl TypedReceipt {
|
||||
/// Create a new receipt.
|
||||
pub fn new(type_id: TypedTxId, legacy_receipt: LegacyReceipt) -> Self {
|
||||
//curently we are using same receipt for both legacy and typed transaction
|
||||
match type_id {
|
||||
TypedTxId::AccessList => Self::AccessList(legacy_receipt),
|
||||
TypedTxId::Legacy => Self::Legacy(legacy_receipt),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tx_type(&self) -> TypedTxId {
|
||||
match self {
|
||||
Self::Legacy(_) => TypedTxId::Legacy,
|
||||
Self::AccessList(_) => TypedTxId::AccessList,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receipt(&self) -> &LegacyReceipt {
|
||||
match self {
|
||||
Self::Legacy(receipt) => receipt,
|
||||
Self::AccessList(receipt) => receipt,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receipt_mut(&mut self) -> &mut LegacyReceipt {
|
||||
match self {
|
||||
Self::Legacy(receipt) => receipt,
|
||||
Self::AccessList(receipt) => receipt,
|
||||
}
|
||||
}
|
||||
|
||||
fn decode(tx: &[u8]) -> Result<Self, DecoderError> {
|
||||
if tx.is_empty() {
|
||||
// at least one byte needs to be present
|
||||
return Err(DecoderError::RlpIncorrectListLen);
|
||||
}
|
||||
let id = tx[0].try_into();
|
||||
if id.is_err() {
|
||||
return Err(DecoderError::Custom("Unknown transaction"));
|
||||
}
|
||||
//other transaction types
|
||||
match id.unwrap() {
|
||||
TypedTxId::AccessList => {
|
||||
let rlp = Rlp::new(&tx[1..]);
|
||||
Ok(Self::AccessList(LegacyReceipt::decode(&rlp)?))
|
||||
}
|
||||
TypedTxId::Legacy => Ok(Self::Legacy(LegacyReceipt::decode(&Rlp::new(tx))?)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode_rlp(rlp: &Rlp) -> Result<Self, DecoderError> {
|
||||
if rlp.is_list() {
|
||||
//legacy transaction wrapped around RLP encoding
|
||||
Ok(Self::Legacy(LegacyReceipt::decode(rlp)?))
|
||||
} else {
|
||||
Self::decode(rlp.data()?)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode_rlp_list(rlp: &Rlp) -> Result<Vec<Self>, DecoderError> {
|
||||
if !rlp.is_list() {
|
||||
// at least one byte needs to be present
|
||||
return Err(DecoderError::RlpIncorrectListLen);
|
||||
}
|
||||
let mut output = Vec::with_capacity(rlp.item_count()?);
|
||||
for tx in rlp.iter() {
|
||||
output.push(Self::decode_rlp(&tx)?);
|
||||
}
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
pub fn rlp_append(&self, s: &mut RlpStream) {
|
||||
match self {
|
||||
Self::Legacy(receipt) => receipt.rlp_append(s),
|
||||
Self::AccessList(receipt) => {
|
||||
let mut rlps = RlpStream::new();
|
||||
receipt.rlp_append(&mut rlps);
|
||||
s.append(&[&[TypedTxId::AccessList as u8], rlps.as_raw()].concat());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rlp_append_list(s: &mut RlpStream, list: &[TypedReceipt]) {
|
||||
s.begin_list(list.len());
|
||||
for rec in list.iter() {
|
||||
rec.rlp_append(s)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn encode(&self) -> Vec<u8> {
|
||||
match self {
|
||||
Self::Legacy(receipt) => {
|
||||
let mut s = RlpStream::new();
|
||||
receipt.rlp_append(&mut s);
|
||||
s.drain()
|
||||
}
|
||||
Self::AccessList(receipt) => {
|
||||
let mut rlps = RlpStream::new();
|
||||
receipt.rlp_append(&mut rlps);
|
||||
[&[TypedTxId::AccessList as u8], rlps.as_raw()].concat()
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HeapSizeOf for Receipt {
|
||||
impl Deref for TypedReceipt {
|
||||
type Target = LegacyReceipt;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.receipt()
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for TypedReceipt {
|
||||
fn deref_mut(&mut self) -> &mut LegacyReceipt {
|
||||
self.receipt_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl HeapSizeOf for TypedReceipt {
|
||||
fn heap_size_of_children(&self) -> usize {
|
||||
self.logs.heap_size_of_children()
|
||||
self.receipt().logs.heap_size_of_children()
|
||||
}
|
||||
}
|
||||
|
||||
/// Receipt with additional info.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct RichReceipt {
|
||||
/// Transaction type
|
||||
pub transaction_type: TypedTxId,
|
||||
/// Transaction hash.
|
||||
pub transaction_hash: H256,
|
||||
/// Transaction index.
|
||||
@ -146,6 +272,8 @@ pub struct RichReceipt {
|
||||
/// Receipt with additional info.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct LocalizedReceipt {
|
||||
/// Transaction type
|
||||
pub transaction_type: TypedTxId,
|
||||
/// Transaction hash.
|
||||
pub transaction_hash: H256,
|
||||
/// Transaction index.
|
||||
@ -176,13 +304,15 @@ pub struct LocalizedReceipt {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{Receipt, TransactionOutcome};
|
||||
use super::{LegacyReceipt, TransactionOutcome, TypedReceipt, TypedTxId};
|
||||
use log_entry::LogEntry;
|
||||
|
||||
#[test]
|
||||
fn test_no_state_root() {
|
||||
let expected = ::rustc_hex::FromHex::from_hex("f9014183040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||
let r = Receipt::new(
|
||||
let r = TypedReceipt::new(
|
||||
TypedTxId::Legacy,
|
||||
LegacyReceipt::new(
|
||||
TransactionOutcome::Unknown,
|
||||
0x40cae.into(),
|
||||
vec![LogEntry {
|
||||
@ -190,14 +320,17 @@ mod tests {
|
||||
topics: vec![],
|
||||
data: vec![0u8; 32],
|
||||
}],
|
||||
),
|
||||
);
|
||||
assert_eq!(&::rlp::encode(&r)[..], &expected[..]);
|
||||
assert_eq!(r.encode(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_basic() {
|
||||
fn test_basic_legacy() {
|
||||
let expected = ::rustc_hex::FromHex::from_hex("f90162a02f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee83040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||
let r = Receipt::new(
|
||||
let r = TypedReceipt::new(
|
||||
TypedTxId::Legacy,
|
||||
LegacyReceipt::new(
|
||||
TransactionOutcome::StateRoot(
|
||||
"2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee".into(),
|
||||
),
|
||||
@ -207,17 +340,43 @@ mod tests {
|
||||
topics: vec![],
|
||||
data: vec![0u8; 32],
|
||||
}],
|
||||
),
|
||||
);
|
||||
let encoded = ::rlp::encode(&r);
|
||||
assert_eq!(&encoded[..], &expected[..]);
|
||||
let decoded: Receipt = ::rlp::decode(&encoded).expect("decoding receipt failed");
|
||||
let encoded = r.encode();
|
||||
assert_eq!(encoded, expected);
|
||||
let decoded = TypedReceipt::decode(&encoded).expect("decoding receipt failed");
|
||||
assert_eq!(decoded, r);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_basic_access_list() {
|
||||
let expected = ::rustc_hex::FromHex::from_hex("01f90162a02f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee83040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||
let r = TypedReceipt::new(
|
||||
TypedTxId::AccessList,
|
||||
LegacyReceipt::new(
|
||||
TransactionOutcome::StateRoot(
|
||||
"2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee".into(),
|
||||
),
|
||||
0x40cae.into(),
|
||||
vec![LogEntry {
|
||||
address: "dcf421d093428b096ca501a7cd1a740855a7976f".into(),
|
||||
topics: vec![],
|
||||
data: vec![0u8; 32],
|
||||
}],
|
||||
),
|
||||
);
|
||||
let encoded = r.encode();
|
||||
assert_eq!(&encoded, &expected);
|
||||
let decoded = TypedReceipt::decode(&encoded).expect("decoding receipt failed");
|
||||
assert_eq!(decoded, r);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_status_code() {
|
||||
let expected = ::rustc_hex::FromHex::from_hex("f901428083040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||
let r = Receipt::new(
|
||||
let r = TypedReceipt::new(
|
||||
TypedTxId::Legacy,
|
||||
LegacyReceipt::new(
|
||||
TransactionOutcome::StatusCode(0),
|
||||
0x40cae.into(),
|
||||
vec![LogEntry {
|
||||
@ -225,10 +384,11 @@ mod tests {
|
||||
topics: vec![],
|
||||
data: vec![0u8; 32],
|
||||
}],
|
||||
),
|
||||
);
|
||||
let encoded = ::rlp::encode(&r);
|
||||
let encoded = r.encode();
|
||||
assert_eq!(&encoded[..], &expected[..]);
|
||||
let decoded: Receipt = ::rlp::decode(&encoded).expect("decoding receipt failed");
|
||||
let decoded = TypedReceipt::decode(&encoded).expect("decoding receipt failed");
|
||||
assert_eq!(decoded, r);
|
||||
}
|
||||
}
|
||||
|
@ -84,6 +84,8 @@ pub enum Error {
|
||||
TooBig,
|
||||
/// Invalid RLP encoding
|
||||
InvalidRlp(String),
|
||||
/// Transaciton is still not enabled.
|
||||
TransactionTypeNotEnabled,
|
||||
}
|
||||
|
||||
impl From<ethkey::Error> for Error {
|
||||
@ -133,6 +135,9 @@ impl fmt::Display for Error {
|
||||
}
|
||||
TooBig => "Transaction too big".into(),
|
||||
InvalidRlp(ref err) => format!("Transaction has invalid RLP structure: {}.", err),
|
||||
TransactionTypeNotEnabled => {
|
||||
format!("Transaction type is not enabled for current block")
|
||||
}
|
||||
};
|
||||
|
||||
f.write_fmt(format_args!("Transaction error ({})", msg))
|
||||
|
@ -18,5 +18,6 @@
|
||||
|
||||
mod error;
|
||||
mod transaction;
|
||||
mod transaction_id;
|
||||
|
||||
pub use self::{error::Error, transaction::*};
|
||||
pub use self::{error::Error, transaction::*, transaction_id::*};
|
||||
|
File diff suppressed because it is too large
Load Diff
45
ethcore/types/src/transaction/transaction_id.rs
Normal file
45
ethcore/types/src/transaction/transaction_id.rs
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright 2020-2020 Parity Technologies (UK) Ltd.
|
||||
// This file is part of OpenEthereum.
|
||||
|
||||
// OpenEthereum is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// OpenEthereum is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Transaction Id.
|
||||
|
||||
use serde_repr::*;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
#[derive(Serialize_repr, Eq, Hash, Deserialize_repr, Debug, Clone, PartialEq)]
|
||||
#[repr(u8)]
|
||||
pub enum TypedTxId {
|
||||
AccessList = 0x01,
|
||||
Legacy = 0x80, // With 0x80 we are sure that all other types will not overlap
|
||||
}
|
||||
|
||||
impl Default for TypedTxId {
|
||||
fn default() -> TypedTxId {
|
||||
TypedTxId::Legacy
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for TypedTxId {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(v: u8) -> Result<Self, Self::Error> {
|
||||
match v {
|
||||
x if x == TypedTxId::AccessList as u8 => Ok(TypedTxId::AccessList),
|
||||
x if (x & 0x80) != 0x00 => Ok(TypedTxId::Legacy),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
@ -21,7 +21,7 @@ use bytes::Bytes;
|
||||
use ethereum_types::H256;
|
||||
use hash::keccak;
|
||||
use header::Header;
|
||||
use transaction::{LocalizedTransaction, UnverifiedTransaction};
|
||||
use transaction::{LocalizedTransaction, TypedTransaction, UnverifiedTransaction};
|
||||
use views::{HeaderView, TransactionView};
|
||||
|
||||
/// View onto block rlp.
|
||||
@ -77,7 +77,12 @@ impl<'a> BlockView<'a> {
|
||||
|
||||
/// Return List of transactions in given block.
|
||||
pub fn transactions(&self) -> Vec<UnverifiedTransaction> {
|
||||
self.rlp.list_at(1)
|
||||
TypedTransaction::decode_rlp_list(&self.rlp.at(1).rlp).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"block transactions, view rlp is trusted and should be valid: {:?}",
|
||||
e
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Return List of transactions with additional localization info.
|
||||
@ -126,10 +131,14 @@ impl<'a> BlockView<'a> {
|
||||
|
||||
/// Returns transaction at given index without deserializing unnecessary data.
|
||||
pub fn transaction_at(&self, index: usize) -> Option<UnverifiedTransaction> {
|
||||
self.transactions_rlp()
|
||||
.iter()
|
||||
.nth(index)
|
||||
.map(|rlp| rlp.as_val())
|
||||
self.transactions_rlp().iter().nth(index).map(|rlp| {
|
||||
TypedTransaction::decode_rlp(&rlp.rlp).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"block transaction_at, view rlp is trusted and should be valid.{:?}",
|
||||
e
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns localized transaction at given index.
|
||||
|
@ -21,7 +21,7 @@ use bytes::Bytes;
|
||||
use ethereum_types::H256;
|
||||
use hash::keccak;
|
||||
use header::Header;
|
||||
use transaction::{LocalizedTransaction, UnverifiedTransaction};
|
||||
use transaction::{LocalizedTransaction, TypedTransaction, UnverifiedTransaction};
|
||||
use views::{HeaderView, TransactionView};
|
||||
use BlockNumber;
|
||||
|
||||
@ -58,7 +58,12 @@ impl<'a> BodyView<'a> {
|
||||
|
||||
/// Return List of transactions in given block.
|
||||
pub fn transactions(&self) -> Vec<UnverifiedTransaction> {
|
||||
self.rlp.list_at(0)
|
||||
TypedTransaction::decode_rlp_list(&self.rlp.at(0).rlp).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"body transactions, view rlp is trusted and should be valid: {:?}",
|
||||
e
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Return List of transactions with additional localization info.
|
||||
@ -107,10 +112,14 @@ impl<'a> BodyView<'a> {
|
||||
|
||||
/// Returns transaction at given index without deserializing unnecessary data.
|
||||
pub fn transaction_at(&self, index: usize) -> Option<UnverifiedTransaction> {
|
||||
self.transactions_rlp()
|
||||
.iter()
|
||||
.nth(index)
|
||||
.map(|rlp| rlp.as_val())
|
||||
self.transactions_rlp().iter().nth(index).map(|rlp| {
|
||||
TypedTransaction::decode_rlp(&rlp.rlp).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"body transaction_a, view rlp is trusted and should be valid: {:?}",
|
||||
e
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns localized transaction at given index.
|
||||
|
@ -213,7 +213,7 @@ mod tests {
|
||||
access_list.insert_address(Address::from(1));
|
||||
access_list.insert_storage_key(Address::from(2), H256::from(3));
|
||||
|
||||
let mut access_list_call = access_list.clone();
|
||||
let access_list_call = access_list.clone();
|
||||
assert_eq!(true, access_list_call.contains_address(&Address::from(1)));
|
||||
assert_eq!(
|
||||
true,
|
||||
|
@ -24,6 +24,10 @@ pub const EIP2929_COLD_ACCOUNT_ACCESS_COST: usize = 2600;
|
||||
pub const EIP2929_WARM_STORAGE_READ_COST: usize = 100;
|
||||
// Gas per sstore reset
|
||||
pub const EIP2929_SSTORE_RESET_GAS: usize = 5000 - EIP2929_COLD_SLOAD_COST;
|
||||
/// Gas per received storage key
|
||||
pub const EIP2930_ACCESS_LIST_STORAGE_KEY_COST: usize = 1900;
|
||||
/// Gas per received address
|
||||
pub const EIP2930_ACCESS_LIST_ADDRESS_COST: usize = 2400;
|
||||
|
||||
/// Definition of the cost schedule and other parameterisations for the EVM.
|
||||
#[derive(Debug)]
|
||||
@ -149,6 +153,8 @@ pub struct Schedule {
|
||||
pub wasm: Option<WasmCosts>,
|
||||
/// Enable EIP-2929 rules
|
||||
pub eip2929: bool,
|
||||
/// Enable EIP-2930 rules for optional access list transactions. it depends on EIP-2929
|
||||
pub eip2930: bool,
|
||||
}
|
||||
|
||||
/// Wasm cost table
|
||||
@ -295,6 +301,7 @@ impl Schedule {
|
||||
keep_unsigned_nonce: false,
|
||||
wasm: None,
|
||||
eip2929: false,
|
||||
eip2930: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -343,6 +350,7 @@ impl Schedule {
|
||||
|
||||
schedule.eip1283 = true;
|
||||
schedule.eip2929 = true;
|
||||
schedule.eip2930 = true;
|
||||
|
||||
schedule.cold_sload_cost = EIP2929_COLD_SLOAD_COST;
|
||||
schedule.cold_account_access_cost = EIP2929_COLD_ACCOUNT_ACCESS_COST;
|
||||
@ -421,6 +429,7 @@ impl Schedule {
|
||||
keep_unsigned_nonce: false,
|
||||
wasm: None,
|
||||
eip2929: false,
|
||||
eip2930: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,7 +141,7 @@ pub fn run_transaction<T: Informant>(
|
||||
let result = run(
|
||||
&spec,
|
||||
trie_spec,
|
||||
transaction.gas,
|
||||
transaction.tx().gas,
|
||||
pre_state,
|
||||
|mut client| {
|
||||
let result = client.transact(env_info, transaction, trace::NoopTracer, informant);
|
||||
|
@ -108,6 +108,8 @@ pub struct Params {
|
||||
/// See `CommonParams` docs.
|
||||
pub eip2929_transition: Option<Uint>,
|
||||
/// See `CommonParams` docs.
|
||||
pub eip2930_transition: Option<Uint>,
|
||||
/// See `CommonParams` docs.
|
||||
pub dust_protection_transition: Option<Uint>,
|
||||
/// See `CommonParams` docs.
|
||||
pub nonce_cap_increment: Option<Uint>,
|
||||
|
@ -20,9 +20,9 @@ use std::{fmt, sync::Arc, time::Duration};
|
||||
|
||||
use io::IoHandler;
|
||||
use kvdb::KeyValueDB;
|
||||
use rlp::Rlp;
|
||||
use types::transaction::{
|
||||
Condition as TransactionCondition, PendingTransaction, SignedTransaction, UnverifiedTransaction,
|
||||
Condition as TransactionCondition, PendingTransaction, SignedTransaction, TypedTransaction,
|
||||
UnverifiedTransaction,
|
||||
};
|
||||
|
||||
extern crate common_types as types;
|
||||
@ -98,7 +98,7 @@ struct TransactionEntry {
|
||||
|
||||
impl TransactionEntry {
|
||||
fn into_pending(self) -> Option<PendingTransaction> {
|
||||
let tx: UnverifiedTransaction = match Rlp::new(&self.rlp_bytes).as_val() {
|
||||
let tx: UnverifiedTransaction = match TypedTransaction::decode(&self.rlp_bytes) {
|
||||
Err(e) => {
|
||||
warn!(target: "local_store", "Invalid persistent transaction stored: {}", e);
|
||||
return None;
|
||||
@ -120,7 +120,7 @@ impl TransactionEntry {
|
||||
impl From<PendingTransaction> for TransactionEntry {
|
||||
fn from(pending: PendingTransaction) -> Self {
|
||||
TransactionEntry {
|
||||
rlp_bytes: ::rlp::encode(&pending.transaction),
|
||||
rlp_bytes: pending.transaction.encode(),
|
||||
condition: pending.condition.map(Into::into),
|
||||
}
|
||||
}
|
||||
@ -239,7 +239,7 @@ mod tests {
|
||||
|
||||
use ethkey::{Brain, Generator};
|
||||
use std::sync::Arc;
|
||||
use types::transaction::{Condition, PendingTransaction, Transaction};
|
||||
use types::transaction::{Condition, PendingTransaction, Transaction, TypedTransaction};
|
||||
|
||||
// we want to test: round-trip of good transactions.
|
||||
// failure to roundtrip bad transactions (but that it doesn't panic)
|
||||
@ -271,8 +271,8 @@ mod tests {
|
||||
let keypair = Brain::new("abcd".into()).generate().unwrap();
|
||||
let transactions: Vec<_> = (0..10u64)
|
||||
.map(|nonce| {
|
||||
let mut tx = Transaction::default();
|
||||
tx.nonce = nonce.into();
|
||||
let mut tx = TypedTransaction::Legacy(Transaction::default());
|
||||
tx.tx_mut().nonce = nonce.into();
|
||||
|
||||
let signed = tx.sign(keypair.secret(), None);
|
||||
let condition = match nonce {
|
||||
@ -308,8 +308,8 @@ mod tests {
|
||||
let keypair = Brain::new("abcd".into()).generate().unwrap();
|
||||
let mut transactions: Vec<_> = (0..10u64)
|
||||
.map(|nonce| {
|
||||
let mut tx = Transaction::default();
|
||||
tx.nonce = nonce.into();
|
||||
let mut tx = TypedTransaction::Legacy(Transaction::default());
|
||||
tx.tx_mut().nonce = nonce.into();
|
||||
|
||||
let signed = tx.sign(keypair.secret(), None);
|
||||
|
||||
@ -318,8 +318,8 @@ mod tests {
|
||||
.collect();
|
||||
|
||||
transactions.push({
|
||||
let mut tx = Transaction::default();
|
||||
tx.nonce = 10.into();
|
||||
let mut tx = TypedTransaction::Legacy(Transaction::default());
|
||||
tx.tx_mut().nonce = 10.into();
|
||||
|
||||
let signed = tx.fake_sign(Default::default());
|
||||
PendingTransaction::new(signed, None)
|
||||
|
@ -79,11 +79,11 @@ impl txpool::Listener<Transaction> for Logger {
|
||||
"[{hash:?}] Sender: {sender}, nonce: {nonce}, gasPrice: {gas_price}, gas: {gas}, value: {value}, dataLen: {data}))",
|
||||
hash = tx.hash(),
|
||||
sender = tx.sender(),
|
||||
nonce = tx.signed().nonce,
|
||||
gas_price = tx.signed().gas_price,
|
||||
gas = tx.signed().gas,
|
||||
value = tx.signed().value,
|
||||
data = tx.signed().data.len(),
|
||||
nonce = tx.signed().tx().nonce,
|
||||
gas_price = tx.signed().tx().gas_price,
|
||||
gas = tx.signed().tx().gas,
|
||||
value = tx.signed().tx().value,
|
||||
data = tx.signed().tx().data.len(),
|
||||
);
|
||||
|
||||
if let Some(old) = old {
|
||||
@ -150,7 +150,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
*received.lock(),
|
||||
vec![
|
||||
"13aff4201ac1dc49daf6a7cf07b558ed956511acbaabf9502bdacc353953766d"
|
||||
"de96bdcdf864c95eb7f81eff1e3290be24a0f327732e0c4251c1896a565a80db"
|
||||
.parse()
|
||||
.unwrap()
|
||||
]
|
||||
@ -158,14 +158,14 @@ mod tests {
|
||||
}
|
||||
|
||||
fn new_tx() -> Arc<Transaction> {
|
||||
let signed = transaction::Transaction {
|
||||
let signed = transaction::TypedTransaction::Legacy(transaction::Transaction {
|
||||
action: transaction::Action::Create,
|
||||
data: vec![1, 2, 3],
|
||||
nonce: 5.into(),
|
||||
gas: 21_000.into(),
|
||||
gas_price: 5.into(),
|
||||
value: 0.into(),
|
||||
}
|
||||
})
|
||||
.fake_sign(5.into());
|
||||
|
||||
Arc::new(Transaction::from_pending_block_transaction(signed))
|
||||
|
@ -340,14 +340,14 @@ mod tests {
|
||||
|
||||
fn new_tx<T: Into<U256>>(nonce: T) -> Arc<Transaction> {
|
||||
let keypair = Random.generate().unwrap();
|
||||
let signed = transaction::Transaction {
|
||||
let signed = transaction::TypedTransaction::Legacy(transaction::Transaction {
|
||||
action: transaction::Action::Create,
|
||||
value: U256::from(100),
|
||||
data: Default::default(),
|
||||
gas: U256::from(10),
|
||||
gas_price: U256::from(1245),
|
||||
nonce: nonce.into(),
|
||||
}
|
||||
})
|
||||
.sign(keypair.secret(), None);
|
||||
|
||||
let mut tx = Transaction::from_pending_block_transaction(signed);
|
||||
|
@ -192,11 +192,11 @@ impl ScoredTransaction for VerifiedTransaction {
|
||||
|
||||
/// Gets transaction gas price.
|
||||
fn gas_price(&self) -> &U256 {
|
||||
&self.transaction.gas_price
|
||||
&self.transaction.tx().gas_price
|
||||
}
|
||||
|
||||
/// Gets transaction nonce.
|
||||
fn nonce(&self) -> U256 {
|
||||
self.transaction.nonce
|
||||
self.transaction.tx().nonce
|
||||
}
|
||||
}
|
||||
|
@ -519,7 +519,7 @@ impl TransactionQueue {
|
||||
.read()
|
||||
.pending_from_sender(state_readiness, address)
|
||||
.last()
|
||||
.map(|tx| tx.signed().nonce.saturating_add(U256::from(1)))
|
||||
.map(|tx| tx.signed().tx().nonce.saturating_add(U256::from(1)))
|
||||
}
|
||||
|
||||
/// Retrieve a transaction from the pool.
|
||||
@ -573,7 +573,7 @@ impl TransactionQueue {
|
||||
/// Returns gas price of currently the worst transaction in the pool.
|
||||
pub fn current_worst_gas_price(&self) -> U256 {
|
||||
match self.pool.read().worst_transaction() {
|
||||
Some(tx) => tx.signed().gas_price,
|
||||
Some(tx) => tx.signed().tx().gas_price,
|
||||
None => self.options.read().minimal_gas_price,
|
||||
}
|
||||
}
|
||||
@ -660,7 +660,7 @@ mod tests {
|
||||
);
|
||||
|
||||
for tx in pending {
|
||||
assert!(tx.signed().nonce > 0.into());
|
||||
assert!(tx.signed().tx().nonce > 0.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ impl<C: NonceClient> txpool::Ready<VerifiedTransaction> for State<C> {
|
||||
fn is_ready(&mut self, tx: &VerifiedTransaction) -> txpool::Readiness {
|
||||
// Check max nonce
|
||||
match self.max_nonce {
|
||||
Some(nonce) if tx.transaction.nonce > nonce => {
|
||||
Some(nonce) if tx.transaction.tx().nonce > nonce => {
|
||||
return txpool::Readiness::Future;
|
||||
}
|
||||
_ => {}
|
||||
@ -81,7 +81,7 @@ impl<C: NonceClient> txpool::Ready<VerifiedTransaction> for State<C> {
|
||||
let state = &self.state;
|
||||
let state_nonce = || state.account_nonce(sender);
|
||||
let nonce = self.nonces.entry(*sender).or_insert_with(state_nonce);
|
||||
match tx.transaction.nonce.cmp(nonce) {
|
||||
match tx.transaction.tx().nonce.cmp(nonce) {
|
||||
// Before marking as future check for stale ids
|
||||
cmp::Ordering::Greater => match self.stale_id {
|
||||
Some(id) if tx.insertion_id() < id => txpool::Readiness::Stale,
|
||||
@ -150,8 +150,8 @@ impl<C: Fn(&Address) -> Option<U256>> txpool::Ready<VerifiedTransaction> for Opt
|
||||
let nonce = self
|
||||
.nonces
|
||||
.entry(*sender)
|
||||
.or_insert_with(|| state(sender).unwrap_or_else(|| tx.transaction.nonce));
|
||||
match tx.transaction.nonce.cmp(nonce) {
|
||||
.or_insert_with(|| state(sender).unwrap_or_else(|| tx.transaction.tx().nonce));
|
||||
match tx.transaction.tx().nonce.cmp(nonce) {
|
||||
cmp::Ordering::Greater => txpool::Readiness::Future,
|
||||
cmp::Ordering::Less => txpool::Readiness::Stale,
|
||||
cmp::Ordering::Equal => {
|
||||
|
@ -67,7 +67,7 @@ impl NonceAndGasPrice {
|
||||
return true;
|
||||
}
|
||||
|
||||
&old.transaction.gas_price > new.gas_price()
|
||||
&old.transaction.tx().gas_price > new.gas_price()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,9 @@ use std::sync::{atomic, Arc};
|
||||
|
||||
use ethereum_types::{Address, H256, U256};
|
||||
use rlp::Rlp;
|
||||
use types::transaction::{self, SignedTransaction, Transaction, UnverifiedTransaction};
|
||||
use types::transaction::{
|
||||
self, SignedTransaction, Transaction, TypedTransaction, UnverifiedTransaction,
|
||||
};
|
||||
|
||||
use pool::{self, client::AccountDetails};
|
||||
|
||||
@ -150,7 +152,7 @@ impl pool::client::Client for TestClient {
|
||||
if rlp.as_raw().len() > self.max_transaction_size {
|
||||
return Err(transaction::Error::TooBig);
|
||||
}
|
||||
rlp.as_val()
|
||||
TypedTransaction::decode(transaction)
|
||||
.map_err(|e| transaction::Error::InvalidRlp(e.to_string()))
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ fn should_return_correct_nonces_when_dropped_because_of_limit() {
|
||||
);
|
||||
let (tx1, tx2) = Tx::gas_price(2).signed_pair();
|
||||
let sender = tx1.sender();
|
||||
let nonce = tx1.nonce;
|
||||
let nonce = tx1.tx().nonce;
|
||||
|
||||
// when
|
||||
let r1 = txq.import(TestClient::new(), vec![tx1].retracted());
|
||||
@ -129,7 +129,7 @@ fn should_never_drop_local_transactions_from_different_senders() {
|
||||
);
|
||||
let (tx1, tx2) = Tx::gas_price(2).signed_pair();
|
||||
let sender = tx1.sender();
|
||||
let nonce = tx1.nonce;
|
||||
let nonce = tx1.tx().nonce;
|
||||
|
||||
// when
|
||||
let r1 = txq.import(TestClient::new(), vec![tx1].local());
|
||||
@ -662,12 +662,14 @@ fn should_not_replace_same_transaction_if_the_fee_is_less_than_minimal_bump() {
|
||||
assert_eq!(
|
||||
txq.pending(client.clone(), PendingSettings::all_prioritized(0, 0))[0]
|
||||
.signed()
|
||||
.tx()
|
||||
.gas_price,
|
||||
U256::from(20)
|
||||
);
|
||||
assert_eq!(
|
||||
txq.pending(client.clone(), PendingSettings::all_prioritized(0, 0))[1]
|
||||
.signed()
|
||||
.tx()
|
||||
.gas_price,
|
||||
U256::from(2)
|
||||
);
|
||||
@ -688,7 +690,7 @@ fn should_return_correct_nonce_when_transactions_from_given_address_exist() {
|
||||
let txq = new_queue();
|
||||
let tx = Tx::default().signed();
|
||||
let from = tx.sender();
|
||||
let nonce = tx.nonce;
|
||||
let nonce = tx.tx().nonce;
|
||||
|
||||
// when
|
||||
txq.import(TestClient::new(), vec![tx.local()]);
|
||||
|
@ -17,7 +17,9 @@
|
||||
use ethereum_types::{H256, U256};
|
||||
use ethkey::{Generator, Random};
|
||||
use rustc_hex::FromHex;
|
||||
use types::transaction::{self, SignedTransaction, Transaction, UnverifiedTransaction};
|
||||
use types::transaction::{
|
||||
self, SignedTransaction, Transaction, TypedTransaction, UnverifiedTransaction,
|
||||
};
|
||||
|
||||
use pool::{verifier, VerifiedTransaction};
|
||||
|
||||
@ -76,20 +78,20 @@ impl Tx {
|
||||
(tx1, tx2)
|
||||
}
|
||||
|
||||
pub fn unsigned(self) -> Transaction {
|
||||
Transaction {
|
||||
pub fn unsigned(self) -> TypedTransaction {
|
||||
TypedTransaction::Legacy(Transaction {
|
||||
action: transaction::Action::Create,
|
||||
value: U256::from(100),
|
||||
data: "3331600055".from_hex().unwrap(),
|
||||
gas: self.gas.into(),
|
||||
gas_price: self.gas_price.into(),
|
||||
nonce: self.nonce.into(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn big_one(self) -> SignedTransaction {
|
||||
let keypair = Random.generate().unwrap();
|
||||
let tx = Transaction {
|
||||
let tx = TypedTransaction::Legacy(Transaction {
|
||||
action: transaction::Action::Create,
|
||||
value: U256::from(100),
|
||||
data: include_str!("../res/big_transaction.data")
|
||||
@ -98,7 +100,7 @@ impl Tx {
|
||||
gas: self.gas.into(),
|
||||
gas_price: self.gas_price.into(),
|
||||
nonce: self.nonce.into(),
|
||||
};
|
||||
});
|
||||
tx.sign(keypair.secret(), None)
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,6 @@ use std::{
|
||||
};
|
||||
|
||||
use ethereum_types::{H256, U256};
|
||||
use rlp::Encodable;
|
||||
use txpool;
|
||||
use types::transaction;
|
||||
|
||||
@ -97,21 +96,21 @@ impl Transaction {
|
||||
/// Return transaction gas price
|
||||
pub fn gas_price(&self) -> &U256 {
|
||||
match *self {
|
||||
Transaction::Unverified(ref tx) => &tx.gas_price,
|
||||
Transaction::Retracted(ref tx) => &tx.gas_price,
|
||||
Transaction::Local(ref tx) => &tx.gas_price,
|
||||
Transaction::Unverified(ref tx) => &tx.tx().gas_price,
|
||||
Transaction::Retracted(ref tx) => &tx.tx().gas_price,
|
||||
Transaction::Local(ref tx) => &tx.tx().gas_price,
|
||||
}
|
||||
}
|
||||
|
||||
fn gas(&self) -> &U256 {
|
||||
match *self {
|
||||
Transaction::Unverified(ref tx) => &tx.gas,
|
||||
Transaction::Retracted(ref tx) => &tx.gas,
|
||||
Transaction::Local(ref tx) => &tx.gas,
|
||||
Transaction::Unverified(ref tx) => &tx.tx().gas,
|
||||
Transaction::Retracted(ref tx) => &tx.tx().gas,
|
||||
Transaction::Local(ref tx) => &tx.tx().gas,
|
||||
}
|
||||
}
|
||||
|
||||
fn transaction(&self) -> &transaction::Transaction {
|
||||
fn transaction(&self) -> &transaction::TypedTransaction {
|
||||
match *self {
|
||||
Transaction::Unverified(ref tx) => &*tx,
|
||||
Transaction::Retracted(ref tx) => &*tx,
|
||||
@ -198,7 +197,7 @@ impl<C: Client> txpool::Verifier<Transaction>
|
||||
});
|
||||
}
|
||||
|
||||
let minimal_gas = self.client.required_gas(tx.transaction());
|
||||
let minimal_gas = self.client.required_gas(tx.transaction().tx());
|
||||
if tx.gas() < &minimal_gas {
|
||||
trace!(target: "txqueue",
|
||||
"[{:?}] Rejected transaction with insufficient gas: {} < {}",
|
||||
@ -240,10 +239,10 @@ impl<C: Client> txpool::Verifier<Transaction>
|
||||
"[{:?}] Rejected tx early, cause it doesn't have any chance to get to the pool: (gas price: {} < {})",
|
||||
hash,
|
||||
tx.gas_price(),
|
||||
vtx.transaction.gas_price,
|
||||
vtx.transaction.tx().gas_price,
|
||||
);
|
||||
return Err(transaction::Error::TooCheapToReplace {
|
||||
prev: Some(vtx.transaction.gas_price),
|
||||
prev: Some(vtx.transaction.tx().gas_price),
|
||||
new: Some(*tx.gas_price()),
|
||||
});
|
||||
}
|
||||
@ -273,7 +272,7 @@ impl<C: Client> txpool::Verifier<Transaction>
|
||||
};
|
||||
|
||||
// Verify RLP payload
|
||||
if let Err(err) = self.client.decode_transaction(&transaction.rlp_bytes()) {
|
||||
if let Err(err) = self.client.decode_transaction(&transaction.encode()) {
|
||||
debug!(target: "txqueue", "[{:?}] Rejected transaction's rlp payload", err);
|
||||
bail!(err)
|
||||
}
|
||||
@ -281,7 +280,7 @@ impl<C: Client> txpool::Verifier<Transaction>
|
||||
let sender = transaction.sender();
|
||||
let account_details = self.client.account_details(&sender);
|
||||
|
||||
if transaction.gas_price < self.options.minimal_gas_price {
|
||||
if transaction.tx().gas_price < self.options.minimal_gas_price {
|
||||
let transaction_type = self.client.transaction_type(&transaction);
|
||||
if let TransactionType::Service = transaction_type {
|
||||
debug!(target: "txqueue", "Service tx {:?} below minimal gas price accepted", hash);
|
||||
@ -292,18 +291,21 @@ impl<C: Client> txpool::Verifier<Transaction>
|
||||
target: "txqueue",
|
||||
"[{:?}] Rejected tx below minimal gas price threshold: {} < {}",
|
||||
hash,
|
||||
transaction.gas_price,
|
||||
transaction.tx().gas_price,
|
||||
self.options.minimal_gas_price,
|
||||
);
|
||||
bail!(transaction::Error::InsufficientGasPrice {
|
||||
minimal: self.options.minimal_gas_price,
|
||||
got: transaction.gas_price,
|
||||
got: transaction.tx().gas_price,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let (full_gas_price, overflow_1) = transaction.gas_price.overflowing_mul(transaction.gas);
|
||||
let (cost, overflow_2) = transaction.value.overflowing_add(full_gas_price);
|
||||
let (full_gas_price, overflow_1) = transaction
|
||||
.tx()
|
||||
.gas_price
|
||||
.overflowing_mul(transaction.tx().gas);
|
||||
let (cost, overflow_2) = transaction.tx().value.overflowing_add(full_gas_price);
|
||||
if overflow_1 || overflow_2 {
|
||||
trace!(
|
||||
target: "txqueue",
|
||||
@ -329,12 +331,12 @@ impl<C: Client> txpool::Verifier<Transaction>
|
||||
});
|
||||
}
|
||||
|
||||
if transaction.nonce < account_details.nonce {
|
||||
if transaction.tx().nonce < account_details.nonce {
|
||||
debug!(
|
||||
target: "txqueue",
|
||||
"[{:?}] Rejected tx with old nonce ({} < {})",
|
||||
hash,
|
||||
transaction.nonce,
|
||||
transaction.tx().nonce,
|
||||
account_details.nonce,
|
||||
);
|
||||
bail!(transaction::Error::Old);
|
||||
|
@ -45,7 +45,7 @@ impl ServiceTransactionChecker {
|
||||
) -> Result<bool, String> {
|
||||
let sender = tx.sender();
|
||||
// Skip checking the contract if the transaction does not have zero gas price
|
||||
if !tx.gas_price.is_zero() {
|
||||
if !tx.tx().gas_price.is_zero() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
|
@ -120,6 +120,7 @@ impl<C: miner::BlockChainClient + BlockChainClient, M: MinerService> Dispatcher
|
||||
};
|
||||
|
||||
Box::new(future::ok(FilledTransactionRequest {
|
||||
tx_type: request.tx_type,
|
||||
from,
|
||||
used_default_from: request.from.is_none(),
|
||||
to: request.to,
|
||||
@ -133,6 +134,7 @@ impl<C: miner::BlockChainClient + BlockChainClient, M: MinerService> Dispatcher
|
||||
value: request.value.unwrap_or_else(|| 0.into()),
|
||||
data: request.data.unwrap_or_else(Vec::new),
|
||||
condition: request.condition,
|
||||
access_list: request.access_list,
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,10 @@ use bytes::Bytes;
|
||||
use crypto::DEFAULT_MAC;
|
||||
use ethereum_types::{Address, H256, U256};
|
||||
use ethkey::Signature;
|
||||
use types::transaction::{Action, SignedTransaction, Transaction};
|
||||
use jsonrpc_core::{Error, ErrorCode};
|
||||
use types::transaction::{
|
||||
AccessListTx, Action, SignedTransaction, Transaction, TypedTransaction, TypedTxId,
|
||||
};
|
||||
|
||||
use jsonrpc_core::Result;
|
||||
use v1::helpers::{errors, FilledTransactionRequest};
|
||||
@ -48,16 +51,28 @@ impl super::Accounts for Signer {
|
||||
nonce: U256,
|
||||
password: SignWith,
|
||||
) -> Result<WithToken<SignedTransaction>> {
|
||||
let t = Transaction {
|
||||
nonce: nonce,
|
||||
let legacy_tx = Transaction {
|
||||
nonce,
|
||||
action: filled.to.map_or(Action::Create, Action::Call),
|
||||
gas: filled.gas,
|
||||
gas_price: filled.gas_price,
|
||||
value: filled.value,
|
||||
data: filled.data,
|
||||
};
|
||||
let t = match filled.tx_type {
|
||||
TypedTxId::Legacy => TypedTransaction::Legacy(legacy_tx),
|
||||
TypedTxId::AccessList => {
|
||||
if filled.access_list.is_none() {
|
||||
return Err(Error::new(ErrorCode::InvalidParams));
|
||||
}
|
||||
TypedTransaction::AccessList(AccessListTx::new(
|
||||
legacy_tx,
|
||||
filled.access_list.unwrap(),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let hash = t.hash(chain_id);
|
||||
let hash = t.signature_hash(chain_id);
|
||||
let signature = signature(&*self.accounts, filled.from, hash, password)?;
|
||||
|
||||
Ok(signature.map(|sig| {
|
||||
|
@ -400,6 +400,7 @@ pub fn transaction_message(error: &TransactionError) -> String {
|
||||
NotAllowed => "Transaction is not permitted.".into(),
|
||||
TooBig => "Transaction is too big, see chain specification for the limit.".into(),
|
||||
InvalidRlp(ref descr) => format!("Invalid RLP data: {}", descr),
|
||||
TransactionTypeNotEnabled => format!("Transaction type is not enabled for current block"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -256,6 +256,7 @@ mod test {
|
||||
|
||||
fn request() -> ConfirmationPayload {
|
||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Address::from(1),
|
||||
used_default_from: false,
|
||||
to: Some(Address::from(2)),
|
||||
@ -265,6 +266,7 @@ mod test {
|
||||
data: vec![],
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,9 @@
|
||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::cmp::min;
|
||||
use types::transaction::{Action, SignedTransaction, Transaction};
|
||||
use types::transaction::{
|
||||
AccessListTx, Action, SignedTransaction, Transaction, TypedTransaction, TypedTxId,
|
||||
};
|
||||
|
||||
use ethereum_types::U256;
|
||||
use jsonrpc_core::Error;
|
||||
@ -25,14 +27,20 @@ pub fn sign_call(request: CallRequest) -> Result<SignedTransaction, Error> {
|
||||
let max_gas = U256::from(500_000_000);
|
||||
let gas = min(request.gas.unwrap_or(max_gas), max_gas);
|
||||
let from = request.from.unwrap_or_default();
|
||||
|
||||
Ok(Transaction {
|
||||
let tx_legacy = Transaction {
|
||||
nonce: request.nonce.unwrap_or_default(),
|
||||
action: request.to.map_or(Action::Create, Action::Call),
|
||||
gas,
|
||||
gas_price: request.gas_price.unwrap_or_default(),
|
||||
value: request.value.unwrap_or_default(),
|
||||
data: request.data.unwrap_or_default(),
|
||||
}
|
||||
.fake_sign(from))
|
||||
};
|
||||
let tx_typed = match request.tx_type {
|
||||
TypedTxId::Legacy => TypedTransaction::Legacy(tx_legacy),
|
||||
TypedTxId::AccessList => TypedTransaction::AccessList(AccessListTx::new(
|
||||
tx_legacy,
|
||||
request.access_list.unwrap_or_default(),
|
||||
)),
|
||||
};
|
||||
Ok(tx_typed.fake_sign(from))
|
||||
}
|
||||
|
@ -16,12 +16,15 @@
|
||||
|
||||
use bytes::Bytes;
|
||||
use ethereum_types::{Address, H256, U256};
|
||||
use types::transaction::{AccessList, TypedTxId};
|
||||
|
||||
use v1::types::{Origin, TransactionCondition};
|
||||
|
||||
/// Transaction request coming from RPC
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Hash)]
|
||||
pub struct TransactionRequest {
|
||||
/// type of transaction.
|
||||
pub tx_type: TypedTxId,
|
||||
/// Sender
|
||||
pub from: Option<Address>,
|
||||
/// Recipient
|
||||
@ -38,11 +41,15 @@ pub struct TransactionRequest {
|
||||
pub nonce: Option<U256>,
|
||||
/// Delay until this condition is met.
|
||||
pub condition: Option<TransactionCondition>,
|
||||
/// Access list
|
||||
pub access_list: Option<AccessList>,
|
||||
}
|
||||
|
||||
/// Transaction request coming from RPC with default values filled in.
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Hash)]
|
||||
pub struct FilledTransactionRequest {
|
||||
/// type of transaction.
|
||||
pub tx_type: TypedTxId,
|
||||
/// Sender
|
||||
pub from: Address,
|
||||
/// Indicates if the sender was filled by default value.
|
||||
@ -61,11 +68,14 @@ pub struct FilledTransactionRequest {
|
||||
pub nonce: Option<U256>,
|
||||
/// Delay until this condition is met.
|
||||
pub condition: Option<TransactionCondition>,
|
||||
/// Access list
|
||||
pub access_list: Option<AccessList>,
|
||||
}
|
||||
|
||||
impl From<FilledTransactionRequest> for TransactionRequest {
|
||||
fn from(r: FilledTransactionRequest) -> Self {
|
||||
TransactionRequest {
|
||||
tx_type: r.tx_type,
|
||||
from: Some(r.from),
|
||||
to: r.to,
|
||||
gas_price: Some(r.gas_price),
|
||||
@ -74,6 +84,7 @@ impl From<FilledTransactionRequest> for TransactionRequest {
|
||||
data: Some(r.data),
|
||||
nonce: r.nonce,
|
||||
condition: r.condition,
|
||||
access_list: r.access_list,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -81,6 +92,8 @@ impl From<FilledTransactionRequest> for TransactionRequest {
|
||||
/// Call request
|
||||
#[derive(Debug, Default, PartialEq)]
|
||||
pub struct CallRequest {
|
||||
/// type of transaction.
|
||||
pub tx_type: TypedTxId,
|
||||
/// From
|
||||
pub from: Option<Address>,
|
||||
/// To
|
||||
@ -95,6 +108,8 @@ pub struct CallRequest {
|
||||
pub data: Option<Vec<u8>>,
|
||||
/// Nonce
|
||||
pub nonce: Option<U256>,
|
||||
/// Access list
|
||||
pub access_list: Option<AccessList>,
|
||||
}
|
||||
|
||||
/// Confirmation object
|
||||
|
@ -24,7 +24,6 @@ use std::{
|
||||
|
||||
use ethereum_types::{Address, H160, H256, H64, U256, U64};
|
||||
use parking_lot::Mutex;
|
||||
use rlp::Rlp;
|
||||
|
||||
use ethash::{self, SeedHashCompute};
|
||||
use ethcore::{
|
||||
@ -42,7 +41,7 @@ use types::{
|
||||
encoded,
|
||||
filter::Filter as EthcoreFilter,
|
||||
header::Header,
|
||||
transaction::{LocalizedTransaction, SignedTransaction},
|
||||
transaction::{LocalizedTransaction, SignedTransaction, TypedTransaction},
|
||||
BlockNumber as EthBlockNumber,
|
||||
};
|
||||
|
||||
@ -1065,8 +1064,7 @@ where
|
||||
}
|
||||
|
||||
fn send_raw_transaction(&self, raw: Bytes) -> Result<H256> {
|
||||
Rlp::new(&raw.into_vec())
|
||||
.as_val()
|
||||
TypedTransaction::decode(&raw.into_vec())
|
||||
.map_err(errors::rlp)
|
||||
.and_then(|tx| SignedTransaction::new(tx).map_err(errors::transaction))
|
||||
.and_then(|signed_transaction| {
|
||||
|
@ -22,8 +22,7 @@ use ethereum_types::U256;
|
||||
use ethkey;
|
||||
use parity_runtime::Executor;
|
||||
use parking_lot::Mutex;
|
||||
use rlp::Rlp;
|
||||
use types::transaction::{PendingTransaction, SignedTransaction};
|
||||
use types::transaction::{PendingTransaction, SignedTransaction, TypedTransaction};
|
||||
|
||||
use jsonrpc_core::{
|
||||
futures::{future, future::Either, Future, IntoFuture},
|
||||
@ -161,17 +160,17 @@ impl<D: Dispatcher + 'static> SignerClient<D> {
|
||||
where
|
||||
F: FnOnce(PendingTransaction) -> Result<ConfirmationResponse>,
|
||||
{
|
||||
let signed_transaction = Rlp::new(&bytes.0).as_val().map_err(errors::rlp)?;
|
||||
let signed_transaction = TypedTransaction::decode(&bytes.0).map_err(errors::rlp)?;
|
||||
let signed_transaction = SignedTransaction::new(signed_transaction)
|
||||
.map_err(|e| errors::invalid_params("Invalid signature.", e))?;
|
||||
let sender = signed_transaction.sender();
|
||||
|
||||
// Verification
|
||||
let sender_matches = sender == request.from;
|
||||
let data_matches = signed_transaction.data == request.data;
|
||||
let value_matches = signed_transaction.value == request.value;
|
||||
let data_matches = signed_transaction.tx().data == request.data;
|
||||
let value_matches = signed_transaction.tx().value == request.value;
|
||||
let nonce_matches = match request.nonce {
|
||||
Some(nonce) => signed_transaction.nonce == nonce,
|
||||
Some(nonce) => signed_transaction.tx().nonce == nonce,
|
||||
None => true,
|
||||
};
|
||||
|
||||
|
@ -22,8 +22,7 @@ use ethcore::client::{
|
||||
BlockChainClient, BlockId, Call, CallAnalytics, StateClient, StateInfo, TraceId, TransactionId,
|
||||
};
|
||||
use ethereum_types::H256;
|
||||
use rlp::Rlp;
|
||||
use types::transaction::SignedTransaction;
|
||||
use types::transaction::{SignedTransaction, TypedTransaction};
|
||||
|
||||
use jsonrpc_core::Result;
|
||||
use v1::{
|
||||
@ -194,9 +193,8 @@ where
|
||||
) -> Result<TraceResults> {
|
||||
let block = block.unwrap_or_default();
|
||||
|
||||
let tx = Rlp::new(&raw_transaction.into_vec())
|
||||
.as_val()
|
||||
.map_err(|e| errors::invalid_params("Transaction is not valid RLP", e))?;
|
||||
let tx = TypedTransaction::decode(&raw_transaction.0)
|
||||
.map_err(|e| errors::invalid_params("Transaction is not in valid Format", e))?;
|
||||
let signed = SignedTransaction::new(tx).map_err(errors::transaction)?;
|
||||
|
||||
let id = match block {
|
||||
|
@ -30,14 +30,13 @@ use ethereum_types::{Address, Bloom, H160, H256, U256};
|
||||
use miner::external::ExternalMiner;
|
||||
use parity_runtime::Runtime;
|
||||
use parking_lot::Mutex;
|
||||
use rlp;
|
||||
use rustc_hex::{FromHex, ToHex};
|
||||
use sync::SyncState;
|
||||
use types::{
|
||||
ids::{BlockId, TransactionId},
|
||||
log_entry::{LocalizedLogEntry, LogEntry},
|
||||
receipt::{LocalizedReceipt, RichReceipt, TransactionOutcome},
|
||||
transaction::{Action, Transaction},
|
||||
transaction::{Action, Transaction, TypedTransaction, TypedTxId},
|
||||
};
|
||||
|
||||
use jsonrpc_core::IoHandler;
|
||||
@ -694,13 +693,12 @@ fn rpc_eth_transaction_count_by_number_pending() {
|
||||
#[test]
|
||||
fn rpc_eth_pending_transaction_by_hash() {
|
||||
use ethereum_types::H256;
|
||||
use rlp;
|
||||
use types::transaction::SignedTransaction;
|
||||
|
||||
let tester = EthTester::default();
|
||||
{
|
||||
let bytes = FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap();
|
||||
let tx = rlp::decode(&bytes).expect("decoding failure");
|
||||
let tx = TypedTransaction::decode(&bytes).expect("decoding failure");
|
||||
let tx = SignedTransaction::new(tx).unwrap();
|
||||
tester
|
||||
.miner
|
||||
@ -1050,6 +1048,23 @@ fn rpc_eth_estimate_gas_default_block() {
|
||||
fn rpc_eth_send_raw_transaction_error() {
|
||||
let tester = EthTester::default();
|
||||
|
||||
let req = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_sendRawTransaction",
|
||||
"params": [
|
||||
"0x1123"
|
||||
],
|
||||
"id": 1
|
||||
}"#;
|
||||
let res = r#"{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid RLP.","data":"Custom(\"Unknown transaction\")"},"id":1}"#.into();
|
||||
|
||||
assert_eq!(tester.io.handle_request_sync(&req), Some(res));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rpc_eth_send_raw_01_transaction_error() {
|
||||
let tester = EthTester::default();
|
||||
|
||||
let req = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_sendRawTransaction",
|
||||
@ -1075,7 +1090,7 @@ fn rpc_eth_send_raw_transaction() {
|
||||
.unlock_account_permanently(address, "abcd".into())
|
||||
.unwrap();
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::zero(),
|
||||
gas_price: U256::from(0x9184e72a000u64),
|
||||
gas: U256::from(0x76c0),
|
||||
@ -1084,14 +1099,14 @@ fn rpc_eth_send_raw_transaction() {
|
||||
),
|
||||
value: U256::from(0x9184e72au64),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
let signature = tester
|
||||
.accounts_provider
|
||||
.sign(address, None, t.hash(None))
|
||||
.sign(address, None, t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
let rlp = rlp::encode(&t).to_hex();
|
||||
let rlp = t.encode().to_hex();
|
||||
|
||||
let req = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
@ -1118,6 +1133,7 @@ fn rpc_eth_transaction_receipt() {
|
||||
to: Some(H160::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||
transaction_hash: H256::zero(),
|
||||
transaction_index: 0,
|
||||
transaction_type: TypedTxId::Legacy,
|
||||
block_hash: H256::from_str(
|
||||
"ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5",
|
||||
)
|
||||
@ -1204,6 +1220,7 @@ fn rpc_eth_pending_receipt() {
|
||||
)
|
||||
.unwrap(),
|
||||
transaction_index: 0,
|
||||
transaction_type: TypedTxId::Legacy,
|
||||
cumulative_gas_used: U256::from(0x20),
|
||||
gas_used: U256::from(0x10),
|
||||
contract_address: None,
|
||||
|
@ -21,7 +21,10 @@ use ethstore::ethkey::{Generator, Random};
|
||||
use miner::pool::local_transactions::Status as LocalTransactionStatus;
|
||||
use std::sync::Arc;
|
||||
use sync::ManageNetwork;
|
||||
use types::receipt::{LocalizedReceipt, TransactionOutcome};
|
||||
use types::{
|
||||
receipt::{LocalizedReceipt, TransactionOutcome},
|
||||
transaction::TypedTxId,
|
||||
};
|
||||
|
||||
use super::manage_network::TestManageNetwork;
|
||||
use jsonrpc_core::IoHandler;
|
||||
@ -368,16 +371,17 @@ fn rpc_parity_transactions_stats() {
|
||||
|
||||
#[test]
|
||||
fn rpc_parity_local_transactions() {
|
||||
use types::transaction::{Transaction, TypedTransaction};
|
||||
let deps = Dependencies::new();
|
||||
let io = deps.default_client();
|
||||
let tx = ::types::transaction::Transaction {
|
||||
let tx = TypedTransaction::Legacy(Transaction {
|
||||
value: 5.into(),
|
||||
gas: 3.into(),
|
||||
gas_price: 2.into(),
|
||||
action: ::types::transaction::Action::Create,
|
||||
data: vec![1, 2, 3],
|
||||
nonce: 0.into(),
|
||||
}
|
||||
})
|
||||
.fake_sign(3.into());
|
||||
let tx = Arc::new(::miner::pool::VerifiedTransaction::from_pending_block_transaction(tx));
|
||||
deps.miner
|
||||
@ -466,6 +470,7 @@ fn rpc_parity_block_receipts() {
|
||||
TransactionId::Hash(1.into()),
|
||||
LocalizedReceipt {
|
||||
transaction_hash: 1.into(),
|
||||
transaction_type: TypedTxId::Legacy,
|
||||
transaction_index: 0,
|
||||
block_hash: 3.into(),
|
||||
block_number: 0,
|
||||
|
@ -178,7 +178,7 @@ fn rpc_parity_set_hash_content() {
|
||||
|
||||
#[test]
|
||||
fn rpc_parity_remove_transaction() {
|
||||
use types::transaction::{Action, Transaction};
|
||||
use types::transaction::{Action, Transaction, TypedTransaction};
|
||||
|
||||
let miner = miner_service();
|
||||
let client = client_service();
|
||||
@ -187,14 +187,14 @@ fn rpc_parity_remove_transaction() {
|
||||
let mut io = IoHandler::new();
|
||||
io.extend_with(parity_set_client(&client, &miner, &network).to_delegate());
|
||||
|
||||
let tx = Transaction {
|
||||
let tx = TypedTransaction::Legacy(Transaction {
|
||||
nonce: 1.into(),
|
||||
gas_price: 0x9184e72a000u64.into(),
|
||||
gas: 0x76c0.into(),
|
||||
action: Action::Call(5.into()),
|
||||
value: 0x9184e72au64.into(),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
let signed = tx.fake_sign(2.into());
|
||||
let hash = signed.hash();
|
||||
|
||||
@ -202,7 +202,7 @@ fn rpc_parity_remove_transaction() {
|
||||
.to_owned()
|
||||
+ &format!("0x{:x}", hash)
|
||||
+ r#""], "id": 1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"chainId":null,"condition":null,"creates":null,"from":"0x0000000000000000000000000000000000000002","gas":"0x76c0","gasPrice":"0x9184e72a000","hash":"0xa2e0da8a8064e0b9f93e95a53c2db6d01280efb8ac72a708d25487e67dd0f8fc","input":"0x","nonce":"0x1","publicKey":null,"r":"0x1","raw":"0xe9018609184e72a0008276c0940000000000000000000000000000000000000005849184e72a80800101","s":"0x1","standardV":"0x4","to":"0x0000000000000000000000000000000000000005","transactionIndex":null,"v":"0x0","value":"0x9184e72a"},"id":1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"chainId":null,"condition":null,"creates":null,"from":"0x0000000000000000000000000000000000000002","gas":"0x76c0","gasPrice":"0x9184e72a000","hash":"0x49569012bc8523519642c337fded3f20ba987beab31e14c67223b3d31359956f","input":"0x","nonce":"0x1","publicKey":null,"r":"0x1","raw":"0xe9018609184e72a0008276c0940000000000000000000000000000000000000005849184e72a801f0101","s":"0x1","standardV":"0x4","to":"0x0000000000000000000000000000000000000005","transactionIndex":null,"v":"0x1f","value":"0x9184e72a"},"id":1}"#;
|
||||
|
||||
miner.pending_transactions.lock().insert(hash, signed);
|
||||
assert_eq!(io.handle_request_sync(&request), Some(response.to_owned()));
|
||||
|
@ -24,7 +24,7 @@ use hash::keccak;
|
||||
use jsonrpc_core::IoHandler;
|
||||
use parity_runtime::Runtime;
|
||||
use parking_lot::Mutex;
|
||||
use types::transaction::{Action, Transaction};
|
||||
use types::transaction::{Action, Transaction, TypedTransaction};
|
||||
|
||||
use ethkey::Secret;
|
||||
use serde_json::to_value;
|
||||
@ -91,9 +91,6 @@ fn setup_with(c: Config) -> PersonalTester {
|
||||
tester
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
use rustc_hex::ToHex;
|
||||
|
||||
#[test]
|
||||
fn accounts() {
|
||||
let tester = setup();
|
||||
@ -265,7 +262,7 @@ fn sign_and_send_test(method: &str) {
|
||||
"id": 1
|
||||
}"#;
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::zero(),
|
||||
gas_price: U256::from(0x9184e72a000u64),
|
||||
gas: U256::from(0x76c0),
|
||||
@ -274,12 +271,15 @@ fn sign_and_send_test(method: &str) {
|
||||
),
|
||||
value: U256::from(0x9184e72au64),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
tester
|
||||
.accounts
|
||||
.unlock_account_temporarily(address, "password123".into())
|
||||
.unwrap();
|
||||
let signature = tester.accounts.sign(address, None, t.hash(None)).unwrap();
|
||||
let signature = tester
|
||||
.accounts
|
||||
.sign(address, None, t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned()
|
||||
@ -293,7 +293,7 @@ fn sign_and_send_test(method: &str) {
|
||||
|
||||
tester.miner.increment_nonce(&address);
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::one(),
|
||||
gas_price: U256::from(0x9184e72a000u64),
|
||||
gas: U256::from(0x76c0),
|
||||
@ -302,12 +302,15 @@ fn sign_and_send_test(method: &str) {
|
||||
),
|
||||
value: U256::from(0x9184e72au64),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
tester
|
||||
.accounts
|
||||
.unlock_account_temporarily(address, "password123".into())
|
||||
.unwrap();
|
||||
let signature = tester.accounts.sign(address, None, t.hash(None)).unwrap();
|
||||
let signature = tester
|
||||
.accounts
|
||||
.sign(address, None, t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned()
|
||||
|
@ -22,8 +22,7 @@ use accounts::AccountProvider;
|
||||
use ethcore::client::TestBlockChainClient;
|
||||
use parity_runtime::Runtime;
|
||||
use parking_lot::Mutex;
|
||||
use rlp::encode;
|
||||
use types::transaction::{Action, SignedTransaction, Transaction};
|
||||
use types::transaction::{Action, SignedTransaction, Transaction, TypedTransaction};
|
||||
|
||||
use jsonrpc_core::IoHandler;
|
||||
use serde_json;
|
||||
@ -92,6 +91,7 @@ fn should_return_list_of_items_to_confirm() {
|
||||
.signer
|
||||
.add_request(
|
||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Address::from(1),
|
||||
used_default_from: false,
|
||||
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||
@ -101,6 +101,7 @@ fn should_return_list_of_items_to_confirm() {
|
||||
data: vec![],
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
}),
|
||||
Origin::Unknown,
|
||||
)
|
||||
@ -137,6 +138,7 @@ fn should_reject_transaction_from_queue_without_dispatching() {
|
||||
.signer
|
||||
.add_request(
|
||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Address::from(1),
|
||||
used_default_from: false,
|
||||
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||
@ -146,6 +148,7 @@ fn should_reject_transaction_from_queue_without_dispatching() {
|
||||
data: vec![],
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
}),
|
||||
Origin::Unknown,
|
||||
)
|
||||
@ -173,6 +176,7 @@ fn should_not_remove_transaction_if_password_is_invalid() {
|
||||
.signer
|
||||
.add_request(
|
||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Address::from(1),
|
||||
used_default_from: false,
|
||||
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||
@ -182,6 +186,7 @@ fn should_not_remove_transaction_if_password_is_invalid() {
|
||||
data: vec![],
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
}),
|
||||
Origin::Unknown,
|
||||
)
|
||||
@ -237,6 +242,7 @@ fn should_confirm_transaction_and_dispatch() {
|
||||
.signer
|
||||
.add_request(
|
||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: address,
|
||||
used_default_from: false,
|
||||
to: Some(recipient),
|
||||
@ -246,24 +252,28 @@ fn should_confirm_transaction_and_dispatch() {
|
||||
data: vec![],
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
}),
|
||||
Origin::Unknown,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::zero(),
|
||||
gas_price: U256::from(0x1000),
|
||||
gas: U256::from(0x50505),
|
||||
action: Action::Call(recipient),
|
||||
value: U256::from(0x1),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
tester
|
||||
.accounts
|
||||
.unlock_account_temporarily(address, "test".into())
|
||||
.unwrap();
|
||||
let signature = tester.accounts.sign(address, None, t.hash(None)).unwrap();
|
||||
let signature = tester
|
||||
.accounts
|
||||
.sign(address, None, t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
assert_eq!(tester.signer.requests().len(), 1);
|
||||
@ -297,6 +307,7 @@ fn should_alter_the_sender_and_nonce() {
|
||||
.signer
|
||||
.add_request(
|
||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: 0.into(),
|
||||
used_default_from: false,
|
||||
to: Some(recipient),
|
||||
@ -306,24 +317,25 @@ fn should_alter_the_sender_and_nonce() {
|
||||
data: vec![],
|
||||
nonce: Some(10.into()),
|
||||
condition: None,
|
||||
access_list: None,
|
||||
}),
|
||||
Origin::Unknown,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::zero(),
|
||||
gas_price: U256::from(0x1000),
|
||||
gas: U256::from(0x50505),
|
||||
action: Action::Call(recipient),
|
||||
value: U256::from(0x1),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
|
||||
let address = tester.accounts.new_account(&"test".into()).unwrap();
|
||||
let signature = tester
|
||||
.accounts
|
||||
.sign(address, Some("test".into()), t.hash(None))
|
||||
.sign(address, Some("test".into()), t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
@ -361,6 +373,7 @@ fn should_confirm_transaction_with_token() {
|
||||
.signer
|
||||
.add_request(
|
||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: address,
|
||||
used_default_from: false,
|
||||
to: Some(recipient),
|
||||
@ -370,22 +383,23 @@ fn should_confirm_transaction_with_token() {
|
||||
data: vec![],
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
}),
|
||||
Origin::Unknown,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::zero(),
|
||||
gas_price: U256::from(0x1000),
|
||||
gas: U256::from(10_000_000),
|
||||
action: Action::Call(recipient),
|
||||
value: U256::from(0x1),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
let (signature, token) = tester
|
||||
.accounts
|
||||
.sign_with_token(address, "test".into(), t.hash(None))
|
||||
.sign_with_token(address, "test".into(), t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
@ -427,6 +441,7 @@ fn should_confirm_transaction_with_rlp() {
|
||||
.signer
|
||||
.add_request(
|
||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: address,
|
||||
used_default_from: false,
|
||||
to: Some(recipient),
|
||||
@ -436,25 +451,26 @@ fn should_confirm_transaction_with_rlp() {
|
||||
data: vec![],
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
}),
|
||||
Origin::Unknown,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::zero(),
|
||||
gas_price: U256::from(0x1000),
|
||||
gas: U256::from(10_000_000),
|
||||
action: Action::Call(recipient),
|
||||
value: U256::from(0x1),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
let signature = tester
|
||||
.accounts
|
||||
.sign(address, Some("test".into()), t.hash(None))
|
||||
.sign(address, Some("test".into()), t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
let rlp = encode(&t);
|
||||
let rlp = t.encode();
|
||||
|
||||
assert_eq!(tester.signer.requests().len(), 1);
|
||||
|
||||
@ -491,6 +507,7 @@ fn should_return_error_when_sender_does_not_match() {
|
||||
.signer
|
||||
.add_request(
|
||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Address::default(),
|
||||
used_default_from: false,
|
||||
to: Some(recipient),
|
||||
@ -500,26 +517,30 @@ fn should_return_error_when_sender_does_not_match() {
|
||||
data: vec![],
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
}),
|
||||
Origin::Unknown,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::zero(),
|
||||
gas_price: U256::from(0x1000),
|
||||
gas: U256::from(10_000_000),
|
||||
action: Action::Call(recipient),
|
||||
value: U256::from(0x1),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
tester
|
||||
.accounts
|
||||
.unlock_account_temporarily(address, "test".into())
|
||||
.unwrap();
|
||||
let signature = tester.accounts.sign(address, None, t.hash(None)).unwrap();
|
||||
let signature = tester
|
||||
.accounts
|
||||
.sign(address, None, t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
let rlp = encode(&t);
|
||||
let rlp = t.encode();
|
||||
|
||||
assert_eq!(tester.signer.requests().len(), 1);
|
||||
|
||||
@ -553,6 +574,7 @@ fn should_confirm_sign_transaction_with_rlp() {
|
||||
.signer
|
||||
.add_request(
|
||||
ConfirmationPayload::SignTransaction(FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: address,
|
||||
used_default_from: false,
|
||||
to: Some(recipient),
|
||||
@ -562,26 +584,27 @@ fn should_confirm_sign_transaction_with_rlp() {
|
||||
data: vec![],
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
}),
|
||||
Origin::Unknown,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(tester.signer.requests().len(), 1);
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::zero(),
|
||||
gas_price: U256::from(0x1000),
|
||||
gas: U256::from(10_000_000),
|
||||
action: Action::Call(recipient),
|
||||
value: U256::from(0x1),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
let signature = tester
|
||||
.accounts
|
||||
.sign(address, Some("test".into()), t.hash(None))
|
||||
.sign(address, Some("test".into()), t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = SignedTransaction::new(t.with_signature(signature.clone(), None)).unwrap();
|
||||
let rlp = encode(&t);
|
||||
let rlp = t.encode();
|
||||
|
||||
// when
|
||||
let request = r#"{
|
||||
|
@ -14,7 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use rlp;
|
||||
use std::{str::FromStr, sync::Arc, thread, time::Duration};
|
||||
|
||||
use jsonrpc_core::{futures::Future, IoHandler, Success};
|
||||
@ -40,7 +39,7 @@ use ethstore::ethkey::{Generator, Random};
|
||||
use parity_runtime::{Executor, Runtime};
|
||||
use parking_lot::Mutex;
|
||||
use serde_json;
|
||||
use types::transaction::{Action, SignedTransaction, Transaction};
|
||||
use types::transaction::{Action, SignedTransaction, Transaction, TypedTransaction};
|
||||
|
||||
struct SigningTester {
|
||||
pub runtime: Runtime,
|
||||
@ -379,7 +378,7 @@ fn should_add_sign_transaction_to_the_queue() {
|
||||
"id": 1
|
||||
}"#;
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::one(),
|
||||
gas_price: U256::from(0x9184e72a000u64),
|
||||
gas: U256::from(0x76c0),
|
||||
@ -388,15 +387,15 @@ fn should_add_sign_transaction_to_the_queue() {
|
||||
),
|
||||
value: U256::from(0x9184e72au64),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
let signature = tester
|
||||
.accounts
|
||||
.sign(address, Some("test".into()), t.hash(None))
|
||||
.sign(address, Some("test".into()), t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
let t = SignedTransaction::new(t).unwrap();
|
||||
let signature = t.signature();
|
||||
let rlp = rlp::encode(&t);
|
||||
let rlp = t.encode();
|
||||
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"#.to_owned()
|
||||
+ r#""raw":"0x"#
|
||||
@ -459,7 +458,7 @@ fn should_dispatch_transaction_if_account_is_unlock() {
|
||||
.unlock_account_permanently(acc, "test".into())
|
||||
.unwrap();
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::zero(),
|
||||
gas_price: U256::from(0x9184e72a000u64),
|
||||
gas: U256::from(0x76c0),
|
||||
@ -468,8 +467,11 @@ fn should_dispatch_transaction_if_account_is_unlock() {
|
||||
),
|
||||
value: U256::from(0x9184e72au64),
|
||||
data: vec![],
|
||||
};
|
||||
let signature = tester.accounts.sign(acc, None, t.hash(None)).unwrap();
|
||||
});
|
||||
let signature = tester
|
||||
.accounts
|
||||
.sign(acc, None, t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
// when
|
||||
|
@ -21,9 +21,7 @@ use ethcore::client::TestBlockChainClient;
|
||||
use ethereum_types::{Address, U256};
|
||||
use parity_runtime::Runtime;
|
||||
use parking_lot::Mutex;
|
||||
use rlp;
|
||||
use rustc_hex::ToHex;
|
||||
use types::transaction::{Action, Transaction};
|
||||
use types::transaction::{Action, Transaction, TypedTransaction};
|
||||
|
||||
use jsonrpc_core::IoHandler;
|
||||
use v1::{
|
||||
@ -117,7 +115,7 @@ fn rpc_eth_send_transaction() {
|
||||
"id": 1
|
||||
}"#;
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::zero(),
|
||||
gas_price: U256::from(0x9184e72a000u64),
|
||||
gas: U256::from(0x76c0),
|
||||
@ -126,10 +124,10 @@ fn rpc_eth_send_transaction() {
|
||||
),
|
||||
value: U256::from(0x9184e72au64),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
let signature = tester
|
||||
.accounts_provider
|
||||
.sign(address, None, t.hash(None))
|
||||
.sign(address, None, t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
@ -141,7 +139,7 @@ fn rpc_eth_send_transaction() {
|
||||
|
||||
tester.miner.increment_nonce(&address);
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::one(),
|
||||
gas_price: U256::from(0x9184e72a000u64),
|
||||
gas: U256::from(0x76c0),
|
||||
@ -150,10 +148,10 @@ fn rpc_eth_send_transaction() {
|
||||
),
|
||||
value: U256::from(0x9184e72au64),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
let signature = tester
|
||||
.accounts_provider
|
||||
.sign(address, None, t.hash(None))
|
||||
.sign(address, None, t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
|
||||
@ -166,6 +164,7 @@ fn rpc_eth_send_transaction() {
|
||||
|
||||
#[test]
|
||||
fn rpc_eth_sign_transaction() {
|
||||
use rustc_hex::ToHex;
|
||||
let tester = EthTester::default();
|
||||
let address = tester.accounts_provider.new_account(&"".into()).unwrap();
|
||||
tester
|
||||
@ -188,7 +187,7 @@ fn rpc_eth_sign_transaction() {
|
||||
"id": 1
|
||||
}"#;
|
||||
|
||||
let t = Transaction {
|
||||
let t = TypedTransaction::Legacy(Transaction {
|
||||
nonce: U256::one(),
|
||||
gas_price: U256::from(0x9184e72a000u64),
|
||||
gas: U256::from(0x76c0),
|
||||
@ -197,14 +196,14 @@ fn rpc_eth_sign_transaction() {
|
||||
),
|
||||
value: U256::from(0x9184e72au64),
|
||||
data: vec![],
|
||||
};
|
||||
});
|
||||
let signature = tester
|
||||
.accounts_provider
|
||||
.sign(address, None, t.hash(None))
|
||||
.sign(address, None, t.signature_hash(None))
|
||||
.unwrap();
|
||||
let t = t.with_signature(signature, None);
|
||||
let signature = t.signature();
|
||||
let rlp = rlp::encode(&t);
|
||||
let rlp = t.encode();
|
||||
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"#.to_owned()
|
||||
+ r#""raw":"0x"#
|
||||
|
@ -15,6 +15,7 @@
|
||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use ethereum_types::{H160, U256};
|
||||
use types::transaction::{AccessList, TypedTxId};
|
||||
use v1::{helpers::CallRequest as Request, types::Bytes};
|
||||
|
||||
/// Call request
|
||||
@ -22,6 +23,9 @@ use v1::{helpers::CallRequest as Request, types::Bytes};
|
||||
#[serde(deny_unknown_fields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CallRequest {
|
||||
/// transaction type
|
||||
#[serde(default)]
|
||||
pub tx_type: TypedTxId,
|
||||
/// From
|
||||
pub from: Option<H160>,
|
||||
/// To
|
||||
@ -36,11 +40,14 @@ pub struct CallRequest {
|
||||
pub data: Option<Bytes>,
|
||||
/// Nonce
|
||||
pub nonce: Option<U256>,
|
||||
/// Access list
|
||||
pub access_list: Option<AccessList>,
|
||||
}
|
||||
|
||||
impl Into<Request> for CallRequest {
|
||||
fn into(self) -> Request {
|
||||
Request {
|
||||
tx_type: self.tx_type,
|
||||
from: self.from.map(Into::into),
|
||||
to: self.to.map(Into::into),
|
||||
gas_price: self.gas_price.map(Into::into),
|
||||
@ -48,6 +55,7 @@ impl Into<Request> for CallRequest {
|
||||
value: self.value.map(Into::into),
|
||||
data: self.data.map(Into::into),
|
||||
nonce: self.nonce.map(Into::into),
|
||||
access_list: self.access_list.map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -76,6 +84,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
deserialized,
|
||||
CallRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Some(H160::from(1)),
|
||||
to: Some(H160::from(2)),
|
||||
gas_price: Some(U256::from(1)),
|
||||
@ -83,6 +92,7 @@ mod tests {
|
||||
value: Some(U256::from(3)),
|
||||
data: Some(vec![0x12, 0x34, 0x56].into()),
|
||||
nonce: Some(U256::from(4)),
|
||||
access_list: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -100,13 +110,15 @@ mod tests {
|
||||
let deserialized: CallRequest = serde_json::from_str(s).unwrap();
|
||||
|
||||
assert_eq!(deserialized, CallRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Some(H160::from_str("b60e8dd61c5d32be8058bb8eb970870f07233155").unwrap()),
|
||||
to: Some(H160::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||
gas_price: Some(U256::from_str("9184e72a000").unwrap()),
|
||||
gas: Some(U256::from_str("76c0").unwrap()),
|
||||
value: Some(U256::from_str("9184e72a").unwrap()),
|
||||
data: Some("d46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675".from_hex().unwrap().into()),
|
||||
nonce: None
|
||||
nonce: None,
|
||||
access_list: None,
|
||||
});
|
||||
}
|
||||
|
||||
@ -118,6 +130,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
deserialized,
|
||||
CallRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Some(H160::from(1)),
|
||||
to: None,
|
||||
gas_price: None,
|
||||
@ -125,6 +138,7 @@ mod tests {
|
||||
value: None,
|
||||
data: None,
|
||||
nonce: None,
|
||||
access_list: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -331,6 +331,7 @@ mod tests {
|
||||
id: 15.into(),
|
||||
payload: helpers::ConfirmationPayload::SendTransaction(
|
||||
helpers::FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: 0.into(),
|
||||
used_default_from: false,
|
||||
to: None,
|
||||
@ -340,6 +341,7 @@ mod tests {
|
||||
data: vec![1, 2, 3],
|
||||
nonce: Some(1.into()),
|
||||
condition: None,
|
||||
access_list: None,
|
||||
},
|
||||
),
|
||||
origin: Origin::Signer { session: 5.into() },
|
||||
@ -360,6 +362,7 @@ mod tests {
|
||||
id: 15.into(),
|
||||
payload: helpers::ConfirmationPayload::SignTransaction(
|
||||
helpers::FilledTransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: 0.into(),
|
||||
used_default_from: false,
|
||||
to: None,
|
||||
@ -369,6 +372,7 @@ mod tests {
|
||||
data: vec![1, 2, 3],
|
||||
nonce: Some(1.into()),
|
||||
condition: None,
|
||||
access_list: None,
|
||||
},
|
||||
),
|
||||
origin: Origin::Unknown,
|
||||
|
@ -15,13 +15,19 @@
|
||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use ethereum_types::{Bloom as H2048, H160, H256, U256, U64};
|
||||
use types::receipt::{LocalizedReceipt, Receipt as EthReceipt, RichReceipt, TransactionOutcome};
|
||||
use types::{
|
||||
receipt::{LocalizedReceipt, RichReceipt, TransactionOutcome, TypedReceipt},
|
||||
transaction::TypedTxId,
|
||||
};
|
||||
use v1::types::Log;
|
||||
|
||||
/// Receipt
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Receipt {
|
||||
/// Transaction Type
|
||||
#[serde(skip_serializing)]
|
||||
pub transaction_type: TypedTxId,
|
||||
/// Transaction Hash
|
||||
pub transaction_hash: Option<H256>,
|
||||
/// Transaction index
|
||||
@ -75,6 +81,7 @@ impl From<LocalizedReceipt> for Receipt {
|
||||
Receipt {
|
||||
to: r.to.map(Into::into),
|
||||
from: Some(r.from),
|
||||
transaction_type: r.transaction_type,
|
||||
transaction_hash: Some(r.transaction_hash),
|
||||
transaction_index: Some(r.transaction_index.into()),
|
||||
block_hash: Some(r.block_hash),
|
||||
@ -95,6 +102,7 @@ impl From<RichReceipt> for Receipt {
|
||||
Receipt {
|
||||
from: Some(r.from),
|
||||
to: r.to.map(Into::into),
|
||||
transaction_type: r.transaction_type,
|
||||
transaction_hash: Some(r.transaction_hash),
|
||||
transaction_index: Some(r.transaction_index.into()),
|
||||
block_hash: None,
|
||||
@ -110,11 +118,14 @@ impl From<RichReceipt> for Receipt {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EthReceipt> for Receipt {
|
||||
fn from(r: EthReceipt) -> Self {
|
||||
impl From<TypedReceipt> for Receipt {
|
||||
fn from(r: TypedReceipt) -> Self {
|
||||
let transaction_type = r.tx_type();
|
||||
let r = r.receipt().clone();
|
||||
Receipt {
|
||||
from: None,
|
||||
to: None,
|
||||
transaction_type,
|
||||
transaction_hash: None,
|
||||
transaction_index: None,
|
||||
block_hash: None,
|
||||
@ -142,6 +153,7 @@ mod tests {
|
||||
let receipt = Receipt {
|
||||
from: None,
|
||||
to: None,
|
||||
transaction_type: Default::default(),
|
||||
transaction_hash: Some(0.into()),
|
||||
transaction_index: Some(0.into()),
|
||||
block_hash: Some(
|
||||
|
@ -20,7 +20,10 @@ use ethcore::{contract_address, CreateContractAddress};
|
||||
use ethereum_types::{H160, H256, H512, U256, U64};
|
||||
use miner;
|
||||
use serde::{ser::SerializeStruct, Serialize, Serializer};
|
||||
use types::transaction::{Action, LocalizedTransaction, PendingTransaction, SignedTransaction};
|
||||
use types::transaction::{
|
||||
AccessList, Action, LocalizedTransaction, PendingTransaction, SignedTransaction,
|
||||
TypedTransaction,
|
||||
};
|
||||
use v1::types::{Bytes, TransactionCondition};
|
||||
|
||||
/// Transaction
|
||||
@ -67,6 +70,12 @@ pub struct Transaction {
|
||||
pub s: U256,
|
||||
/// Transaction activates at specified block.
|
||||
pub condition: Option<TransactionCondition>,
|
||||
/// transaction type
|
||||
#[serde(skip_serializing)]
|
||||
pub transaction_type: u8,
|
||||
/// optional access list
|
||||
#[serde(skip_serializing)]
|
||||
pub access_list: AccessList,
|
||||
}
|
||||
|
||||
/// Local Transaction Status
|
||||
@ -176,26 +185,35 @@ impl Transaction {
|
||||
pub fn from_localized(mut t: LocalizedTransaction) -> Transaction {
|
||||
let signature = t.signature();
|
||||
let scheme = CreateContractAddress::FromSenderAndNonce;
|
||||
|
||||
let access_list = if let TypedTransaction::AccessList(al) = t.as_unsigned() {
|
||||
al.access_list.clone()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
Transaction {
|
||||
hash: t.hash(),
|
||||
nonce: t.nonce,
|
||||
nonce: t.tx().nonce,
|
||||
block_hash: Some(t.block_hash),
|
||||
block_number: Some(t.block_number.into()),
|
||||
transaction_index: Some(t.transaction_index.into()),
|
||||
from: t.sender(),
|
||||
to: match t.action {
|
||||
to: match t.tx().action {
|
||||
Action::Create => None,
|
||||
Action::Call(ref address) => Some(*address),
|
||||
},
|
||||
value: t.value,
|
||||
gas_price: t.gas_price,
|
||||
gas: t.gas,
|
||||
input: Bytes::new(t.data.clone()),
|
||||
creates: match t.action {
|
||||
Action::Create => Some(contract_address(scheme, &t.sender(), &t.nonce, &t.data).0),
|
||||
value: t.tx().value,
|
||||
gas_price: t.tx().gas_price,
|
||||
gas: t.tx().gas,
|
||||
input: Bytes::new(t.tx().data.clone()),
|
||||
creates: match t.tx().action {
|
||||
Action::Create => {
|
||||
Some(contract_address(scheme, &t.sender(), &t.tx().nonce, &t.tx().data).0)
|
||||
}
|
||||
Action::Call(_) => None,
|
||||
},
|
||||
raw: ::rlp::encode(&t.signed).into(),
|
||||
raw: Bytes::new(t.signed.encode()),
|
||||
public_key: t.recover_public().ok().map(Into::into),
|
||||
chain_id: t.chain_id().map(U64::from),
|
||||
standard_v: t.standard_v().into(),
|
||||
@ -203,6 +221,8 @@ impl Transaction {
|
||||
r: signature.r().into(),
|
||||
s: signature.s().into(),
|
||||
condition: None,
|
||||
transaction_type: t.signed.tx_type() as u8,
|
||||
access_list,
|
||||
}
|
||||
}
|
||||
|
||||
@ -210,26 +230,33 @@ impl Transaction {
|
||||
pub fn from_signed(t: SignedTransaction) -> Transaction {
|
||||
let signature = t.signature();
|
||||
let scheme = CreateContractAddress::FromSenderAndNonce;
|
||||
let access_list = if let TypedTransaction::AccessList(al) = t.as_unsigned() {
|
||||
al.access_list.clone()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
Transaction {
|
||||
hash: t.hash(),
|
||||
nonce: t.nonce,
|
||||
nonce: t.tx().nonce,
|
||||
block_hash: None,
|
||||
block_number: None,
|
||||
transaction_index: None,
|
||||
from: t.sender(),
|
||||
to: match t.action {
|
||||
to: match t.tx().action {
|
||||
Action::Create => None,
|
||||
Action::Call(ref address) => Some(*address),
|
||||
},
|
||||
value: t.value,
|
||||
gas_price: t.gas_price,
|
||||
gas: t.gas,
|
||||
input: Bytes::new(t.data.clone()),
|
||||
creates: match t.action {
|
||||
Action::Create => Some(contract_address(scheme, &t.sender(), &t.nonce, &t.data).0),
|
||||
value: t.tx().value,
|
||||
gas_price: t.tx().gas_price,
|
||||
gas: t.tx().gas,
|
||||
input: Bytes::new(t.tx().data.clone()),
|
||||
creates: match t.tx().action {
|
||||
Action::Create => {
|
||||
Some(contract_address(scheme, &t.sender(), &t.tx().nonce, &t.tx().data).0)
|
||||
}
|
||||
Action::Call(_) => None,
|
||||
},
|
||||
raw: ::rlp::encode(&t).into(),
|
||||
raw: t.encode().into(),
|
||||
public_key: t.public_key().map(Into::into),
|
||||
chain_id: t.chain_id().map(U64::from),
|
||||
standard_v: t.standard_v().into(),
|
||||
@ -237,6 +264,8 @@ impl Transaction {
|
||||
r: signature.r().into(),
|
||||
s: signature.s().into(),
|
||||
condition: None,
|
||||
transaction_type: t.tx_type() as u8,
|
||||
access_list,
|
||||
}
|
||||
}
|
||||
|
||||
@ -265,7 +294,7 @@ impl LocalTransactionStatus {
|
||||
Canceled(tx) => LocalTransactionStatus::Canceled(convert(tx)),
|
||||
Replaced { old, new } => LocalTransactionStatus::Replaced(
|
||||
convert(old),
|
||||
new.signed().gas_price,
|
||||
new.signed().tx().gas_price,
|
||||
new.signed().hash(),
|
||||
),
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
use ansi_term::Colour;
|
||||
use ethereum_types::{H160, U256};
|
||||
use types::transaction::{AccessList, TypedTxId};
|
||||
use v1::{
|
||||
helpers,
|
||||
types::{Bytes, TransactionCondition},
|
||||
@ -30,6 +31,10 @@ use std::fmt;
|
||||
#[serde(deny_unknown_fields)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TransactionRequest {
|
||||
/// type of transaction. If none we assume it is legacy
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing)]
|
||||
pub tx_type: TypedTxId,
|
||||
/// Sender
|
||||
pub from: Option<H160>,
|
||||
/// Recipient
|
||||
@ -46,6 +51,9 @@ pub struct TransactionRequest {
|
||||
pub nonce: Option<U256>,
|
||||
/// Delay until this block condition.
|
||||
pub condition: Option<TransactionCondition>,
|
||||
/// Access list
|
||||
#[serde(skip_serializing)]
|
||||
pub access_list: Option<AccessList>,
|
||||
}
|
||||
|
||||
pub fn format_ether(i: U256) -> String {
|
||||
@ -97,6 +105,7 @@ impl fmt::Display for TransactionRequest {
|
||||
impl From<helpers::TransactionRequest> for TransactionRequest {
|
||||
fn from(r: helpers::TransactionRequest) -> Self {
|
||||
TransactionRequest {
|
||||
tx_type: r.tx_type,
|
||||
from: r.from.map(Into::into),
|
||||
to: r.to.map(Into::into),
|
||||
gas_price: r.gas_price.map(Into::into),
|
||||
@ -105,6 +114,7 @@ impl From<helpers::TransactionRequest> for TransactionRequest {
|
||||
data: r.data.map(Into::into),
|
||||
nonce: r.nonce.map(Into::into),
|
||||
condition: r.condition.map(Into::into),
|
||||
access_list: r.access_list.map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -112,6 +122,7 @@ impl From<helpers::TransactionRequest> for TransactionRequest {
|
||||
impl From<helpers::FilledTransactionRequest> for TransactionRequest {
|
||||
fn from(r: helpers::FilledTransactionRequest) -> Self {
|
||||
TransactionRequest {
|
||||
tx_type: r.tx_type,
|
||||
from: Some(r.from),
|
||||
to: r.to,
|
||||
gas_price: Some(r.gas_price),
|
||||
@ -120,6 +131,7 @@ impl From<helpers::FilledTransactionRequest> for TransactionRequest {
|
||||
data: Some(r.data.into()),
|
||||
nonce: r.nonce,
|
||||
condition: r.condition,
|
||||
access_list: r.access_list,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -127,6 +139,7 @@ impl From<helpers::FilledTransactionRequest> for TransactionRequest {
|
||||
impl Into<helpers::TransactionRequest> for TransactionRequest {
|
||||
fn into(self) -> helpers::TransactionRequest {
|
||||
helpers::TransactionRequest {
|
||||
tx_type: self.tx_type,
|
||||
from: self.from.map(Into::into),
|
||||
to: self.to.map(Into::into),
|
||||
gas_price: self.gas_price.map(Into::into),
|
||||
@ -135,6 +148,7 @@ impl Into<helpers::TransactionRequest> for TransactionRequest {
|
||||
data: self.data.map(Into::into),
|
||||
nonce: self.nonce.map(Into::into),
|
||||
condition: self.condition.map(Into::into),
|
||||
access_list: self.access_list.map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -165,6 +179,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
deserialized,
|
||||
TransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Some(H160::from(1)),
|
||||
to: Some(H160::from(2)),
|
||||
gas_price: Some(U256::from(1)),
|
||||
@ -173,6 +188,7 @@ mod tests {
|
||||
data: Some(vec![0x12, 0x34, 0x56].into()),
|
||||
nonce: Some(U256::from(4)),
|
||||
condition: Some(TransactionCondition::Number(0x13)),
|
||||
access_list: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -190,6 +206,7 @@ mod tests {
|
||||
let deserialized: TransactionRequest = serde_json::from_str(s).unwrap();
|
||||
|
||||
assert_eq!(deserialized, TransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Some(H160::from_str("b60e8dd61c5d32be8058bb8eb970870f07233155").unwrap()),
|
||||
to: Some(H160::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||
gas_price: Some(U256::from_str("9184e72a000").unwrap()),
|
||||
@ -198,6 +215,7 @@ mod tests {
|
||||
data: Some("d46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675".from_hex().unwrap().into()),
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
});
|
||||
}
|
||||
|
||||
@ -209,6 +227,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
deserialized,
|
||||
TransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Some(H160::from(1).into()),
|
||||
to: None,
|
||||
gas_price: None,
|
||||
@ -217,6 +236,7 @@ mod tests {
|
||||
data: None,
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -236,6 +256,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
deserialized,
|
||||
TransactionRequest {
|
||||
tx_type: Default::default(),
|
||||
from: Some(H160::from_str("b5f7502a2807cb23615c7456055e1d65b2508625").unwrap()),
|
||||
to: Some(H160::from_str("895d32f2db7d01ebb50053f9e48aacf26584fe40").unwrap()),
|
||||
gas_price: Some(U256::from_str("0ba43b7400").unwrap()),
|
||||
@ -244,6 +265,7 @@ mod tests {
|
||||
data: Some(vec![0x85, 0x95, 0xba, 0xb1].into()),
|
||||
nonce: None,
|
||||
condition: None,
|
||||
access_list: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
use bytes::Bytes;
|
||||
use call_contract::RegistryInfo;
|
||||
use common_types::transaction::{Action, SignedTransaction, Transaction};
|
||||
use common_types::transaction::{Action, SignedTransaction, Transaction, TypedTransaction};
|
||||
use ethcore::{
|
||||
client::{BlockChainClient, BlockId, ChainInfo, Client, Nonce},
|
||||
miner::{Miner, MinerService},
|
||||
@ -89,16 +89,18 @@ impl TrustedClient {
|
||||
.upgrade()
|
||||
.ok_or_else(|| Error::Internal("cannot submit tx when miner is offline".into()))?;
|
||||
let engine = client.engine();
|
||||
let transaction = Transaction {
|
||||
let transaction = TypedTransaction::Legacy(Transaction {
|
||||
nonce: client.latest_nonce(&self.self_key_pair.address()),
|
||||
action: Action::Call(contract),
|
||||
gas: miner.authoring_params().gas_range_target.0,
|
||||
gas_price: miner.sensible_gas_price(),
|
||||
value: Default::default(),
|
||||
data: tx_data,
|
||||
};
|
||||
});
|
||||
let chain_id = engine.signing_chain_id(&client.latest_env_info());
|
||||
let signature = self.self_key_pair.sign(&transaction.hash(chain_id))?;
|
||||
let signature = self
|
||||
.self_key_pair
|
||||
.sign(&transaction.signature_hash(chain_id))?;
|
||||
let signed = SignedTransaction::new(transaction.with_signature(signature, chain_id))?;
|
||||
miner
|
||||
.import_own_transaction(&*client, signed.into())
|
||||
|
Loading…
Reference in New Issue
Block a user