TypedTransaction (EIP-2718) and Optional access list (EIP-2930) (#135)
This commit is contained in:
parent
1bce9fa76d
commit
fb975731bb
14
Cargo.lock
generated
14
Cargo.lock
generated
@ -447,6 +447,9 @@ dependencies = [
|
|||||||
"rlp 0.3.0",
|
"rlp 0.3.0",
|
||||||
"rlp_derive",
|
"rlp_derive",
|
||||||
"rustc-hex 1.0.0",
|
"rustc-hex 1.0.0",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_repr",
|
||||||
"unexpected",
|
"unexpected",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4274,6 +4277,17 @@ dependencies = [
|
|||||||
"serde",
|
"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]]
|
[[package]]
|
||||||
name = "sha-1"
|
name = "sha-1"
|
||||||
version = "0.8.1"
|
version = "0.8.1"
|
||||||
|
@ -34,7 +34,7 @@ use common_types::{
|
|||||||
},
|
},
|
||||||
header::{ExtendedHeader, Header},
|
header::{ExtendedHeader, Header},
|
||||||
log_entry::{LocalizedLogEntry, LogEntry},
|
log_entry::{LocalizedLogEntry, LogEntry},
|
||||||
receipt::Receipt,
|
receipt::TypedReceipt,
|
||||||
transaction::LocalizedTransaction,
|
transaction::LocalizedTransaction,
|
||||||
tree_route::TreeRoute,
|
tree_route::TreeRoute,
|
||||||
view,
|
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());
|
warn!("Block {} ({}) has different number of receipts ({}) to transactions ({}). Database corrupt?", number, hash, receipts.len(), hashes.len());
|
||||||
assert!(false);
|
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();
|
let receipts_len = receipts.len();
|
||||||
hashes.reverse();
|
hashes.reverse();
|
||||||
receipts.reverse();
|
receipts.reverse();
|
||||||
receipts.into_iter()
|
receipts.into_iter()
|
||||||
.map(|receipt| receipt.logs)
|
.map(|receipt| receipt.receipt().logs.clone())
|
||||||
.zip(hashes)
|
.zip(hashes)
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.flat_map(move |(index, (mut logs, tx_hash))| {
|
.flat_map(move |(index, (mut logs, tx_hash))| {
|
||||||
@ -895,7 +895,7 @@ impl BlockChain {
|
|||||||
&self,
|
&self,
|
||||||
batch: &mut DBTransaction,
|
batch: &mut DBTransaction,
|
||||||
block: encoded::Block,
|
block: encoded::Block,
|
||||||
receipts: Vec<Receipt>,
|
receipts: Vec<TypedReceipt>,
|
||||||
parent_td: Option<U256>,
|
parent_td: Option<U256>,
|
||||||
is_best: bool,
|
is_best: bool,
|
||||||
is_ancient: bool,
|
is_ancient: bool,
|
||||||
@ -1265,7 +1265,7 @@ impl BlockChain {
|
|||||||
&self,
|
&self,
|
||||||
batch: &mut DBTransaction,
|
batch: &mut DBTransaction,
|
||||||
block: encoded::Block,
|
block: encoded::Block,
|
||||||
receipts: Vec<Receipt>,
|
receipts: Vec<TypedReceipt>,
|
||||||
extras: ExtrasInsert,
|
extras: ExtrasInsert,
|
||||||
) -> ImportRoute {
|
) -> ImportRoute {
|
||||||
let parent_hash = block.header_view().parent_hash();
|
let parent_hash = block.header_view().parent_hash();
|
||||||
@ -1283,7 +1283,7 @@ impl BlockChain {
|
|||||||
&self,
|
&self,
|
||||||
batch: &mut DBTransaction,
|
batch: &mut DBTransaction,
|
||||||
block: encoded::Block,
|
block: encoded::Block,
|
||||||
receipts: Vec<Receipt>,
|
receipts: Vec<TypedReceipt>,
|
||||||
route: TreeRoute,
|
route: TreeRoute,
|
||||||
extras: ExtrasInsert,
|
extras: ExtrasInsert,
|
||||||
) -> ImportRoute {
|
) -> ImportRoute {
|
||||||
@ -1659,7 +1659,7 @@ impl BlockChain {
|
|||||||
/// This function returns modified block receipts.
|
/// This function returns modified block receipts.
|
||||||
fn prepare_block_receipts_update(
|
fn prepare_block_receipts_update(
|
||||||
&self,
|
&self,
|
||||||
receipts: Vec<Receipt>,
|
receipts: Vec<TypedReceipt>,
|
||||||
info: &BlockInfo,
|
info: &BlockInfo,
|
||||||
) -> HashMap<H256, BlockReceipts> {
|
) -> HashMap<H256, BlockReceipts> {
|
||||||
let mut block_receipts = HashMap::new();
|
let mut block_receipts = HashMap::new();
|
||||||
@ -1921,8 +1921,8 @@ mod tests {
|
|||||||
|
|
||||||
use crate::generator::{BlockBuilder, BlockGenerator, BlockOptions};
|
use crate::generator::{BlockBuilder, BlockGenerator, BlockOptions};
|
||||||
use common_types::{
|
use common_types::{
|
||||||
receipt::{Receipt, TransactionOutcome},
|
receipt::{LegacyReceipt, TransactionOutcome, TypedReceipt},
|
||||||
transaction::{Action, Transaction},
|
transaction::{Action, Transaction, TypedTransaction},
|
||||||
};
|
};
|
||||||
use ethkey::Secret;
|
use ethkey::Secret;
|
||||||
use keccak_hash::keccak;
|
use keccak_hash::keccak;
|
||||||
@ -1975,7 +1975,7 @@ mod tests {
|
|||||||
db: &Arc<dyn BlockChainDB>,
|
db: &Arc<dyn BlockChainDB>,
|
||||||
bc: &BlockChain,
|
bc: &BlockChain,
|
||||||
block: encoded::Block,
|
block: encoded::Block,
|
||||||
receipts: Vec<Receipt>,
|
receipts: Vec<TypedReceipt>,
|
||||||
) -> ImportRoute {
|
) -> ImportRoute {
|
||||||
insert_block_commit(db, bc, block, receipts, true)
|
insert_block_commit(db, bc, block, receipts, true)
|
||||||
}
|
}
|
||||||
@ -1984,7 +1984,7 @@ mod tests {
|
|||||||
db: &Arc<dyn BlockChainDB>,
|
db: &Arc<dyn BlockChainDB>,
|
||||||
bc: &BlockChain,
|
bc: &BlockChain,
|
||||||
block: encoded::Block,
|
block: encoded::Block,
|
||||||
receipts: Vec<Receipt>,
|
receipts: Vec<TypedReceipt>,
|
||||||
commit: bool,
|
commit: bool,
|
||||||
) -> ImportRoute {
|
) -> ImportRoute {
|
||||||
let mut batch = db.key_value().transaction();
|
let mut batch = db.key_value().transaction();
|
||||||
@ -2000,7 +2000,7 @@ mod tests {
|
|||||||
batch: &mut DBTransaction,
|
batch: &mut DBTransaction,
|
||||||
bc: &BlockChain,
|
bc: &BlockChain,
|
||||||
block: encoded::Block,
|
block: encoded::Block,
|
||||||
receipts: Vec<Receipt>,
|
receipts: Vec<TypedReceipt>,
|
||||||
) -> ImportRoute {
|
) -> ImportRoute {
|
||||||
let fork_choice = {
|
let fork_choice = {
|
||||||
let header = block.header_view();
|
let header = block.header_view();
|
||||||
@ -2157,7 +2157,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fork_transaction_addresses() {
|
fn test_fork_transaction_addresses() {
|
||||||
let t1 = Transaction {
|
let t1 = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
@ -2166,7 +2166,7 @@ mod tests {
|
|||||||
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
||||||
.from_hex()
|
.from_hex()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
|
|
||||||
let t1_hash = t1.hash();
|
let t1_hash = t1.hash();
|
||||||
@ -2211,7 +2211,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_overwriting_transaction_addresses() {
|
fn test_overwriting_transaction_addresses() {
|
||||||
let t1 = Transaction {
|
let t1 = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
@ -2220,10 +2220,10 @@ mod tests {
|
|||||||
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
||||||
.from_hex()
|
.from_hex()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
|
|
||||||
let t2 = Transaction {
|
let t2 = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 1.into(),
|
nonce: 1.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
@ -2232,10 +2232,10 @@ mod tests {
|
|||||||
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
||||||
.from_hex()
|
.from_hex()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
|
|
||||||
let t3 = Transaction {
|
let t3 = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 2.into(),
|
nonce: 2.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
@ -2244,7 +2244,7 @@ mod tests {
|
|||||||
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
||||||
.from_hex()
|
.from_hex()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
|
|
||||||
let genesis = BlockBuilder::genesis();
|
let genesis = BlockBuilder::genesis();
|
||||||
@ -2509,7 +2509,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_logs() {
|
fn test_logs() {
|
||||||
let t1 = Transaction {
|
let t1 = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
@ -2518,9 +2518,9 @@ mod tests {
|
|||||||
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
||||||
.from_hex()
|
.from_hex()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
let t2 = Transaction {
|
let t2 = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
@ -2529,9 +2529,9 @@ mod tests {
|
|||||||
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
||||||
.from_hex()
|
.from_hex()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
let t3 = Transaction {
|
let t3 = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
@ -2540,9 +2540,9 @@ mod tests {
|
|||||||
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
||||||
.from_hex()
|
.from_hex()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
let t4 = Transaction {
|
let t4 = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
@ -2551,7 +2551,7 @@ mod tests {
|
|||||||
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
data: "601080600c6000396000f3006000355415600957005b60203560003555"
|
||||||
.from_hex()
|
.from_hex()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
let tx_hash1 = t1.hash();
|
let tx_hash1 = t1.hash();
|
||||||
let tx_hash2 = t2.hash();
|
let tx_hash2 = t2.hash();
|
||||||
@ -2580,7 +2580,7 @@ mod tests {
|
|||||||
&bc,
|
&bc,
|
||||||
b1.last().encoded(),
|
b1.last().encoded(),
|
||||||
vec![
|
vec![
|
||||||
Receipt {
|
TypedReceipt::Legacy(LegacyReceipt {
|
||||||
outcome: TransactionOutcome::StateRoot(H256::default()),
|
outcome: TransactionOutcome::StateRoot(H256::default()),
|
||||||
gas_used: 10_000.into(),
|
gas_used: 10_000.into(),
|
||||||
log_bloom: Default::default(),
|
log_bloom: Default::default(),
|
||||||
@ -2596,8 +2596,8 @@ mod tests {
|
|||||||
data: vec![2],
|
data: vec![2],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
}),
|
||||||
Receipt {
|
TypedReceipt::Legacy(LegacyReceipt {
|
||||||
outcome: TransactionOutcome::StateRoot(H256::default()),
|
outcome: TransactionOutcome::StateRoot(H256::default()),
|
||||||
gas_used: 10_000.into(),
|
gas_used: 10_000.into(),
|
||||||
log_bloom: Default::default(),
|
log_bloom: Default::default(),
|
||||||
@ -2606,14 +2606,14 @@ mod tests {
|
|||||||
topics: vec![],
|
topics: vec![],
|
||||||
data: vec![3],
|
data: vec![3],
|
||||||
}],
|
}],
|
||||||
},
|
}),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
insert_block(
|
insert_block(
|
||||||
&db,
|
&db,
|
||||||
&bc,
|
&bc,
|
||||||
b2.last().encoded(),
|
b2.last().encoded(),
|
||||||
vec![Receipt {
|
vec![TypedReceipt::Legacy(LegacyReceipt {
|
||||||
outcome: TransactionOutcome::StateRoot(H256::default()),
|
outcome: TransactionOutcome::StateRoot(H256::default()),
|
||||||
gas_used: 10_000.into(),
|
gas_used: 10_000.into(),
|
||||||
log_bloom: Default::default(),
|
log_bloom: Default::default(),
|
||||||
@ -2622,13 +2622,13 @@ mod tests {
|
|||||||
topics: vec![],
|
topics: vec![],
|
||||||
data: vec![4],
|
data: vec![4],
|
||||||
}],
|
}],
|
||||||
}],
|
})],
|
||||||
);
|
);
|
||||||
insert_block(
|
insert_block(
|
||||||
&db,
|
&db,
|
||||||
&bc,
|
&bc,
|
||||||
b3.last().encoded(),
|
b3.last().encoded(),
|
||||||
vec![Receipt {
|
vec![TypedReceipt::Legacy(LegacyReceipt {
|
||||||
outcome: TransactionOutcome::StateRoot(H256::default()),
|
outcome: TransactionOutcome::StateRoot(H256::default()),
|
||||||
gas_used: 10_000.into(),
|
gas_used: 10_000.into(),
|
||||||
log_bloom: Default::default(),
|
log_bloom: Default::default(),
|
||||||
@ -2637,7 +2637,7 @@ mod tests {
|
|||||||
topics: vec![],
|
topics: vec![],
|
||||||
data: vec![5],
|
data: vec![5],
|
||||||
}],
|
}],
|
||||||
}],
|
})],
|
||||||
);
|
);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
|
@ -22,17 +22,16 @@ use std::collections::VecDeque;
|
|||||||
use common_types::{
|
use common_types::{
|
||||||
encoded,
|
encoded,
|
||||||
header::Header,
|
header::Header,
|
||||||
transaction::{Action, SignedTransaction, Transaction},
|
transaction::{Action, SignedTransaction, Transaction, TypedTransaction},
|
||||||
view,
|
view,
|
||||||
views::BlockView,
|
views::BlockView,
|
||||||
};
|
};
|
||||||
use keccak_hash::keccak;
|
use keccak_hash::keccak;
|
||||||
use rlp::encode;
|
use rlp::{encode, RlpStream};
|
||||||
use rlp_derive::RlpEncodable;
|
|
||||||
use triehash_ethereum::ordered_trie_root;
|
use triehash_ethereum::ordered_trie_root;
|
||||||
|
|
||||||
/// Helper structure, used for encoding blocks.
|
/// Helper structure, used for encoding blocks.
|
||||||
#[derive(Default, Clone, RlpEncodable)]
|
#[derive(Default, Clone)]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
/// Block header
|
/// Block header
|
||||||
pub header: Header,
|
pub header: Header,
|
||||||
@ -42,6 +41,15 @@ pub struct Block {
|
|||||||
pub uncles: Vec<Header>,
|
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 {
|
impl Block {
|
||||||
/// Get a copy of the header
|
/// Get a copy of the header
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -154,14 +162,14 @@ impl BlockBuilder {
|
|||||||
let data = std::iter::repeat_with(|| rand::random::<u8>())
|
let data = std::iter::repeat_with(|| rand::random::<u8>())
|
||||||
.take(data_len as usize)
|
.take(data_len as usize)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
Transaction {
|
TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data,
|
data,
|
||||||
}
|
})
|
||||||
.sign(&keccak("").into(), None)
|
.sign(&keccak("").into(), None)
|
||||||
})
|
})
|
||||||
.take(count);
|
.take(count);
|
||||||
@ -205,7 +213,7 @@ impl BlockBuilder {
|
|||||||
let metadata = get_metadata();
|
let metadata = get_metadata();
|
||||||
let block_number = parent_number + 1;
|
let block_number = parent_number + 1;
|
||||||
let transactions = metadata.transactions;
|
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_parent_hash(parent_hash);
|
||||||
block.header.set_number(block_number);
|
block.header.set_number(block_number);
|
||||||
|
@ -18,12 +18,14 @@
|
|||||||
|
|
||||||
use std::{io::Write, ops};
|
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 ethereum_types::{H256, H264, U256};
|
||||||
use heapsize::HeapSizeOf;
|
use heapsize::HeapSizeOf;
|
||||||
use kvdb::PREFIX_LEN as DB_PREFIX_LEN;
|
use kvdb::PREFIX_LEN as DB_PREFIX_LEN;
|
||||||
use rlp;
|
use rlp;
|
||||||
use rlp_derive::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper};
|
use rlp_derive::{RlpDecodable, RlpEncodable};
|
||||||
|
|
||||||
use crate::db::Key;
|
use crate::db::Key;
|
||||||
|
|
||||||
@ -235,15 +237,27 @@ impl HeapSizeOf for TransactionAddress {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Contains all block receipts.
|
/// Contains all block receipts.
|
||||||
#[derive(Clone, RlpEncodableWrapper, RlpDecodableWrapper)]
|
#[derive(Clone)]
|
||||||
pub struct BlockReceipts {
|
pub struct BlockReceipts {
|
||||||
/// Block receipts
|
/// 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 {
|
impl BlockReceipts {
|
||||||
/// Create new block receipts wrapper.
|
/// Create new block receipts wrapper.
|
||||||
pub fn new(receipts: Vec<Receipt>) -> Self {
|
pub fn new(receipts: Vec<TypedReceipt>) -> Self {
|
||||||
BlockReceipts { receipts: receipts }
|
BlockReceipts { receipts: receipts }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,8 @@
|
|||||||
"eip1884Transition": "0x0",
|
"eip1884Transition": "0x0",
|
||||||
"eip2028Transition": "0x0",
|
"eip2028Transition": "0x0",
|
||||||
"eip2315Transition": "0x0",
|
"eip2315Transition": "0x0",
|
||||||
"eip2929Transition": "0x0"
|
"eip2929Transition": "0x0",
|
||||||
|
"eip2930Transition": "0x0"
|
||||||
},
|
},
|
||||||
"genesis": {
|
"genesis": {
|
||||||
"seal": {
|
"seal": {
|
||||||
|
@ -48,10 +48,10 @@ use verification::PreverifiedBlock;
|
|||||||
use vm::{EnvInfo, LastHashes};
|
use vm::{EnvInfo, LastHashes};
|
||||||
|
|
||||||
use hash::keccak;
|
use hash::keccak;
|
||||||
use rlp::{encode_list, Encodable, RlpStream};
|
use rlp::{encode_list, RlpStream};
|
||||||
use types::{
|
use types::{
|
||||||
header::{ExtendedHeader, Header},
|
header::{ExtendedHeader, Header},
|
||||||
receipt::{Receipt, TransactionOutcome},
|
receipt::{TransactionOutcome, TypedReceipt},
|
||||||
transaction::{Error as TransactionError, SignedTransaction},
|
transaction::{Error as TransactionError, SignedTransaction},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -99,7 +99,7 @@ pub struct ExecutedBlock {
|
|||||||
/// Uncles.
|
/// Uncles.
|
||||||
pub uncles: Vec<Header>,
|
pub uncles: Vec<Header>,
|
||||||
/// Transaction receipts.
|
/// Transaction receipts.
|
||||||
pub receipts: Vec<Receipt>,
|
pub receipts: Vec<TypedReceipt>,
|
||||||
/// Hashes of already executed transactions.
|
/// Hashes of already executed transactions.
|
||||||
pub transactions_set: HashSet<H256>,
|
pub transactions_set: HashSet<H256>,
|
||||||
/// Underlaying state.
|
/// Underlaying state.
|
||||||
@ -253,7 +253,7 @@ impl<'x> OpenBlock<'x> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
t: SignedTransaction,
|
t: SignedTransaction,
|
||||||
h: Option<H256>,
|
h: Option<H256>,
|
||||||
) -> Result<&Receipt, Error> {
|
) -> Result<&TypedReceipt, Error> {
|
||||||
if self.block.transactions_set.contains(&t.hash()) {
|
if self.block.transactions_set.contains(&t.hash()) {
|
||||||
return Err(TransactionError::AlreadyImported.into());
|
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
|
// t_nb 8.5.3 fill open block header with all other fields
|
||||||
s.block.header.set_transactions_root(ordered_trie_root(
|
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);
|
let uncle_bytes = encode_list(&s.block.uncles);
|
||||||
s.block.header.set_uncles_hash(keccak(&uncle_bytes));
|
s.block.header.set_uncles_hash(keccak(&uncle_bytes));
|
||||||
s.block.header.set_state_root(s.block.state.root().clone());
|
s.block.header.set_state_root(s.block.state.root().clone());
|
||||||
s.block.header.set_receipts_root(ordered_trie_root(
|
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
|
s.block
|
||||||
.header
|
.header
|
||||||
@ -453,7 +453,7 @@ impl LockedBlock {
|
|||||||
receipt.outcome = TransactionOutcome::Unknown;
|
receipt.outcome = TransactionOutcome::Unknown;
|
||||||
}
|
}
|
||||||
self.block.header.set_receipts_root(ordered_trie_root(
|
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 {
|
pub fn rlp_bytes(&self) -> Bytes {
|
||||||
let mut block_rlp = RlpStream::new_list(3);
|
let mut block_rlp = RlpStream::new_list(3);
|
||||||
block_rlp.append(&self.block.header);
|
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.append_list(&self.block.uncles);
|
||||||
block_rlp.out()
|
block_rlp.out()
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ use itertools::Itertools;
|
|||||||
use kvdb::{DBTransaction, DBValue, KeyValueDB};
|
use kvdb::{DBTransaction, DBValue, KeyValueDB};
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use rand::OsRng;
|
use rand::OsRng;
|
||||||
use rlp::PayloadInfo;
|
use rlp::{PayloadInfo, Rlp};
|
||||||
use rustc_hex::FromHex;
|
use rustc_hex::FromHex;
|
||||||
use trie::{Trie, TrieFactory, TrieSpec};
|
use trie::{Trie, TrieFactory, TrieSpec};
|
||||||
use types::{
|
use types::{
|
||||||
@ -51,8 +51,11 @@ use types::{
|
|||||||
filter::Filter,
|
filter::Filter,
|
||||||
header::{ExtendedHeader, Header},
|
header::{ExtendedHeader, Header},
|
||||||
log_entry::LocalizedLogEntry,
|
log_entry::LocalizedLogEntry,
|
||||||
receipt::{LocalizedReceipt, Receipt},
|
receipt::{LocalizedReceipt, TypedReceipt},
|
||||||
transaction::{self, Action, LocalizedTransaction, SignedTransaction, UnverifiedTransaction},
|
transaction::{
|
||||||
|
self, Action, LocalizedTransaction, SignedTransaction, TypedTransaction,
|
||||||
|
UnverifiedTransaction,
|
||||||
|
},
|
||||||
BlockNumber,
|
BlockNumber,
|
||||||
};
|
};
|
||||||
use vm::{EnvInfo, LastHashes};
|
use vm::{EnvInfo, LastHashes};
|
||||||
@ -524,7 +527,8 @@ impl Importer {
|
|||||||
db: &dyn KeyValueDB,
|
db: &dyn KeyValueDB,
|
||||||
chain: &BlockChain,
|
chain: &BlockChain,
|
||||||
) -> EthcoreResult<()> {
|
) -> 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();
|
let _import_lock = self.import_lock.lock();
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -714,7 +718,7 @@ impl Importer {
|
|||||||
&self,
|
&self,
|
||||||
header: &Header,
|
header: &Header,
|
||||||
block_bytes: &[u8],
|
block_bytes: &[u8],
|
||||||
receipts: &[Receipt],
|
receipts: &[TypedReceipt],
|
||||||
state_db: &StateDB,
|
state_db: &StateDB,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
) -> EthcoreResult<Option<PendingTransition>> {
|
) -> EthcoreResult<Option<PendingTransition>> {
|
||||||
@ -1436,7 +1440,7 @@ impl Client {
|
|||||||
data: Bytes,
|
data: Bytes,
|
||||||
) -> SignedTransaction {
|
) -> SignedTransaction {
|
||||||
let from = Address::default();
|
let from = Address::default();
|
||||||
transaction::Transaction {
|
TypedTransaction::Legacy(transaction::Transaction {
|
||||||
nonce: self
|
nonce: self
|
||||||
.nonce(&from, block_id)
|
.nonce(&from, block_id)
|
||||||
.unwrap_or_else(|| self.engine.account_start_nonce(0)),
|
.unwrap_or_else(|| self.engine.account_start_nonce(0)),
|
||||||
@ -1445,7 +1449,7 @@ impl Client {
|
|||||||
gas_price: U256::default(),
|
gas_price: U256::default(),
|
||||||
value: U256::default(),
|
value: U256::default(),
|
||||||
data: data,
|
data: data,
|
||||||
}
|
})
|
||||||
.fake_sign(from)
|
.fake_sign(from)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1889,7 +1893,7 @@ impl Call for Client {
|
|||||||
|
|
||||||
let exec = |gas| {
|
let exec = |gas| {
|
||||||
let mut tx = t.as_unsigned().clone();
|
let mut tx = t.as_unsigned().clone();
|
||||||
tx.gas = gas;
|
tx.tx_mut().gas = gas;
|
||||||
let tx = tx.fake_sign(sender);
|
let tx = tx.fake_sign(sender);
|
||||||
|
|
||||||
let mut clone = state.clone();
|
let mut clone = state.clone();
|
||||||
@ -1920,6 +1924,7 @@ impl Call for Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let lower = t
|
let lower = t
|
||||||
|
.tx()
|
||||||
.gas_required(&self.engine.schedule(env_info.number))
|
.gas_required(&self.engine.schedule(env_info.number))
|
||||||
.into();
|
.into();
|
||||||
if cond(lower) {
|
if cond(lower) {
|
||||||
@ -2571,18 +2576,18 @@ impl BlockChainClient for Client {
|
|||||||
} else {
|
} else {
|
||||||
self.importer.miner.sensible_gas_price()
|
self.importer.miner.sensible_gas_price()
|
||||||
};
|
};
|
||||||
let transaction = transaction::Transaction {
|
let transaction = TypedTransaction::Legacy(transaction::Transaction {
|
||||||
nonce: self.latest_nonce(&authoring_params.author),
|
nonce: self.latest_nonce(&authoring_params.author),
|
||||||
action: Action::Call(address),
|
action: Action::Call(address),
|
||||||
gas: self.importer.miner.sensible_gas_limit(),
|
gas: self.importer.miner.sensible_gas_limit(),
|
||||||
gas_price,
|
gas_price,
|
||||||
value: U256::zero(),
|
value: U256::zero(),
|
||||||
data: data,
|
data: data,
|
||||||
};
|
});
|
||||||
let chain_id = self.engine.signing_chain_id(&self.latest_env_info());
|
let chain_id = self.engine.signing_chain_id(&self.latest_env_info());
|
||||||
let signature = self
|
let signature = self
|
||||||
.engine
|
.engine
|
||||||
.sign(transaction.hash(chain_id))
|
.sign(transaction.signature_hash(chain_id))
|
||||||
.map_err(|e| transaction::Error::InvalidSignature(e.to_string()))?;
|
.map_err(|e| transaction::Error::InvalidSignature(e.to_string()))?;
|
||||||
let signed = SignedTransaction::new(transaction.with_signature(signature, chain_id))?;
|
let signed = SignedTransaction::new(transaction.with_signature(signature, chain_id))?;
|
||||||
self.importer
|
self.importer
|
||||||
@ -2602,10 +2607,15 @@ impl IoClient for Client {
|
|||||||
self.queue_transactions
|
self.queue_transactions
|
||||||
.queue(&self.io_channel.read(), len, move |client| {
|
.queue(&self.io_channel.read(), len, move |client| {
|
||||||
trace_time!("import_queued_transactions");
|
trace_time!("import_queued_transactions");
|
||||||
|
let best_block_number = client.best_block_header().number();
|
||||||
let txs: Vec<UnverifiedTransaction> = transactions
|
let txs: Vec<UnverifiedTransaction> = transactions
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|bytes| client.engine.decode_transaction(bytes).ok())
|
.filter_map(|bytes| {
|
||||||
|
client
|
||||||
|
.engine
|
||||||
|
.decode_transaction(bytes, best_block_number)
|
||||||
|
.ok()
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
client.notify(|notify| {
|
client.notify(|notify| {
|
||||||
@ -2954,7 +2964,7 @@ impl ProvingBlockChainClient for Client {
|
|||||||
_ => return None,
|
_ => 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();
|
let mut jdb = self.state_db.read().journal_db().boxed_clone();
|
||||||
|
|
||||||
state::prove_transaction_virtual(
|
state::prove_transaction_virtual(
|
||||||
@ -3112,7 +3122,7 @@ impl ImportExportBlocks for Client {
|
|||||||
fn transaction_receipt(
|
fn transaction_receipt(
|
||||||
machine: &::machine::EthereumMachine,
|
machine: &::machine::EthereumMachine,
|
||||||
mut tx: LocalizedTransaction,
|
mut tx: LocalizedTransaction,
|
||||||
receipt: Receipt,
|
receipt: TypedReceipt,
|
||||||
prior_gas_used: U256,
|
prior_gas_used: U256,
|
||||||
prior_no_of_logs: usize,
|
prior_no_of_logs: usize,
|
||||||
) -> LocalizedReceipt {
|
) -> LocalizedReceipt {
|
||||||
@ -3121,27 +3131,31 @@ fn transaction_receipt(
|
|||||||
let block_hash = tx.block_hash;
|
let block_hash = tx.block_hash;
|
||||||
let block_number = tx.block_number;
|
let block_number = tx.block_number;
|
||||||
let transaction_index = tx.transaction_index;
|
let transaction_index = tx.transaction_index;
|
||||||
|
let transaction_type = tx.tx_type();
|
||||||
|
|
||||||
|
let receipt = receipt.receipt().clone();
|
||||||
|
|
||||||
LocalizedReceipt {
|
LocalizedReceipt {
|
||||||
from: sender,
|
from: sender,
|
||||||
to: match tx.action {
|
to: match tx.tx().action {
|
||||||
Action::Create => None,
|
Action::Create => None,
|
||||||
Action::Call(ref address) => Some(address.clone().into()),
|
Action::Call(ref address) => Some(address.clone().into()),
|
||||||
},
|
},
|
||||||
transaction_hash: transaction_hash,
|
transaction_hash: transaction_hash,
|
||||||
transaction_index: transaction_index,
|
transaction_index: transaction_index,
|
||||||
|
transaction_type: transaction_type,
|
||||||
block_hash: block_hash,
|
block_hash: block_hash,
|
||||||
block_number: block_number,
|
block_number: block_number,
|
||||||
cumulative_gas_used: receipt.gas_used,
|
cumulative_gas_used: receipt.gas_used,
|
||||||
gas_used: receipt.gas_used - prior_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::Call(_) => None,
|
||||||
Action::Create => Some(
|
Action::Create => Some(
|
||||||
contract_address(
|
contract_address(
|
||||||
machine.create_address_scheme(block_number),
|
machine.create_address_scheme(block_number),
|
||||||
&sender,
|
&sender,
|
||||||
&tx.nonce,
|
&tx.tx().nonce,
|
||||||
&tx.data,
|
&tx.tx().data,
|
||||||
)
|
)
|
||||||
.0,
|
.0,
|
||||||
),
|
),
|
||||||
@ -3161,7 +3175,7 @@ fn transaction_receipt(
|
|||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
log_bloom: receipt.log_bloom,
|
log_bloom: receipt.log_bloom,
|
||||||
outcome: receipt.outcome,
|
outcome: receipt.outcome.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3457,8 +3471,8 @@ mod tests {
|
|||||||
use hash::keccak;
|
use hash::keccak;
|
||||||
use types::{
|
use types::{
|
||||||
log_entry::{LocalizedLogEntry, LogEntry},
|
log_entry::{LocalizedLogEntry, LogEntry},
|
||||||
receipt::{LocalizedReceipt, Receipt, TransactionOutcome},
|
receipt::{LegacyReceipt, LocalizedReceipt, TransactionOutcome, TypedReceipt},
|
||||||
transaction::{Action, LocalizedTransaction, Transaction},
|
transaction::{Action, LocalizedTransaction, Transaction, TypedTransaction},
|
||||||
};
|
};
|
||||||
|
|
||||||
// given
|
// given
|
||||||
@ -3470,14 +3484,14 @@ mod tests {
|
|||||||
let block_hash = 5.into();
|
let block_hash = 5.into();
|
||||||
let state_root = 99.into();
|
let state_root = 99.into();
|
||||||
let gas_used = 10.into();
|
let gas_used = 10.into();
|
||||||
let raw_tx = Transaction {
|
let raw_tx = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 21000.into(),
|
gas: 21000.into(),
|
||||||
action: Action::Call(10.into()),
|
action: Action::Call(10.into()),
|
||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
};
|
});
|
||||||
let tx1 = raw_tx.clone().sign(secret, None);
|
let tx1 = raw_tx.clone().sign(secret, None);
|
||||||
let transaction = LocalizedTransaction {
|
let transaction = LocalizedTransaction {
|
||||||
signed: tx1.clone().into(),
|
signed: tx1.clone().into(),
|
||||||
@ -3498,12 +3512,12 @@ mod tests {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
let receipt = Receipt {
|
let receipt = TypedReceipt::Legacy(LegacyReceipt {
|
||||||
outcome: TransactionOutcome::StateRoot(state_root),
|
outcome: TransactionOutcome::StateRoot(state_root),
|
||||||
gas_used: gas_used,
|
gas_used: gas_used,
|
||||||
log_bloom: Default::default(),
|
log_bloom: Default::default(),
|
||||||
logs: logs.clone(),
|
logs: logs.clone(),
|
||||||
};
|
});
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let receipt = transaction_receipt(&machine, transaction, receipt, 5.into(), 1);
|
let receipt = transaction_receipt(&machine, transaction, receipt, 5.into(), 1);
|
||||||
@ -3513,12 +3527,13 @@ mod tests {
|
|||||||
receipt,
|
receipt,
|
||||||
LocalizedReceipt {
|
LocalizedReceipt {
|
||||||
from: tx1.sender().into(),
|
from: tx1.sender().into(),
|
||||||
to: match tx1.action {
|
to: match tx1.tx().action {
|
||||||
Action::Create => None,
|
Action::Create => None,
|
||||||
Action::Call(ref address) => Some(address.clone().into()),
|
Action::Call(ref address) => Some(address.clone().into()),
|
||||||
},
|
},
|
||||||
transaction_hash: tx1.hash(),
|
transaction_hash: tx1.hash(),
|
||||||
transaction_index: 1,
|
transaction_index: 1,
|
||||||
|
transaction_type: tx1.tx_type(),
|
||||||
block_hash: block_hash,
|
block_hash: block_hash,
|
||||||
block_number: block_number,
|
block_number: block_number,
|
||||||
cumulative_gas_used: gas_used,
|
cumulative_gas_used: gas_used,
|
||||||
|
@ -281,7 +281,7 @@ impl<'a> EvmTestClient<'a> {
|
|||||||
tracer: T,
|
tracer: T,
|
||||||
vm_tracer: V,
|
vm_tracer: V,
|
||||||
) -> std::result::Result<TransactSuccess<T::Output, V::Output>, TransactErr> {
|
) -> std::result::Result<TransactSuccess<T::Output, V::Output>, TransactErr> {
|
||||||
let initial_gas = transaction.gas;
|
let initial_gas = transaction.tx().gas;
|
||||||
// Verify transaction
|
// Verify transaction
|
||||||
let is_ok = transaction.verify_basic(true, None);
|
let is_ok = transaction.verify_basic(true, None);
|
||||||
if let Err(error) = is_ok {
|
if let Err(error) = is_ok {
|
||||||
@ -342,18 +342,18 @@ impl<'a> EvmTestClient<'a> {
|
|||||||
Ok(result) => Ok(TransactSuccess {
|
Ok(result) => Ok(TransactSuccess {
|
||||||
state_root,
|
state_root,
|
||||||
gas_left: initial_gas - result.receipt.gas_used,
|
gas_left: initial_gas - result.receipt.gas_used,
|
||||||
outcome: result.receipt.outcome,
|
outcome: result.receipt.outcome.clone(),
|
||||||
output: result.output,
|
output: result.output,
|
||||||
trace: result.trace,
|
trace: result.trace,
|
||||||
vm_trace: result.vm_trace,
|
vm_trace: result.vm_trace,
|
||||||
logs: result.receipt.logs,
|
logs: result.receipt.logs.clone(),
|
||||||
contract_address: if let transaction::Action::Create = transaction.action {
|
contract_address: if let transaction::Action::Create = transaction.tx().action {
|
||||||
Some(
|
Some(
|
||||||
executive::contract_address(
|
executive::contract_address(
|
||||||
scheme,
|
scheme,
|
||||||
&transaction.sender(),
|
&transaction.sender(),
|
||||||
&transaction.nonce,
|
&transaction.tx().nonce,
|
||||||
&transaction.data,
|
&transaction.tx().data,
|
||||||
)
|
)
|
||||||
.0,
|
.0,
|
||||||
)
|
)
|
||||||
|
@ -36,7 +36,7 @@ use itertools::Itertools;
|
|||||||
use kvdb::DBValue;
|
use kvdb::DBValue;
|
||||||
use kvdb_memorydb;
|
use kvdb_memorydb;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use rlp::{Rlp, RlpStream};
|
use rlp::RlpStream;
|
||||||
use rustc_hex::FromHex;
|
use rustc_hex::FromHex;
|
||||||
use types::{
|
use types::{
|
||||||
basic_account::BasicAccount,
|
basic_account::BasicAccount,
|
||||||
@ -45,8 +45,11 @@ use types::{
|
|||||||
header::Header,
|
header::Header,
|
||||||
log_entry::LocalizedLogEntry,
|
log_entry::LocalizedLogEntry,
|
||||||
pruning_info::PruningInfo,
|
pruning_info::PruningInfo,
|
||||||
receipt::{LocalizedReceipt, Receipt, TransactionOutcome},
|
receipt::{LegacyReceipt, LocalizedReceipt, TransactionOutcome, TypedReceipt},
|
||||||
transaction::{self, Action, LocalizedTransaction, SignedTransaction, Transaction},
|
transaction::{
|
||||||
|
self, Action, LocalizedTransaction, SignedTransaction, Transaction, TypedTransaction,
|
||||||
|
TypedTxId,
|
||||||
|
},
|
||||||
view,
|
view,
|
||||||
views::BlockView,
|
views::BlockView,
|
||||||
BlockNumber,
|
BlockNumber,
|
||||||
@ -296,16 +299,16 @@ impl TestBlockChainClient {
|
|||||||
|
|
||||||
for _ in 0..num_transactions {
|
for _ in 0..num_transactions {
|
||||||
// Update nonces value
|
// Update nonces value
|
||||||
let tx = Transaction {
|
let tx = TypedTransaction::Legacy(Transaction {
|
||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: U256::from(100),
|
value: U256::from(100),
|
||||||
data: "3331600055".from_hex().unwrap(),
|
data: "3331600055".from_hex().unwrap(),
|
||||||
gas: U256::from(100_000),
|
gas: U256::from(100_000),
|
||||||
gas_price: U256::from(200_000_000_000u64),
|
gas_price: U256::from(200_000_000_000u64),
|
||||||
nonce: nonce,
|
nonce: nonce,
|
||||||
};
|
});
|
||||||
let signed_tx = tx.sign(keypair.secret(), None);
|
let signed_tx = tx.sign(keypair.secret(), None);
|
||||||
txs.append(&signed_tx);
|
signed_tx.rlp_append(&mut txs);
|
||||||
nonce += U256::one();
|
nonce += U256::one();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,14 +372,14 @@ impl TestBlockChainClient {
|
|||||||
/// Inserts a transaction with given gas price to miners transactions queue.
|
/// 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 {
|
pub fn insert_transaction_with_gas_price_to_queue(&self, gas_price: U256) -> H256 {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate().unwrap();
|
||||||
let tx = Transaction {
|
let tx = TypedTransaction::Legacy(Transaction {
|
||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: U256::from(100),
|
value: U256::from(100),
|
||||||
data: "3331600055".from_hex().unwrap(),
|
data: "3331600055".from_hex().unwrap(),
|
||||||
gas: U256::from(100_000),
|
gas: U256::from(100_000),
|
||||||
gas_price: gas_price,
|
gas_price: gas_price,
|
||||||
nonce: U256::zero(),
|
nonce: U256::zero(),
|
||||||
};
|
});
|
||||||
let signed_tx = tx.sign(keypair.secret(), None);
|
let signed_tx = tx.sign(keypair.secret(), None);
|
||||||
self.set_balance(signed_tx.sender(), 10_000_000_000_000_000_000u64.into());
|
self.set_balance(signed_tx.sender(), 10_000_000_000_000_000_000u64.into());
|
||||||
let hash = signed_tx.hash();
|
let hash = signed_tx.hash();
|
||||||
@ -938,10 +941,13 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
fn block_receipts(&self, hash: &H256) -> Option<BlockReceipts> {
|
fn block_receipts(&self, hash: &H256) -> Option<BlockReceipts> {
|
||||||
// starts with 'f' ?
|
// starts with 'f' ?
|
||||||
if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") {
|
if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") {
|
||||||
let receipt = BlockReceipts::new(vec![Receipt::new(
|
let receipt = BlockReceipts::new(vec![TypedReceipt::new(
|
||||||
TransactionOutcome::StateRoot(H256::zero()),
|
TypedTxId::Legacy,
|
||||||
U256::zero(),
|
LegacyReceipt::new(
|
||||||
vec![],
|
TransactionOutcome::StateRoot(H256::zero()),
|
||||||
|
U256::zero(),
|
||||||
|
vec![],
|
||||||
|
),
|
||||||
)]);
|
)]);
|
||||||
return Some(receipt);
|
return Some(receipt);
|
||||||
}
|
}
|
||||||
@ -1027,16 +1033,20 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn transact_contract(&self, address: Address, data: Bytes) -> Result<(), transaction::Error> {
|
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),
|
nonce: self.latest_nonce(&self.miner.authoring_params().author),
|
||||||
action: Action::Call(address),
|
action: Action::Call(address),
|
||||||
gas: self.spec.gas_limit,
|
gas: self.spec.gas_limit,
|
||||||
gas_price: U256::zero(),
|
gas_price: U256::zero(),
|
||||||
value: U256::default(),
|
value: U256::default(),
|
||||||
data: data,
|
data: data,
|
||||||
};
|
});
|
||||||
let chain_id = Some(self.spec.chain_id());
|
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();
|
let signed = SignedTransaction::new(transaction.with_signature(sig, chain_id)).unwrap();
|
||||||
self.miner.import_own_transaction(self, signed.into())
|
self.miner.import_own_transaction(self, signed.into())
|
||||||
}
|
}
|
||||||
@ -1051,7 +1061,7 @@ impl IoClient for TestBlockChainClient {
|
|||||||
// import right here
|
// import right here
|
||||||
let txs = transactions
|
let txs = transactions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|bytes| Rlp::new(&bytes).as_val().ok())
|
.filter_map(|bytes| TypedTransaction::decode(&bytes).ok())
|
||||||
.collect();
|
.collect();
|
||||||
self.miner.import_external_transactions(self, txs);
|
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 test_helpers::{generate_dummy_client_with_spec, get_temp_state_db, TestNotify};
|
||||||
use types::{
|
use types::{
|
||||||
header::Header,
|
header::Header,
|
||||||
transaction::{Action, Transaction},
|
transaction::{Action, Transaction, TypedTransaction},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn aura<F>(f: F) -> Arc<AuthorityRound>
|
fn aura<F>(f: F) -> Arc<AuthorityRound>
|
||||||
@ -2287,14 +2287,14 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
b2.push_transaction(
|
b2.push_transaction(
|
||||||
Transaction {
|
TypedTransaction::Legacy(Transaction {
|
||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
nonce: U256::from(0),
|
nonce: U256::from(0),
|
||||||
gas_price: U256::from(3000),
|
gas_price: U256::from(3000),
|
||||||
gas: U256::from(53_000),
|
gas: U256::from(53_000),
|
||||||
value: U256::from(1),
|
value: U256::from(1),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}
|
})
|
||||||
.fake_sign(addr2),
|
.fake_sign(addr2),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
|
@ -605,8 +605,10 @@ pub trait EthEngine: Engine<::machine::EthereumMachine> {
|
|||||||
fn decode_transaction(
|
fn decode_transaction(
|
||||||
&self,
|
&self,
|
||||||
transaction: &[u8],
|
transaction: &[u8],
|
||||||
|
best_block_number: BlockNumber,
|
||||||
) -> Result<UnverifiedTransaction, transaction::Error> {
|
) -> 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 memory_cache::MemoryLruCache;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use rlp::{Rlp, RlpStream};
|
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 unexpected::Mismatch;
|
||||||
|
|
||||||
use super::{simple_list::SimpleList, SystemCall, ValidatorSet};
|
use super::{simple_list::SimpleList, SystemCall, ValidatorSet};
|
||||||
@ -91,7 +91,7 @@ fn check_first_proof(
|
|||||||
old_header: Header,
|
old_header: Header,
|
||||||
state_items: &[DBValue],
|
state_items: &[DBValue],
|
||||||
) -> Result<Vec<Address>, String> {
|
) -> 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.
|
// TODO: match client contract_call_tx more cleanly without duplication.
|
||||||
const PROVIDED_GAS: u64 = 50_000_000;
|
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 (data, decoder) = validator_set::functions::get_validators::call();
|
||||||
|
|
||||||
let from = Address::default();
|
let from = Address::default();
|
||||||
let tx = Transaction {
|
let tx = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: machine.account_start_nonce(number),
|
nonce: machine.account_start_nonce(number),
|
||||||
action: Action::Call(contract_address),
|
action: Action::Call(contract_address),
|
||||||
gas: PROVIDED_GAS.into(),
|
gas: PROVIDED_GAS.into(),
|
||||||
gas_price: U256::default(),
|
gas_price: U256::default(),
|
||||||
value: U256::default(),
|
value: U256::default(),
|
||||||
data,
|
data,
|
||||||
}
|
})
|
||||||
.fake_sign(from);
|
.fake_sign(from);
|
||||||
|
|
||||||
let res = ::state::check_proof(
|
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.
|
// inter-contract proofs are a header and receipts.
|
||||||
// checking will involve ensuring that the receipts match the header and
|
// checking will involve ensuring that the receipts match the header and
|
||||||
// extracting the validator set from the receipts.
|
// 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);
|
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()
|
stream.drain()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_proof(rlp: &Rlp) -> Result<(Header, Vec<Receipt>), ::error::Error> {
|
fn decode_proof(rlp: &Rlp) -> Result<(Header, Vec<TypedReceipt>), ::error::Error> {
|
||||||
Ok((rlp.val_at(0)?, rlp.list_at(1)?))
|
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
|
// given a provider and caller, generate proof. this will just be a state proof
|
||||||
@ -265,7 +266,7 @@ impl ValidatorSafeContract {
|
|||||||
&self,
|
&self,
|
||||||
bloom: Bloom,
|
bloom: Bloom,
|
||||||
header: &Header,
|
header: &Header,
|
||||||
receipts: &[Receipt],
|
receipts: &[TypedReceipt],
|
||||||
) -> Option<SimpleList> {
|
) -> Option<SimpleList> {
|
||||||
let check_log = |log: &LogEntry| {
|
let check_log = |log: &LogEntry| {
|
||||||
log.address == self.contract_address
|
log.address == self.contract_address
|
||||||
@ -406,7 +407,7 @@ impl ValidatorSet for ValidatorSafeContract {
|
|||||||
|
|
||||||
// ensure receipts match header.
|
// ensure receipts match header.
|
||||||
// TODO: optimize? these were just decoded.
|
// 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() {
|
if found_root != *old_header.receipts_root() {
|
||||||
return Err(::error::BlockError::InvalidReceiptsRoot(Mismatch {
|
return Err(::error::BlockError::InvalidReceiptsRoot(Mismatch {
|
||||||
expected: *old_header.receipts_root(),
|
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 test_helpers::{generate_dummy_client_with_spec, generate_dummy_client_with_spec_and_data};
|
||||||
use types::{
|
use types::{
|
||||||
ids::BlockId,
|
ids::BlockId,
|
||||||
transaction::{Action, Transaction},
|
transaction::{Action, Transaction, TypedTransaction},
|
||||||
};
|
};
|
||||||
use verification::queue::kind::blocks::Unverified;
|
use verification::queue::kind::blocks::Unverified;
|
||||||
|
|
||||||
@ -537,7 +538,7 @@ mod tests {
|
|||||||
|
|
||||||
client.miner().set_author(miner::Author::Sealer(signer));
|
client.miner().set_author(miner::Author::Sealer(signer));
|
||||||
// Remove "1" validator.
|
// Remove "1" validator.
|
||||||
let tx = Transaction {
|
let tx = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 500_000.into(),
|
gas: 500_000.into(),
|
||||||
@ -546,7 +547,7 @@ mod tests {
|
|||||||
data: "bfc708a000000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1"
|
data: "bfc708a000000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1"
|
||||||
.from_hex()
|
.from_hex()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
}
|
})
|
||||||
.sign(&s0, Some(chain_id));
|
.sign(&s0, Some(chain_id));
|
||||||
client
|
client
|
||||||
.miner()
|
.miner()
|
||||||
@ -555,7 +556,7 @@ mod tests {
|
|||||||
EngineClient::update_sealing(&*client, ForceUpdateSealing::No);
|
EngineClient::update_sealing(&*client, ForceUpdateSealing::No);
|
||||||
assert_eq!(client.chain_info().best_block_number, 1);
|
assert_eq!(client.chain_info().best_block_number, 1);
|
||||||
// Add "1" validator back in.
|
// Add "1" validator back in.
|
||||||
let tx = Transaction {
|
let tx = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 1.into(),
|
nonce: 1.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 500_000.into(),
|
gas: 500_000.into(),
|
||||||
@ -564,7 +565,7 @@ mod tests {
|
|||||||
data: "4d238c8e00000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1"
|
data: "4d238c8e00000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1"
|
||||||
.from_hex()
|
.from_hex()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
}
|
})
|
||||||
.sign(&s0, Some(chain_id));
|
.sign(&s0, Some(chain_id));
|
||||||
client
|
client
|
||||||
.miner()
|
.miner()
|
||||||
@ -582,14 +583,14 @@ mod tests {
|
|||||||
// Switch back to the added validator, since the state is updated.
|
// Switch back to the added validator, since the state is updated.
|
||||||
let signer = Box::new((tap.clone(), v1, "".into()));
|
let signer = Box::new((tap.clone(), v1, "".into()));
|
||||||
client.miner().set_author(miner::Author::Sealer(signer));
|
client.miner().set_author(miner::Author::Sealer(signer));
|
||||||
let tx = Transaction {
|
let tx = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 2.into(),
|
nonce: 2.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 21000.into(),
|
gas: 21000.into(),
|
||||||
action: Action::Call(Address::default()),
|
action: Action::Call(Address::default()),
|
||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
data: Vec::new(),
|
data: Vec::new(),
|
||||||
}
|
})
|
||||||
.sign(&s0, Some(chain_id));
|
.sign(&s0, Some(chain_id));
|
||||||
client
|
client
|
||||||
.miner()
|
.miner()
|
||||||
|
@ -28,7 +28,7 @@ use state::{Backend as StateBackend, CleanupMode, State, Substate};
|
|||||||
use std::{cmp, sync::Arc};
|
use std::{cmp, sync::Arc};
|
||||||
use trace::{self, Tracer, VMTracer};
|
use trace::{self, Tracer, VMTracer};
|
||||||
use transaction_ext::Transaction;
|
use transaction_ext::Transaction;
|
||||||
use types::transaction::{Action, SignedTransaction};
|
use types::transaction::{Action, SignedTransaction, TypedTransaction};
|
||||||
use vm::{
|
use vm::{
|
||||||
self, AccessList, ActionParams, ActionValue, CleanDustMode, CreateContractAddress, EnvInfo,
|
self, AccessList, ActionParams, ActionValue, CleanDustMode, CreateContractAddress, EnvInfo,
|
||||||
ResumeCall, ResumeCreate, ReturnData, Schedule, TrapError,
|
ResumeCall, ResumeCreate, ReturnData, Schedule, TrapError,
|
||||||
@ -1109,7 +1109,10 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
{
|
{
|
||||||
let sender = t.sender();
|
let sender = t.sender();
|
||||||
let balance = self.state.balance(&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 {
|
if balance < needed_balance {
|
||||||
// give the sender a sufficient balance
|
// give the sender a sufficient balance
|
||||||
self.state
|
self.state
|
||||||
@ -1132,16 +1135,51 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
T: Tracer,
|
T: Tracer,
|
||||||
V: VMTracer,
|
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 sender = t.sender();
|
||||||
let nonce = self.state.nonce(&sender)?;
|
let nonce = self.state.nonce(&sender)?;
|
||||||
|
|
||||||
let schedule = self.schedule;
|
let mut base_gas_required = U256::from(t.tx().gas_required(&schedule));
|
||||||
let base_gas_required = U256::from(t.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 {
|
return Err(ExecutionError::NotEnoughBaseGas {
|
||||||
required: base_gas_required,
|
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);
|
return Err(ExecutionError::SenderMustExist);
|
||||||
}
|
}
|
||||||
|
|
||||||
let init_gas = t.gas - base_gas_required;
|
let init_gas = t.tx().gas - base_gas_required;
|
||||||
|
|
||||||
// validate transaction nonce
|
// validate transaction nonce
|
||||||
if check_nonce && t.nonce != nonce {
|
if check_nonce && t.tx().nonce != nonce {
|
||||||
return Err(ExecutionError::InvalidNonce {
|
return Err(ExecutionError::InvalidNonce {
|
||||||
expected: nonce,
|
expected: nonce,
|
||||||
got: t.nonce,
|
got: t.tx().nonce,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate if transaction fits into given block
|
// 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 {
|
return Err(ExecutionError::BlockGasLimitReached {
|
||||||
gas_limit: self.info.gas_limit,
|
gas_limit: self.info.gas_limit,
|
||||||
gas_used: self.info.gas_used,
|
gas_used: self.info.gas_used,
|
||||||
gas: t.gas,
|
gas: t.tx().gas,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: we might need bigints here, or at least check overflows.
|
// TODO: we might need bigints here, or at least check overflows.
|
||||||
let balance = self.state.balance(&sender)?;
|
let balance = self.state.balance(&sender)?;
|
||||||
let gas_cost = t.gas.full_mul(t.gas_price);
|
let gas_cost = t.tx().gas.full_mul(t.tx().gas_price);
|
||||||
let total_cost = U512::from(t.value) + gas_cost;
|
let total_cost = U512::from(t.tx().value) + gas_cost;
|
||||||
|
|
||||||
// avoid unaffordable transactions
|
// avoid unaffordable transactions
|
||||||
let balance512 = U512::from(balance);
|
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);
|
let mut substate = Substate::from_access_list(&access_list);
|
||||||
|
|
||||||
// NOTE: there can be no invalid transactions from this point.
|
// 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),
|
&mut substate.to_cleanup_mode(&schedule),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let (result, output) = match t.action {
|
let (result, output) = match t.tx().action {
|
||||||
Action::Create => {
|
Action::Create => {
|
||||||
let (new_address, code_hash) = contract_address(
|
let (new_address, code_hash) = contract_address(
|
||||||
self.machine.create_address_scheme(self.info.number),
|
self.machine.create_address_scheme(self.info.number),
|
||||||
&sender,
|
&sender,
|
||||||
&nonce,
|
&nonce,
|
||||||
&t.data,
|
&t.tx().data,
|
||||||
);
|
);
|
||||||
let params = ActionParams {
|
let params = ActionParams {
|
||||||
code_address: new_address.clone(),
|
code_address: new_address.clone(),
|
||||||
@ -1220,9 +1251,9 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
sender: sender.clone(),
|
sender: sender.clone(),
|
||||||
origin: sender.clone(),
|
origin: sender.clone(),
|
||||||
gas: init_gas,
|
gas: init_gas,
|
||||||
gas_price: t.gas_price,
|
gas_price: t.tx().gas_price,
|
||||||
value: ActionValue::Transfer(t.value),
|
value: ActionValue::Transfer(t.tx().value),
|
||||||
code: Some(Arc::new(t.data.clone())),
|
code: Some(Arc::new(t.tx().data.clone())),
|
||||||
data: None,
|
data: None,
|
||||||
call_type: CallType::None,
|
call_type: CallType::None,
|
||||||
params_type: vm::ParamsType::Embedded,
|
params_type: vm::ParamsType::Embedded,
|
||||||
@ -1242,11 +1273,11 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
sender: sender.clone(),
|
sender: sender.clone(),
|
||||||
origin: sender.clone(),
|
origin: sender.clone(),
|
||||||
gas: init_gas,
|
gas: init_gas,
|
||||||
gas_price: t.gas_price,
|
gas_price: t.tx().gas_price,
|
||||||
value: ActionValue::Transfer(t.value),
|
value: ActionValue::Transfer(t.tx().value),
|
||||||
code: self.state.code(address)?,
|
code: self.state.code(address)?,
|
||||||
code_hash: self.state.code_hash(address)?,
|
code_hash: self.state.code_hash(address)?,
|
||||||
data: Some(t.data.clone()),
|
data: Some(t.tx().data.clone()),
|
||||||
call_type: CallType::Call,
|
call_type: CallType::Call,
|
||||||
params_type: vm::ParamsType::Separate,
|
params_type: vm::ParamsType::Separate,
|
||||||
access_list: access_list,
|
access_list: access_list,
|
||||||
@ -1445,12 +1476,12 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
Ok(FinalizationResult { gas_left, .. }) => gas_left,
|
Ok(FinalizationResult { gas_left, .. }) => gas_left,
|
||||||
_ => 0.into(),
|
_ => 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_left = gas_left_prerefund + refunded;
|
||||||
|
|
||||||
let gas_used = t.gas.saturating_sub(gas_left);
|
let gas_used = t.tx().gas.saturating_sub(gas_left);
|
||||||
let (refund_value, overflow_1) = gas_left.overflowing_mul(t.gas_price);
|
let (refund_value, overflow_1) = gas_left.overflowing_mul(t.tx().gas_price);
|
||||||
let (fees_value, overflow_2) = gas_used.overflowing_mul(t.gas_price);
|
let (fees_value, overflow_2) = gas_used.overflowing_mul(t.tx().gas_price);
|
||||||
if overflow_1 || overflow_2 {
|
if overflow_1 || overflow_2 {
|
||||||
return Err(ExecutionError::TransactionMalformed(
|
return Err(ExecutionError::TransactionMalformed(
|
||||||
"U256 Overflow".to_string(),
|
"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",
|
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();
|
let sender = t.sender();
|
||||||
trace!(
|
trace!(
|
||||||
@ -1487,7 +1518,11 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
|
|
||||||
// perform garbage-collection
|
// perform garbage-collection
|
||||||
let min_balance = if schedule.kill_dust != CleanDustMode::Off {
|
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 {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
@ -1502,10 +1537,10 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
Err(vm::Error::Internal(msg)) => Err(ExecutionError::Internal(msg)),
|
Err(vm::Error::Internal(msg)) => Err(ExecutionError::Internal(msg)),
|
||||||
Err(exception) => Ok(Executed {
|
Err(exception) => Ok(Executed {
|
||||||
exception: Some(exception),
|
exception: Some(exception),
|
||||||
gas: t.gas,
|
gas: t.tx().gas,
|
||||||
gas_used: t.gas,
|
gas_used: t.tx().gas,
|
||||||
refunded: U256::zero(),
|
refunded: U256::zero(),
|
||||||
cumulative_gas_used: self.info.gas_used + t.gas,
|
cumulative_gas_used: self.info.gas_used + t.tx().gas,
|
||||||
logs: vec![],
|
logs: vec![],
|
||||||
contracts_created: vec![],
|
contracts_created: vec![],
|
||||||
output: output,
|
output: output,
|
||||||
@ -1519,7 +1554,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> {
|
|||||||
} else {
|
} else {
|
||||||
Some(vm::Error::Reverted)
|
Some(vm::Error::Reverted)
|
||||||
},
|
},
|
||||||
gas: t.gas,
|
gas: t.tx().gas,
|
||||||
gas_used: gas_used,
|
gas_used: gas_used,
|
||||||
refunded: refunded,
|
refunded: refunded,
|
||||||
cumulative_gas_used: self.info.gas_used + gas_used,
|
cumulative_gas_used: self.info.gas_used + gas_used,
|
||||||
@ -1551,7 +1586,7 @@ mod tests {
|
|||||||
trace, ExecutiveTracer, ExecutiveVMTracer, FlatTrace, MemoryDiff, NoopTracer, NoopVMTracer,
|
trace, ExecutiveTracer, ExecutiveVMTracer, FlatTrace, MemoryDiff, NoopTracer, NoopVMTracer,
|
||||||
StorageDiff, Tracer, VMExecutedOperation, VMOperation, VMTrace, VMTracer,
|
StorageDiff, Tracer, VMExecutedOperation, VMOperation, VMTrace, VMTracer,
|
||||||
};
|
};
|
||||||
use types::transaction::{Action, Transaction};
|
use types::transaction::{Action, Transaction, TypedTransaction};
|
||||||
use vm::{ActionParams, ActionValue, CallType, CreateContractAddress, EnvInfo};
|
use vm::{ActionParams, ActionValue, CallType, CreateContractAddress, EnvInfo};
|
||||||
|
|
||||||
fn make_frontier_machine(max_depth: usize) -> EthereumMachine {
|
fn make_frontier_machine(max_depth: usize) -> EthereumMachine {
|
||||||
@ -2445,14 +2480,14 @@ mod tests {
|
|||||||
evm_test_ignore! {test_transact_simple: test_transact_simple_int}
|
evm_test_ignore! {test_transact_simple: test_transact_simple_int}
|
||||||
fn test_transact_simple(factory: Factory) {
|
fn test_transact_simple(factory: Factory) {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate().unwrap();
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: U256::from(17),
|
value: U256::from(17),
|
||||||
data: "3331600055".from_hex().unwrap(),
|
data: "3331600055".from_hex().unwrap(),
|
||||||
gas: U256::from(100_000),
|
gas: U256::from(100_000),
|
||||||
gas_price: U256::zero(),
|
gas_price: U256::zero(),
|
||||||
nonce: U256::zero(),
|
nonce: U256::zero(),
|
||||||
}
|
})
|
||||||
.sign(keypair.secret(), None);
|
.sign(keypair.secret(), None);
|
||||||
let sender = t.sender();
|
let sender = t.sender();
|
||||||
let contract = contract_address(
|
let contract = contract_address(
|
||||||
@ -2496,14 +2531,14 @@ mod tests {
|
|||||||
evm_test! {test_transact_invalid_nonce: test_transact_invalid_nonce_int}
|
evm_test! {test_transact_invalid_nonce: test_transact_invalid_nonce_int}
|
||||||
fn test_transact_invalid_nonce(factory: Factory) {
|
fn test_transact_invalid_nonce(factory: Factory) {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate().unwrap();
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: U256::from(17),
|
value: U256::from(17),
|
||||||
data: "3331600055".from_hex().unwrap(),
|
data: "3331600055".from_hex().unwrap(),
|
||||||
gas: U256::from(100_000),
|
gas: U256::from(100_000),
|
||||||
gas_price: U256::zero(),
|
gas_price: U256::zero(),
|
||||||
nonce: U256::one(),
|
nonce: U256::one(),
|
||||||
}
|
})
|
||||||
.sign(keypair.secret(), None);
|
.sign(keypair.secret(), None);
|
||||||
let sender = t.sender();
|
let sender = t.sender();
|
||||||
|
|
||||||
@ -2535,14 +2570,14 @@ mod tests {
|
|||||||
evm_test! {test_transact_gas_limit_reached: test_transact_gas_limit_reached_int}
|
evm_test! {test_transact_gas_limit_reached: test_transact_gas_limit_reached_int}
|
||||||
fn test_transact_gas_limit_reached(factory: Factory) {
|
fn test_transact_gas_limit_reached(factory: Factory) {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate().unwrap();
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: U256::from(17),
|
value: U256::from(17),
|
||||||
data: "3331600055".from_hex().unwrap(),
|
data: "3331600055".from_hex().unwrap(),
|
||||||
gas: U256::from(80_001),
|
gas: U256::from(80_001),
|
||||||
gas_price: U256::zero(),
|
gas_price: U256::zero(),
|
||||||
nonce: U256::zero(),
|
nonce: U256::zero(),
|
||||||
}
|
})
|
||||||
.sign(keypair.secret(), None);
|
.sign(keypair.secret(), None);
|
||||||
let sender = t.sender();
|
let sender = t.sender();
|
||||||
|
|
||||||
@ -2580,14 +2615,14 @@ mod tests {
|
|||||||
evm_test! {test_not_enough_cash: test_not_enough_cash_int}
|
evm_test! {test_not_enough_cash: test_not_enough_cash_int}
|
||||||
fn test_not_enough_cash(factory: Factory) {
|
fn test_not_enough_cash(factory: Factory) {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate().unwrap();
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: U256::from(18),
|
value: U256::from(18),
|
||||||
data: "3331600055".from_hex().unwrap(),
|
data: "3331600055".from_hex().unwrap(),
|
||||||
gas: U256::from(100_000),
|
gas: U256::from(100_000),
|
||||||
gas_price: U256::one(),
|
gas_price: U256::one(),
|
||||||
nonce: U256::zero(),
|
nonce: U256::zero(),
|
||||||
}
|
})
|
||||||
.sign(keypair.secret(), None);
|
.sign(keypair.secret(), None);
|
||||||
let sender = t.sender();
|
let sender = t.sender();
|
||||||
|
|
||||||
|
@ -17,10 +17,12 @@
|
|||||||
use super::test_common::*;
|
use super::test_common::*;
|
||||||
use client::EvmTestClient;
|
use client::EvmTestClient;
|
||||||
use ethjson;
|
use ethjson;
|
||||||
use rlp::Rlp;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use transaction_ext::Transaction;
|
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)>(
|
pub fn json_transaction_test<H: FnMut(&str, HookType)>(
|
||||||
path: &Path,
|
path: &Path,
|
||||||
@ -65,8 +67,7 @@ pub fn json_transaction_test<H: FnMut(&str, HookType)>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let rlp: Vec<u8> = test.rlp.clone().into();
|
let rlp: Vec<u8> = test.rlp.clone().into();
|
||||||
let res = Rlp::new(&rlp)
|
let res = TypedTransaction::decode(&rlp)
|
||||||
.as_val()
|
|
||||||
.map_err(::error::Error::from)
|
.map_err(::error::Error::from)
|
||||||
.and_then(|t: UnverifiedTransaction| {
|
.and_then(|t: UnverifiedTransaction| {
|
||||||
let mut header: Header = Default::default();
|
let mut header: Header = Default::default();
|
||||||
@ -74,12 +75,13 @@ pub fn json_transaction_test<H: FnMut(&str, HookType)>(
|
|||||||
header.set_number(BLOCK_NUMBER);
|
header.set_number(BLOCK_NUMBER);
|
||||||
|
|
||||||
let minimal = t
|
let minimal = t
|
||||||
|
.tx()
|
||||||
.gas_required(&spec.engine.schedule(header.number()))
|
.gas_required(&spec.engine.schedule(header.number()))
|
||||||
.into();
|
.into();
|
||||||
if t.gas < minimal {
|
if t.tx().gas < minimal {
|
||||||
return Err(::types::transaction::Error::InsufficientGas {
|
return Err(::types::transaction::Error::InsufficientGas {
|
||||||
minimal,
|
minimal,
|
||||||
got: t.gas,
|
got: t.tx().gas,
|
||||||
}
|
}
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
|
@ -23,11 +23,11 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use ethereum_types::{Address, H256, U256};
|
use ethereum_types::{Address, H256, U256};
|
||||||
use rlp::Rlp;
|
|
||||||
use types::{
|
use types::{
|
||||||
header::Header,
|
header::Header,
|
||||||
transaction::{
|
transaction::{
|
||||||
self, SignedTransaction, UnverifiedTransaction, SYSTEM_ADDRESS, UNSIGNED_SENDER,
|
self, SignedTransaction, TypedTransaction, UnverifiedTransaction, SYSTEM_ADDRESS,
|
||||||
|
UNSIGNED_SENDER,
|
||||||
},
|
},
|
||||||
BlockNumber,
|
BlockNumber,
|
||||||
};
|
};
|
||||||
@ -455,17 +455,27 @@ impl EthereumMachine {
|
|||||||
pub fn decode_transaction(
|
pub fn decode_transaction(
|
||||||
&self,
|
&self,
|
||||||
transaction: &[u8],
|
transaction: &[u8],
|
||||||
|
schedule: &Schedule,
|
||||||
) -> Result<UnverifiedTransaction, transaction::Error> {
|
) -> Result<UnverifiedTransaction, transaction::Error> {
|
||||||
let rlp = Rlp::new(&transaction);
|
if transaction.len() > self.params().max_transaction_size {
|
||||||
if rlp.as_raw().len() > self.params().max_transaction_size {
|
|
||||||
debug!(
|
debug!(
|
||||||
"Rejected oversized transaction of {} bytes",
|
"Rejected oversized transaction of {} bytes",
|
||||||
rlp.as_raw().len()
|
transaction.len()
|
||||||
);
|
);
|
||||||
return Err(transaction::Error::TooBig);
|
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.
|
/// The full block bytes, including the header.
|
||||||
pub bytes: Option<&'a [u8]>,
|
pub bytes: Option<&'a [u8]>,
|
||||||
/// The block receipts.
|
/// 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.
|
/// Type alias for a function we can make calls through synchronously.
|
||||||
@ -550,7 +560,7 @@ mod tests {
|
|||||||
fn should_disallow_unsigned_transactions() {
|
fn should_disallow_unsigned_transactions() {
|
||||||
let rlp = "ea80843b9aca0083015f90948921ebb5f79e9e3920abe571004d0b1d5119c154865af3107a400080038080";
|
let rlp = "ea80843b9aca0083015f90948921ebb5f79e9e3920abe571004d0b1d5119c154865af3107a400080038080";
|
||||||
let transaction: UnverifiedTransaction =
|
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 spec = ::ethereum::new_ropsten_test();
|
||||||
let ethparams = get_default_ethash_extensions();
|
let ethparams = get_default_ethash_extensions();
|
||||||
|
|
||||||
|
@ -1195,15 +1195,16 @@ impl miner::MinerService for Miner {
|
|||||||
let receipt = &receipts[index];
|
let receipt = &receipts[index];
|
||||||
RichReceipt {
|
RichReceipt {
|
||||||
from: tx.sender(),
|
from: tx.sender(),
|
||||||
to: match tx.action {
|
to: match tx.tx().action {
|
||||||
Action::Create => None,
|
Action::Create => None,
|
||||||
Action::Call(ref address) => Some(*address),
|
Action::Call(ref address) => Some(*address),
|
||||||
},
|
},
|
||||||
transaction_hash: tx.hash(),
|
transaction_hash: tx.hash(),
|
||||||
|
transaction_type: tx.tx_type(),
|
||||||
transaction_index: index,
|
transaction_index: index,
|
||||||
cumulative_gas_used: receipt.gas_used,
|
cumulative_gas_used: receipt.gas_used,
|
||||||
gas_used: receipt.gas_used - prev_gas,
|
gas_used: receipt.gas_used - prev_gas,
|
||||||
contract_address: match tx.action {
|
contract_address: match tx.tx().action {
|
||||||
Action::Call(_) => None,
|
Action::Call(_) => None,
|
||||||
Action::Create => {
|
Action::Create => {
|
||||||
let sender = tx.sender();
|
let sender = tx.sender();
|
||||||
@ -1212,8 +1213,8 @@ impl miner::MinerService for Miner {
|
|||||||
self.engine
|
self.engine
|
||||||
.create_address_scheme(pending.header.number()),
|
.create_address_scheme(pending.header.number()),
|
||||||
&sender,
|
&sender,
|
||||||
&tx.nonce,
|
&tx.tx().nonce,
|
||||||
&tx.data,
|
&tx.tx().data,
|
||||||
)
|
)
|
||||||
.0,
|
.0,
|
||||||
)
|
)
|
||||||
@ -1509,7 +1510,7 @@ mod tests {
|
|||||||
use client::{ChainInfo, EachBlockWith, ImportSealedBlock, TestBlockChainClient};
|
use client::{ChainInfo, EachBlockWith, ImportSealedBlock, TestBlockChainClient};
|
||||||
use miner::{MinerService, PendingOrdering};
|
use miner::{MinerService, PendingOrdering};
|
||||||
use test_helpers::{generate_dummy_client, generate_dummy_client_with_spec};
|
use test_helpers::{generate_dummy_client, generate_dummy_client_with_spec};
|
||||||
use types::transaction::Transaction;
|
use types::transaction::{Transaction, TypedTransaction};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_prepare_block_to_seal() {
|
fn should_prepare_block_to_seal() {
|
||||||
@ -1583,14 +1584,14 @@ mod tests {
|
|||||||
|
|
||||||
fn transaction_with_chain_id(chain_id: u64) -> SignedTransaction {
|
fn transaction_with_chain_id(chain_id: u64) -> SignedTransaction {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate().unwrap();
|
||||||
Transaction {
|
TypedTransaction::Legacy(Transaction {
|
||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: U256::zero(),
|
value: U256::zero(),
|
||||||
data: "3331600055".from_hex().unwrap(),
|
data: "3331600055".from_hex().unwrap(),
|
||||||
gas: U256::from(100_000),
|
gas: U256::from(100_000),
|
||||||
gas_price: U256::zero(),
|
gas_price: U256::zero(),
|
||||||
nonce: U256::zero(),
|
nonce: U256::zero(),
|
||||||
}
|
})
|
||||||
.sign(keypair.secret(), Some(chain_id))
|
.sign(keypair.secret(), Some(chain_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +195,8 @@ where
|
|||||||
&self,
|
&self,
|
||||||
transaction: &[u8],
|
transaction: &[u8],
|
||||||
) -> Result<UnverifiedTransaction, transaction::Error> {
|
) -> 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 hash::keccak;
|
||||||
use rlp::{DecoderError, Rlp, RlpStream};
|
use rlp::{DecoderError, Rlp, RlpStream};
|
||||||
use triehash::ordered_trie_root;
|
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 HEADER_FIELDS: usize = 8;
|
||||||
const BLOCK_FIELDS: usize = 2;
|
const BLOCK_FIELDS: usize = 2;
|
||||||
@ -62,9 +62,9 @@ impl AbridgedBlock {
|
|||||||
.append(&header.extra_data());
|
.append(&header.extra_data());
|
||||||
|
|
||||||
// write block values.
|
// write block values.
|
||||||
stream
|
|
||||||
.append_list(&block_view.transactions())
|
TypedTransaction::rlp_append_list(&mut stream, &block_view.transactions());
|
||||||
.append_list(&block_view.uncles());
|
stream.append_list(&block_view.uncles());
|
||||||
|
|
||||||
// write seal fields.
|
// write seal fields.
|
||||||
for field in seal_fields {
|
for field in seal_fields {
|
||||||
@ -97,10 +97,17 @@ impl AbridgedBlock {
|
|||||||
header.set_timestamp(rlp.val_at(6)?);
|
header.set_timestamp(rlp.val_at(6)?);
|
||||||
header.set_extra_data(rlp.val_at(7)?);
|
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)?;
|
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);
|
header.set_receipts_root(receipts_root);
|
||||||
|
|
||||||
let mut uncles_rlp = RlpStream::new();
|
let mut uncles_rlp = RlpStream::new();
|
||||||
@ -131,7 +138,7 @@ mod tests {
|
|||||||
use ethereum_types::{Address, H256, U256};
|
use ethereum_types::{Address, H256, U256};
|
||||||
use types::{
|
use types::{
|
||||||
block::Block,
|
block::Block,
|
||||||
transaction::{Action, Transaction},
|
transaction::{Action, Transaction, TypedTransaction},
|
||||||
view,
|
view,
|
||||||
views::BlockView,
|
views::BlockView,
|
||||||
};
|
};
|
||||||
@ -165,24 +172,24 @@ mod tests {
|
|||||||
fn with_transactions() {
|
fn with_transactions() {
|
||||||
let mut b = Block::default();
|
let mut b = Block::default();
|
||||||
|
|
||||||
let t1 = Transaction {
|
let t1 = TypedTransaction::Legacy(Transaction {
|
||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
nonce: U256::from(42),
|
nonce: U256::from(42),
|
||||||
gas_price: U256::from(3000),
|
gas_price: U256::from(3000),
|
||||||
gas: U256::from(50_000),
|
gas: U256::from(50_000),
|
||||||
value: U256::from(1),
|
value: U256::from(1),
|
||||||
data: b"Hello!".to_vec(),
|
data: b"Hello!".to_vec(),
|
||||||
}
|
})
|
||||||
.fake_sign(Address::from(0x69));
|
.fake_sign(Address::from(0x69));
|
||||||
|
|
||||||
let t2 = Transaction {
|
let t2 = TypedTransaction::Legacy(Transaction {
|
||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
nonce: U256::from(88),
|
nonce: U256::from(88),
|
||||||
gas_price: U256::from(12345),
|
gas_price: U256::from(12345),
|
||||||
gas: U256::from(300000),
|
gas: U256::from(300000),
|
||||||
value: U256::from(1000000000),
|
value: U256::from(1000000000),
|
||||||
data: "Eep!".into(),
|
data: "Eep!".into(),
|
||||||
}
|
})
|
||||||
.fake_sign(Address::from(0x55));
|
.fake_sign(Address::from(0x55));
|
||||||
|
|
||||||
b.transactions.push(t1.into());
|
b.transactions.push(t1.into());
|
||||||
@ -191,7 +198,7 @@ mod tests {
|
|||||||
let receipts_root = b.header.receipts_root().clone();
|
let receipts_root = b.header.receipts_root().clone();
|
||||||
b.header
|
b.header
|
||||||
.set_transactions_root(::triehash::ordered_trie_root(
|
.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);
|
let encoded = encode_block(&b);
|
||||||
|
@ -36,7 +36,9 @@ use ethereum_types::{H256, U256};
|
|||||||
use itertools::{Itertools, Position};
|
use itertools::{Itertools, Position};
|
||||||
use kvdb::KeyValueDB;
|
use kvdb::KeyValueDB;
|
||||||
use rlp::{Rlp, RlpStream};
|
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.
|
/// Snapshot creation and restoration for PoA chains.
|
||||||
/// Chunk format:
|
/// Chunk format:
|
||||||
@ -114,9 +116,9 @@ impl SnapshotComponents for PoaSnapshot {
|
|||||||
|
|
||||||
rlps.push({
|
rlps.push({
|
||||||
let mut stream = RlpStream::new_list(5);
|
let mut stream = RlpStream::new_list(5);
|
||||||
|
stream.append(&block.header);
|
||||||
|
TypedTransaction::rlp_append_list(&mut stream, &block.transactions);
|
||||||
stream
|
stream
|
||||||
.append(&block.header)
|
|
||||||
.append_list(&block.transactions)
|
|
||||||
.append_list(&block.uncles)
|
.append_list(&block.uncles)
|
||||||
.append(&receipts)
|
.append(&receipts)
|
||||||
.append(&parent_td);
|
.append(&parent_td);
|
||||||
@ -349,11 +351,11 @@ impl Rebuilder for ChunkRebuilder {
|
|||||||
let last_rlp = rlp.at(num_items - 1)?;
|
let last_rlp = rlp.at(num_items - 1)?;
|
||||||
let block = Block {
|
let block = Block {
|
||||||
header: last_rlp.val_at(0)?,
|
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)?,
|
uncles: last_rlp.list_at(2)?,
|
||||||
};
|
};
|
||||||
let block_data = block.rlp_bytes();
|
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();
|
let hash = block.header.hash();
|
||||||
|
@ -291,8 +291,15 @@ impl Rebuilder for PowRebuilder {
|
|||||||
let pair = rlp.at(idx)?;
|
let pair = rlp.at(idx)?;
|
||||||
let abridged_rlp = pair.at(0)?.as_raw().to_owned();
|
let abridged_rlp = pair.at(0)?.as_raw().to_owned();
|
||||||
let abridged_block = AbridgedBlock::from_raw(abridged_rlp);
|
let abridged_block = AbridgedBlock::from_raw(abridged_rlp);
|
||||||
let receipts: Vec<::types::receipt::Receipt> = pair.list_at(1)?;
|
let receipts = ::types::receipt::TypedReceipt::decode_rlp_list(&pair.at(1)?)?;
|
||||||
let receipts_root = ordered_trie_root(pair.at(1)?.iter().map(|r| r.as_raw()));
|
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 = abridged_block.to_block(parent_hash, cur_number, receipts_root)?;
|
||||||
let block_bytes = encoded::Block::new(block.rlp_bytes());
|
let block_bytes = encoded::Block::new(block.rlp_bytes());
|
||||||
|
@ -25,7 +25,7 @@ use snapshot::tests::helpers as snapshot_helpers;
|
|||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
use tempdir::TempDir;
|
use tempdir::TempDir;
|
||||||
use test_helpers::generate_dummy_client_with_spec;
|
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 ethereum_types::Address;
|
||||||
use test_helpers;
|
use test_helpers;
|
||||||
@ -128,14 +128,14 @@ fn make_chain(
|
|||||||
// and force sealing.
|
// and force sealing.
|
||||||
let make_useless_transactions = || {
|
let make_useless_transactions = || {
|
||||||
let mut nonce = nonce.borrow_mut();
|
let mut nonce = nonce.borrow_mut();
|
||||||
let transaction = Transaction {
|
let transaction = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: *nonce,
|
nonce: *nonce,
|
||||||
gas_price: 1.into(),
|
gas_price: 1.into(),
|
||||||
gas: 21_000.into(),
|
gas: 21_000.into(),
|
||||||
action: Action::Call(Address::new()),
|
action: Action::Call(Address::new()),
|
||||||
value: 1.into(),
|
value: 1.into(),
|
||||||
data: Vec::new(),
|
data: Vec::new(),
|
||||||
}
|
})
|
||||||
.sign(&*RICH_SECRET, client.signing_chain_id());
|
.sign(&*RICH_SECRET, client.signing_chain_id());
|
||||||
|
|
||||||
*nonce = *nonce + 1;
|
*nonce = *nonce + 1;
|
||||||
@ -171,14 +171,14 @@ fn make_chain(
|
|||||||
let data =
|
let data =
|
||||||
test_validator_set::functions::set_validators::encode_input(new_set.clone());
|
test_validator_set::functions::set_validators::encode_input(new_set.clone());
|
||||||
let mut nonce = nonce.borrow_mut();
|
let mut nonce = nonce.borrow_mut();
|
||||||
let transaction = Transaction {
|
let transaction = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: *nonce,
|
nonce: *nonce,
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 1_000_000.into(),
|
gas: 1_000_000.into(),
|
||||||
action: Action::Call(*address),
|
action: Action::Call(*address),
|
||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
data,
|
data,
|
||||||
}
|
})
|
||||||
.sign(&*RICH_SECRET, client.signing_chain_id());
|
.sign(&*RICH_SECRET, client.signing_chain_id());
|
||||||
|
|
||||||
*nonce = *nonce + 1;
|
*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);
|
generate_dummy_client_with_spec_and_data(Spec::new_null, NUM_BLOCKS, 5, &gas_prices);
|
||||||
|
|
||||||
let spec = Spec::new_null();
|
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 db_config = DatabaseConfig::with_columns(::db::NUM_COLUMNS);
|
||||||
let client_db = new_db();
|
let client_db = new_db();
|
||||||
let client2 = Client::new(
|
let client2 = Client::new(
|
||||||
|
@ -137,6 +137,8 @@ pub struct CommonParams {
|
|||||||
pub eip2315_transition: BlockNumber,
|
pub eip2315_transition: BlockNumber,
|
||||||
/// Number of first block where EIP-2929 rules begin.
|
/// Number of first block where EIP-2929 rules begin.
|
||||||
pub eip2929_transition: BlockNumber,
|
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.
|
/// Number of first block where dust cleanup rules (EIP-168 and EIP169) begin.
|
||||||
pub dust_protection_transition: BlockNumber,
|
pub dust_protection_transition: BlockNumber,
|
||||||
/// Nonce cap increase per block. Nonce cap is only checked if dust protection is enabled.
|
/// 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.eip1706 = block_number >= self.eip1706_transition;
|
||||||
schedule.have_subs = block_number >= self.eip2315_transition;
|
schedule.have_subs = block_number >= self.eip2315_transition;
|
||||||
schedule.eip2929 = block_number >= self.eip2929_transition;
|
schedule.eip2929 = block_number >= self.eip2929_transition;
|
||||||
|
schedule.eip2930 = block_number >= self.eip2930_transition;
|
||||||
|
|
||||||
if block_number >= self.eip1884_transition {
|
if block_number >= self.eip1884_transition {
|
||||||
schedule.have_selfbalance = true;
|
schedule.have_selfbalance = true;
|
||||||
@ -370,6 +373,9 @@ impl From<ethjson::spec::Params> for CommonParams {
|
|||||||
eip2929_transition: p
|
eip2929_transition: p
|
||||||
.eip2929_transition
|
.eip2929_transition
|
||||||
.map_or_else(BlockNumber::max_value, Into::into),
|
.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: p
|
||||||
.dust_protection_transition
|
.dust_protection_transition
|
||||||
.map_or_else(BlockNumber::max_value, Into::into),
|
.map_or_else(BlockNumber::max_value, Into::into),
|
||||||
@ -956,7 +962,7 @@ impl Spec {
|
|||||||
/// initialize genesis epoch data, using in-memory database for
|
/// initialize genesis epoch data, using in-memory database for
|
||||||
/// constructor.
|
/// constructor.
|
||||||
pub fn genesis_epoch_data(&self) -> Result<Vec<u8>, String> {
|
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();
|
let genesis = self.genesis_header();
|
||||||
|
|
||||||
@ -983,14 +989,14 @@ impl Spec {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let from = Address::default();
|
let from = Address::default();
|
||||||
let tx = Transaction {
|
let tx = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: self.engine.account_start_nonce(0),
|
nonce: self.engine.account_start_nonce(0),
|
||||||
action: Action::Call(a),
|
action: Action::Call(a),
|
||||||
gas: U256::max_value(),
|
gas: U256::max_value(),
|
||||||
gas_price: U256::default(),
|
gas_price: U256::default(),
|
||||||
value: U256::default(),
|
value: U256::default(),
|
||||||
data: d,
|
data: d,
|
||||||
}
|
})
|
||||||
.fake_sign(from);
|
.fake_sign(from);
|
||||||
|
|
||||||
let res = ::state::prove_transaction_virtual(
|
let res = ::state::prove_transaction_virtual(
|
||||||
|
@ -38,10 +38,11 @@ use state_db::StateDB;
|
|||||||
use trace::{self, FlatTrace, VMTrace};
|
use trace::{self, FlatTrace, VMTrace};
|
||||||
use types::{
|
use types::{
|
||||||
basic_account::BasicAccount,
|
basic_account::BasicAccount,
|
||||||
receipt::{Receipt, TransactionOutcome},
|
receipt::{LegacyReceipt, TransactionOutcome, TypedReceipt},
|
||||||
state_diff::StateDiff,
|
state_diff::StateDiff,
|
||||||
transaction::SignedTransaction,
|
transaction::SignedTransaction,
|
||||||
};
|
};
|
||||||
|
|
||||||
use vm::EnvInfo;
|
use vm::EnvInfo;
|
||||||
|
|
||||||
use bytes::Bytes;
|
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.
|
/// Used to return information about an `State::apply` operation.
|
||||||
pub struct ApplyOutcome<T, V> {
|
pub struct ApplyOutcome<T, V> {
|
||||||
/// The receipt for the applied transaction.
|
/// The receipt for the applied transaction.
|
||||||
pub receipt: Receipt,
|
pub receipt: TypedReceipt,
|
||||||
/// The output of the applied transaction.
|
/// The output of the applied transaction.
|
||||||
pub output: Bytes,
|
pub output: Bytes,
|
||||||
/// The trace for the applied transaction, empty if tracing was not produced.
|
/// 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 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);
|
trace!(target: "state", "Transaction receipt: {:?}", receipt);
|
||||||
|
|
||||||
Ok(ApplyOutcome {
|
Ok(ApplyOutcome {
|
||||||
@ -1602,7 +1606,7 @@ mod tests {
|
|||||||
info.gas_limit = 1_000_000.into();
|
info.gas_limit = 1_000_000.into();
|
||||||
let machine = make_frontier_machine(5);
|
let machine = make_frontier_machine(5);
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
@ -1610,7 +1614,7 @@ mod tests {
|
|||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: FromHex::from_hex("601080600c6000396000f3006000355415600957005b60203560003555")
|
data: FromHex::from_hex("601080600c6000396000f3006000355415600957005b60203560003555")
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
|
|
||||||
state
|
state
|
||||||
@ -1667,14 +1671,14 @@ mod tests {
|
|||||||
info.gas_limit = 1_000_000.into();
|
info.gas_limit = 1_000_000.into();
|
||||||
let machine = make_frontier_machine(5);
|
let machine = make_frontier_machine(5);
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: FromHex::from_hex("5b600056").unwrap(),
|
data: FromHex::from_hex("5b600056").unwrap(),
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
|
|
||||||
state
|
state
|
||||||
@ -1706,14 +1710,14 @@ mod tests {
|
|||||||
info.gas_limit = 1_000_000.into();
|
info.gas_limit = 1_000_000.into();
|
||||||
let machine = make_frontier_machine(5);
|
let machine = make_frontier_machine(5);
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
|
|
||||||
state
|
state
|
||||||
@ -1753,14 +1757,14 @@ mod tests {
|
|||||||
info.gas_limit = 1_000_000.into();
|
info.gas_limit = 1_000_000.into();
|
||||||
let machine = make_frontier_machine(5);
|
let machine = make_frontier_machine(5);
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
|
|
||||||
state
|
state
|
||||||
@ -1797,14 +1801,14 @@ mod tests {
|
|||||||
info.gas_limit = 1_000_000.into();
|
info.gas_limit = 1_000_000.into();
|
||||||
let machine = Spec::new_test_machine();
|
let machine = Spec::new_test_machine();
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
action: Action::Call(0x1.into()),
|
action: Action::Call(0x1.into()),
|
||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
|
|
||||||
let result = state.apply(&info, &machine, &t, true).unwrap();
|
let result = state.apply(&info, &machine, &t, true).unwrap();
|
||||||
@ -1839,14 +1843,14 @@ mod tests {
|
|||||||
info.gas_limit = 1_000_000.into();
|
info.gas_limit = 1_000_000.into();
|
||||||
let machine = Spec::new_test_machine();
|
let machine = Spec::new_test_machine();
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
|
|
||||||
state
|
state
|
||||||
@ -1887,14 +1891,14 @@ mod tests {
|
|||||||
info.gas_limit = 1_000_000.into();
|
info.gas_limit = 1_000_000.into();
|
||||||
let machine = Spec::new_test_machine();
|
let machine = Spec::new_test_machine();
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
|
|
||||||
state
|
state
|
||||||
@ -1957,14 +1961,14 @@ mod tests {
|
|||||||
info.number = 0x789b0;
|
info.number = 0x789b0;
|
||||||
let machine = Spec::new_test_machine();
|
let machine = Spec::new_test_machine();
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
|
|
||||||
state
|
state
|
||||||
@ -2029,14 +2033,14 @@ mod tests {
|
|||||||
info.gas_limit = 1_000_000.into();
|
info.gas_limit = 1_000_000.into();
|
||||||
let machine = make_frontier_machine(5);
|
let machine = make_frontier_machine(5);
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
|
|
||||||
state
|
state
|
||||||
@ -2073,14 +2077,14 @@ mod tests {
|
|||||||
info.gas_limit = 1_000_000.into();
|
info.gas_limit = 1_000_000.into();
|
||||||
let machine = make_frontier_machine(5);
|
let machine = make_frontier_machine(5);
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
|
|
||||||
state
|
state
|
||||||
@ -2145,14 +2149,14 @@ mod tests {
|
|||||||
info.gas_limit = 1_000_000.into();
|
info.gas_limit = 1_000_000.into();
|
||||||
let machine = make_frontier_machine(5);
|
let machine = make_frontier_machine(5);
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
|
|
||||||
state
|
state
|
||||||
@ -2210,14 +2214,14 @@ mod tests {
|
|||||||
info.gas_limit = 1_000_000.into();
|
info.gas_limit = 1_000_000.into();
|
||||||
let machine = make_frontier_machine(5);
|
let machine = make_frontier_machine(5);
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
|
|
||||||
state
|
state
|
||||||
@ -2260,14 +2264,14 @@ mod tests {
|
|||||||
info.gas_limit = 1_000_000.into();
|
info.gas_limit = 1_000_000.into();
|
||||||
let machine = make_frontier_machine(5);
|
let machine = make_frontier_machine(5);
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: vec![], //600480600b6000396000f35b600056
|
data: vec![], //600480600b6000396000f35b600056
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
|
|
||||||
state
|
state
|
||||||
@ -2328,14 +2332,14 @@ mod tests {
|
|||||||
info.gas_limit = 1_000_000.into();
|
info.gas_limit = 1_000_000.into();
|
||||||
let machine = make_frontier_machine(5);
|
let machine = make_frontier_machine(5);
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
|
|
||||||
state
|
state
|
||||||
@ -2421,14 +2425,14 @@ mod tests {
|
|||||||
info.gas_limit = 1_000_000.into();
|
info.gas_limit = 1_000_000.into();
|
||||||
let machine = make_frontier_machine(5);
|
let machine = make_frontier_machine(5);
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: vec![], //600480600b6000396000f35b600056
|
data: vec![], //600480600b6000396000f35b600056
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
|
|
||||||
state
|
state
|
||||||
@ -2512,14 +2516,14 @@ mod tests {
|
|||||||
info.gas_limit = 1_000_000.into();
|
info.gas_limit = 1_000_000.into();
|
||||||
let machine = make_frontier_machine(5);
|
let machine = make_frontier_machine(5);
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 100_000.into(),
|
gas: 100_000.into(),
|
||||||
action: Action::Call(0xa.into()),
|
action: Action::Call(0xa.into()),
|
||||||
value: 100.into(),
|
value: 100.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
}
|
})
|
||||||
.sign(&secret(), None);
|
.sign(&secret(), None);
|
||||||
|
|
||||||
state
|
state
|
||||||
|
@ -36,7 +36,7 @@ use tempdir::TempDir;
|
|||||||
use types::{
|
use types::{
|
||||||
encoded,
|
encoded,
|
||||||
header::Header,
|
header::Header,
|
||||||
transaction::{Action, SignedTransaction, Transaction},
|
transaction::{Action, SignedTransaction, Transaction, TypedTransaction},
|
||||||
view,
|
view,
|
||||||
views::BlockView,
|
views::BlockView,
|
||||||
};
|
};
|
||||||
@ -104,7 +104,7 @@ pub fn create_test_block_with_data(
|
|||||||
rlp.append(header);
|
rlp.append(header);
|
||||||
rlp.begin_list(transactions.len());
|
rlp.begin_list(transactions.len());
|
||||||
for t in transactions {
|
for t in transactions {
|
||||||
rlp.append_raw(&rlp::encode(t), 1);
|
t.rlp_append(&mut rlp);
|
||||||
}
|
}
|
||||||
rlp.append_list(&uncles);
|
rlp.append_list(&uncles);
|
||||||
rlp.out()
|
rlp.out()
|
||||||
@ -197,14 +197,14 @@ where
|
|||||||
// first block we don't have any balance, so can't send any transactions.
|
// first block we don't have any balance, so can't send any transactions.
|
||||||
for _ in 0..txs_per_block {
|
for _ in 0..txs_per_block {
|
||||||
b.push_transaction(
|
b.push_transaction(
|
||||||
Transaction {
|
TypedTransaction::Legacy(Transaction {
|
||||||
nonce: n.into(),
|
nonce: n.into(),
|
||||||
gas_price: tx_gas_prices[n % tx_gas_prices.len()],
|
gas_price: tx_gas_prices[n % tx_gas_prices.len()],
|
||||||
gas: 100000.into(),
|
gas: 100000.into(),
|
||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
data: vec![],
|
data: vec![],
|
||||||
value: U256::zero(),
|
value: U256::zero(),
|
||||||
}
|
})
|
||||||
.sign(kp.secret(), Some(test_spec.chain_id())),
|
.sign(kp.secret(), Some(test_spec.chain_id())),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
|
@ -45,7 +45,7 @@ use types::{
|
|||||||
data_format::DataFormat,
|
data_format::DataFormat,
|
||||||
filter::Filter,
|
filter::Filter,
|
||||||
ids::BlockId,
|
ids::BlockId,
|
||||||
transaction::{Action, Condition, PendingTransaction, Transaction},
|
transaction::{Action, Condition, PendingTransaction, Transaction, TypedTransaction},
|
||||||
view,
|
view,
|
||||||
views::BlockView,
|
views::BlockView,
|
||||||
};
|
};
|
||||||
@ -362,26 +362,26 @@ fn does_not_propagate_delayed_transactions() {
|
|||||||
let key = KeyPair::from_secret(keccak("test").into()).unwrap();
|
let key = KeyPair::from_secret(keccak("test").into()).unwrap();
|
||||||
let secret = key.secret();
|
let secret = key.secret();
|
||||||
let tx0 = PendingTransaction::new(
|
let tx0 = PendingTransaction::new(
|
||||||
Transaction {
|
TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 21000.into(),
|
gas: 21000.into(),
|
||||||
action: Action::Call(Address::default()),
|
action: Action::Call(Address::default()),
|
||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
data: Vec::new(),
|
data: Vec::new(),
|
||||||
}
|
})
|
||||||
.sign(secret, None),
|
.sign(secret, None),
|
||||||
Some(Condition::Number(2)),
|
Some(Condition::Number(2)),
|
||||||
);
|
);
|
||||||
let tx1 = PendingTransaction::new(
|
let tx1 = PendingTransaction::new(
|
||||||
Transaction {
|
TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 1.into(),
|
nonce: 1.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 21000.into(),
|
gas: 21000.into(),
|
||||||
action: Action::Call(Address::default()),
|
action: Action::Call(Address::default()),
|
||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
data: Vec::new(),
|
data: Vec::new(),
|
||||||
}
|
})
|
||||||
.sign(secret, None),
|
.sign(secret, None),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@ -443,14 +443,14 @@ fn transaction_proof() {
|
|||||||
client.import_sealed_block(b).unwrap(); // account change is in the journal overlay
|
client.import_sealed_block(b).unwrap(); // account change is in the journal overlay
|
||||||
}
|
}
|
||||||
|
|
||||||
let transaction = Transaction {
|
let transaction = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 21000.into(),
|
gas: 21000.into(),
|
||||||
action: Action::Call(Address::default()),
|
action: Action::Call(Address::default()),
|
||||||
value: 5.into(),
|
value: 5.into(),
|
||||||
data: Vec::new(),
|
data: Vec::new(),
|
||||||
}
|
})
|
||||||
.fake_sign(address);
|
.fake_sign(address);
|
||||||
|
|
||||||
let proof = client
|
let proof = client
|
||||||
|
@ -29,7 +29,7 @@ use test_helpers::{self, get_temp_state_db};
|
|||||||
use trace::{trace::Action::Reward, LocalizedTrace, RewardType};
|
use trace::{trace::Action::Reward, LocalizedTrace, RewardType};
|
||||||
use types::{
|
use types::{
|
||||||
header::Header,
|
header::Header,
|
||||||
transaction::{Action, Transaction},
|
transaction::{Action, Transaction, TypedTransaction},
|
||||||
view,
|
view,
|
||||||
views::BlockView,
|
views::BlockView,
|
||||||
};
|
};
|
||||||
@ -171,14 +171,14 @@ fn can_trace_block_and_uncle_reward() {
|
|||||||
for _ in 0..1 {
|
for _ in 0..1 {
|
||||||
block
|
block
|
||||||
.push_transaction(
|
.push_transaction(
|
||||||
Transaction {
|
TypedTransaction::Legacy(Transaction {
|
||||||
nonce: n.into(),
|
nonce: n.into(),
|
||||||
gas_price: 10000.into(),
|
gas_price: 10000.into(),
|
||||||
gas: 100000.into(),
|
gas: 100000.into(),
|
||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
data: vec![],
|
data: vec![],
|
||||||
value: U256::zero(),
|
value: U256::zero(),
|
||||||
}
|
})
|
||||||
.sign(kp.secret(), Some(spec.network_id())),
|
.sign(kp.secret(), Some(spec.network_id())),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
|
@ -83,7 +83,7 @@ impl TransactionFilter {
|
|||||||
let mut permission_cache = self.permission_cache.lock();
|
let mut permission_cache = self.permission_cache.lock();
|
||||||
let mut contract_version_cache = self.contract_version_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::Create => (tx_permissions::CREATE, Address::new()),
|
||||||
Action::Call(address) => {
|
Action::Call(address) => {
|
||||||
if client
|
if client
|
||||||
@ -98,7 +98,7 @@ impl TransactionFilter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let sender = transaction.sender();
|
let sender = transaction.sender();
|
||||||
let value = transaction.value;
|
let value = transaction.tx().value;
|
||||||
let key = (*parent_hash, sender);
|
let key = (*parent_hash, sender);
|
||||||
|
|
||||||
if let Some(permissions) = permission_cache.get_mut(&key) {
|
if let Some(permissions) = permission_cache.get_mut(&key) {
|
||||||
@ -181,7 +181,7 @@ mod test {
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tempdir::TempDir;
|
use tempdir::TempDir;
|
||||||
use test_helpers;
|
use test_helpers;
|
||||||
use types::transaction::{Action, Transaction};
|
use types::transaction::{Action, Transaction, TypedTransaction};
|
||||||
|
|
||||||
/// Contract code: https://gist.github.com/VladLupashevskyi/84f18eabb1e4afadf572cf92af3e7e7f
|
/// Contract code: https://gist.github.com/VladLupashevskyi/84f18eabb1e4afadf572cf92af3e7e7f
|
||||||
#[test]
|
#[test]
|
||||||
@ -230,28 +230,30 @@ mod test {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let filter = TransactionFilter::from_params(spec.params()).unwrap();
|
let filter = TransactionFilter::from_params(spec.params()).unwrap();
|
||||||
let mut basic_tx = Transaction::default();
|
let mut basic_tx = TypedTransaction::Legacy(Transaction::default());
|
||||||
basic_tx.action = Action::Call(Address::from("d41c057fd1c78805aac12b0a94a405c0461a6fbb"));
|
basic_tx.tx_mut().action =
|
||||||
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 =
|
|
||||||
Action::Call(Address::from("d41c057fd1c78805aac12b0a94a405c0461a6fbb"));
|
Action::Call(Address::from("d41c057fd1c78805aac12b0a94a405c0461a6fbb"));
|
||||||
basic_tx_with_ether_and_to_key7.value = U256::from(123123);
|
let create_tx = TypedTransaction::Legacy(Transaction::default());
|
||||||
let mut call_tx_with_ether = Transaction::default();
|
let mut call_tx = TypedTransaction::Legacy(Transaction::default());
|
||||||
call_tx_with_ether.action =
|
call_tx.tx_mut().action =
|
||||||
Action::Call(Address::from("0000000000000000000000000000000000000005"));
|
Action::Call(Address::from("0000000000000000000000000000000000000005"));
|
||||||
call_tx_with_ether.value = U256::from(123123);
|
|
||||||
|
|
||||||
let mut basic_tx_to_key6 = Transaction::default();
|
let mut basic_tx_with_ether_and_to_key7 = TypedTransaction::Legacy(Transaction::default());
|
||||||
basic_tx_to_key6.action =
|
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"));
|
Action::Call(Address::from("e57bfe9f44b819898f47bf37e5af72a0783e1141"));
|
||||||
let mut basic_tx_with_ether_and_to_key6 = Transaction::default();
|
let mut basic_tx_with_ether_and_to_key6 = TypedTransaction::Legacy(Transaction::default());
|
||||||
basic_tx_with_ether_and_to_key6.action =
|
basic_tx_with_ether_and_to_key6.tx_mut().action =
|
||||||
Action::Call(Address::from("e57bfe9f44b819898f47bf37e5af72a0783e1141"));
|
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 genesis = client.block_hash(BlockId::Latest).unwrap();
|
||||||
let block_number = 1;
|
let block_number = 1;
|
||||||
@ -444,11 +446,13 @@ mod test {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let filter = TransactionFilter::from_params(spec.params()).unwrap();
|
let filter = TransactionFilter::from_params(spec.params()).unwrap();
|
||||||
let mut basic_tx = Transaction::default();
|
let mut basic_tx = TypedTransaction::Legacy(Transaction::default());
|
||||||
basic_tx.action = Action::Call(Address::from("000000000000000000000000000000000000032"));
|
basic_tx.tx_mut().action =
|
||||||
let create_tx = Transaction::default();
|
Action::Call(Address::from("000000000000000000000000000000000000032"));
|
||||||
let mut call_tx = Transaction::default();
|
let create_tx = TypedTransaction::Legacy(Transaction::default());
|
||||||
call_tx.action = Action::Call(Address::from("0000000000000000000000000000000000000005"));
|
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 genesis = client.block_hash(BlockId::Latest).unwrap();
|
||||||
let block_number = 1;
|
let block_number = 1;
|
||||||
|
@ -80,7 +80,10 @@ pub mod blocks {
|
|||||||
|
|
||||||
use engines::EthEngine;
|
use engines::EthEngine;
|
||||||
use error::{BlockError, Error, ErrorKind};
|
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 verification::{verify_block_basic, verify_block_unordered, PreverifiedBlock};
|
||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
@ -151,7 +154,7 @@ pub mod blocks {
|
|||||||
let (header, transactions, uncles) = {
|
let (header, transactions, uncles) = {
|
||||||
let rlp = Rlp::new(&bytes);
|
let rlp = Rlp::new(&bytes);
|
||||||
let header = rlp.val_at(0)?;
|
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)?;
|
let uncles = rlp.list_at(2)?;
|
||||||
(header, transactions, uncles)
|
(header, transactions, uncles)
|
||||||
};
|
};
|
||||||
|
@ -133,7 +133,7 @@ pub fn verify_block_unordered(
|
|||||||
let t = engine.verify_transaction_unordered(t, &header)?;
|
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)
|
// 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 let Some(max_nonce) = nonce_cap {
|
||||||
if t.nonce >= max_nonce {
|
if t.tx().nonce >= max_nonce {
|
||||||
return Err(BlockError::TooManyTransactions(t.sender()).into());
|
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> {
|
fn verify_block_integrity(block: &Unverified) -> Result<(), Error> {
|
||||||
let block_rlp = Rlp::new(&block.bytes);
|
let block_rlp = Rlp::new(&block.bytes);
|
||||||
let tx = block_rlp.at(1)?;
|
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() {
|
if &expected_root != block.header.transactions_root() {
|
||||||
bail!(BlockError::InvalidTransactionsRoot(Mismatch {
|
bail!(BlockError::InvalidTransactionsRoot(Mismatch {
|
||||||
expected: expected_root,
|
expected: expected_root,
|
||||||
@ -531,7 +540,7 @@ mod tests {
|
|||||||
use types::{
|
use types::{
|
||||||
encoded,
|
encoded,
|
||||||
log_entry::{LocalizedLogEntry, LogEntry},
|
log_entry::{LocalizedLogEntry, LogEntry},
|
||||||
transaction::{Action, SignedTransaction, Transaction, UnverifiedTransaction},
|
transaction::{Action, SignedTransaction, Transaction, TypedTransaction},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn check_ok(result: Result<(), Error>) {
|
fn check_ok(result: Result<(), Error>) {
|
||||||
@ -764,34 +773,34 @@ mod tests {
|
|||||||
|
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate().unwrap();
|
||||||
|
|
||||||
let tr1 = Transaction {
|
let tr1 = TypedTransaction::Legacy(Transaction {
|
||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: U256::from(0),
|
value: U256::from(0),
|
||||||
data: Bytes::new(),
|
data: Bytes::new(),
|
||||||
gas: U256::from(30_000),
|
gas: U256::from(30_000),
|
||||||
gas_price: U256::from(40_000),
|
gas_price: U256::from(40_000),
|
||||||
nonce: U256::one(),
|
nonce: U256::one(),
|
||||||
}
|
})
|
||||||
.sign(keypair.secret(), None);
|
.sign(keypair.secret(), None);
|
||||||
|
|
||||||
let tr2 = Transaction {
|
let tr2 = TypedTransaction::Legacy(Transaction {
|
||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: U256::from(0),
|
value: U256::from(0),
|
||||||
data: Bytes::new(),
|
data: Bytes::new(),
|
||||||
gas: U256::from(30_000),
|
gas: U256::from(30_000),
|
||||||
gas_price: U256::from(40_000),
|
gas_price: U256::from(40_000),
|
||||||
nonce: U256::from(2),
|
nonce: U256::from(2),
|
||||||
}
|
})
|
||||||
.sign(keypair.secret(), None);
|
.sign(keypair.secret(), None);
|
||||||
|
|
||||||
let tr3 = Transaction {
|
let tr3 = TypedTransaction::Legacy(Transaction {
|
||||||
action: Action::Call(0x0.into()),
|
action: Action::Call(0x0.into()),
|
||||||
value: U256::from(0),
|
value: U256::from(0),
|
||||||
data: Bytes::new(),
|
data: Bytes::new(),
|
||||||
gas: U256::from(30_000),
|
gas: U256::from(30_000),
|
||||||
gas_price: U256::from(0),
|
gas_price: U256::from(0),
|
||||||
nonce: U256::zero(),
|
nonce: U256::zero(),
|
||||||
}
|
})
|
||||||
.null_sign(0);
|
.null_sign(0);
|
||||||
|
|
||||||
let good_transactions = [tr1.clone(), tr2.clone()];
|
let good_transactions = [tr1.clone(), tr2.clone()];
|
||||||
@ -834,16 +843,10 @@ mod tests {
|
|||||||
let mut uncles_rlp = RlpStream::new();
|
let mut uncles_rlp = RlpStream::new();
|
||||||
uncles_rlp.append_list(&good_uncles);
|
uncles_rlp.append_list(&good_uncles);
|
||||||
let good_uncles_hash = keccak(uncles_rlp.as_raw());
|
let good_uncles_hash = keccak(uncles_rlp.as_raw());
|
||||||
let good_transactions_root = ordered_trie_root(
|
let good_transactions_root =
|
||||||
good_transactions
|
ordered_trie_root(good_transactions.iter().map(|t| t.encode()));
|
||||||
.iter()
|
let eip86_transactions_root =
|
||||||
.map(|t| ::rlp::encode::<UnverifiedTransaction>(t)),
|
ordered_trie_root(eip86_transactions.iter().map(|t| t.encode()));
|
||||||
);
|
|
||||||
let eip86_transactions_root = ordered_trie_root(
|
|
||||||
eip86_transactions
|
|
||||||
.iter()
|
|
||||||
.map(|t| ::rlp::encode::<UnverifiedTransaction>(t)),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut parent = good.clone();
|
let mut parent = good.clone();
|
||||||
parent.set_number(9);
|
parent.set_number(9);
|
||||||
@ -1114,14 +1117,14 @@ mod tests {
|
|||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate().unwrap();
|
||||||
let bad_transactions: Vec<_> = (0..3)
|
let bad_transactions: Vec<_> = (0..3)
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
Transaction {
|
TypedTransaction::Legacy(Transaction {
|
||||||
action: Action::Create,
|
action: Action::Create,
|
||||||
value: U256::zero(),
|
value: U256::zero(),
|
||||||
data: Vec::new(),
|
data: Vec::new(),
|
||||||
gas: 0.into(),
|
gas: 0.into(),
|
||||||
gas_price: U256::zero(),
|
gas_price: U256::zero(),
|
||||||
nonce: i.into(),
|
nonce: i.into(),
|
||||||
}
|
})
|
||||||
.sign(keypair.secret(), None)
|
.sign(keypair.secret(), None)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -762,7 +762,7 @@ mod tests {
|
|||||||
use triehash_ethereum::ordered_trie_root;
|
use triehash_ethereum::ordered_trie_root;
|
||||||
use types::{
|
use types::{
|
||||||
header::Header as BlockHeader,
|
header::Header as BlockHeader,
|
||||||
transaction::{SignedTransaction, Transaction},
|
transaction::{SignedTransaction, Transaction, TypedTransaction},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn dummy_header(number: u64, parent_hash: H256) -> BlockHeader {
|
fn dummy_header(number: u64, parent_hash: H256) -> BlockHeader {
|
||||||
@ -778,7 +778,7 @@ mod tests {
|
|||||||
|
|
||||||
fn dummy_signed_tx() -> SignedTransaction {
|
fn dummy_signed_tx() -> SignedTransaction {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate().unwrap();
|
||||||
Transaction::default().sign(keypair.secret(), None)
|
TypedTransaction::Legacy(Transaction::default()).sign(keypair.secret(), None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_headers(
|
fn import_headers(
|
||||||
@ -949,8 +949,16 @@ mod tests {
|
|||||||
::rlp::EMPTY_LIST_RLP.to_vec()
|
::rlp::EMPTY_LIST_RLP.to_vec()
|
||||||
};
|
};
|
||||||
|
|
||||||
let txs = encode_list(&[dummy_signed_tx()]);
|
let mut rlp_strem = RlpStream::new();
|
||||||
let tx_root = ordered_trie_root(Rlp::new(&txs).iter().map(|r| r.as_raw()));
|
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);
|
let mut rlp = RlpStream::new_list(2);
|
||||||
rlp.append_raw(&txs, 1);
|
rlp.append_raw(&txs, 1);
|
||||||
@ -1019,14 +1027,20 @@ mod tests {
|
|||||||
// Construct the receipts. Receipt root for the first two blocks is the same.
|
// 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
|
// 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 {
|
let receipts_rlp = if i < 2 {
|
||||||
encode_list(&[0u32])
|
vec![0xC1, 0]
|
||||||
} else {
|
} else {
|
||||||
encode_list(&[i as u32])
|
vec![0xC1, i as u8]
|
||||||
};
|
};
|
||||||
let receipts_root =
|
let receipts_root = ordered_trie_root(Rlp::new(&receipts_rlp).iter().map(|r| {
|
||||||
ordered_trie_root(Rlp::new(&receipts_rlp).iter().map(|r| r.as_raw()));
|
if r.is_list() {
|
||||||
|
r.as_raw()
|
||||||
|
} else {
|
||||||
|
r.data().expect("expect proper test data")
|
||||||
|
}
|
||||||
|
}));
|
||||||
receipts.push(receipts_rlp);
|
receipts.push(receipts_rlp);
|
||||||
|
|
||||||
// Construct the block header.
|
// Construct the block header.
|
||||||
|
@ -23,7 +23,10 @@ use network;
|
|||||||
use rlp::{DecoderError, Rlp, RlpStream};
|
use rlp::{DecoderError, Rlp, RlpStream};
|
||||||
use std::collections::{hash_map, BTreeMap, HashMap, HashSet};
|
use std::collections::{hash_map, BTreeMap, HashMap, HashSet};
|
||||||
use triehash_ethereum::ordered_trie_root;
|
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);
|
known_heap_size!(0, HeaderId);
|
||||||
|
|
||||||
@ -65,7 +68,7 @@ impl SyncBody {
|
|||||||
|
|
||||||
let result = SyncBody {
|
let result = SyncBody {
|
||||||
transactions_bytes: transactions_rlp.as_raw().to_vec(),
|
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_bytes: uncles_rlp.as_raw().to_vec(),
|
||||||
uncles: uncles_rlp.as_list()?,
|
uncles: uncles_rlp.as_list()?,
|
||||||
};
|
};
|
||||||
@ -454,11 +457,14 @@ impl BlockCollection {
|
|||||||
|
|
||||||
fn insert_body(&mut self, body: SyncBody) -> Result<H256, network::Error> {
|
fn insert_body(&mut self, body: SyncBody) -> Result<H256, network::Error> {
|
||||||
let header_id = {
|
let header_id = {
|
||||||
let tx_root = ordered_trie_root(
|
let tx_root = ordered_trie_root(Rlp::new(&body.transactions_bytes).iter().map(|r| {
|
||||||
Rlp::new(&body.transactions_bytes)
|
if r.is_list() {
|
||||||
.iter()
|
r.as_raw()
|
||||||
.map(|r| 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);
|
let uncles = keccak(&body.uncles_bytes);
|
||||||
HeaderId {
|
HeaderId {
|
||||||
transactions_root: tx_root,
|
transactions_root: tx_root,
|
||||||
@ -491,7 +497,22 @@ impl BlockCollection {
|
|||||||
fn insert_receipt(&mut self, r: Bytes) -> Result<Vec<H256>, network::Error> {
|
fn insert_receipt(&mut self, r: Bytes) -> Result<Vec<H256>, network::Error> {
|
||||||
let receipt_root = {
|
let receipt_root = {
|
||||||
let receipts = Rlp::new(&r);
|
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);
|
self.downloading_receipts.remove(&receipt_root);
|
||||||
match self.receipt_ids.entry(receipt_root) {
|
match self.receipt_ids.entry(receipt_root) {
|
||||||
|
@ -837,9 +837,12 @@ impl SyncHandler {
|
|||||||
let item_count = r.item_count()?;
|
let item_count = r.item_count()?;
|
||||||
trace!(target: "sync", "{:02} -> Transactions ({} entries)", peer_id, item_count);
|
trace!(target: "sync", "{:02} -> Transactions ({} entries)", peer_id, item_count);
|
||||||
let mut transactions = Vec::with_capacity(item_count);
|
let mut transactions = Vec::with_capacity(item_count);
|
||||||
for i in 0..item_count {
|
for i in r.iter() {
|
||||||
let rlp = r.at(i)?;
|
let tx = if i.is_list() {
|
||||||
let tx = rlp.as_raw().to_vec();
|
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);
|
transactions.push(tx);
|
||||||
}
|
}
|
||||||
io.chain().queue_transactions(transactions, peer_id);
|
io.chain().queue_transactions(transactions, peer_id);
|
||||||
|
@ -21,7 +21,7 @@ use ethereum_types::H256;
|
|||||||
use fastmap::H256FastSet;
|
use fastmap::H256FastSet;
|
||||||
use network::{client_version::ClientCapabilities, PeerId};
|
use network::{client_version::ClientCapabilities, PeerId};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use rlp::{Encodable, RlpStream};
|
use rlp::RlpStream;
|
||||||
use sync_io::SyncIo;
|
use sync_io::SyncIo;
|
||||||
use types::{blockchain_info::BlockChainInfo, transaction::SignedTransaction, BlockNumber};
|
use types::{blockchain_info::BlockChainInfo, transaction::SignedTransaction, BlockNumber};
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ impl SyncPropagator {
|
|||||||
let (transactions, service_transactions): (Vec<_>, Vec<_>) = transactions
|
let (transactions, service_transactions): (Vec<_>, Vec<_>) = transactions
|
||||||
.iter()
|
.iter()
|
||||||
.map(|tx| tx.signed())
|
.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
|
// usual transactions could be propagated to all peers
|
||||||
let mut affected_peers = HashSet::new();
|
let mut affected_peers = HashSet::new();
|
||||||
@ -171,7 +171,7 @@ impl SyncPropagator {
|
|||||||
let all_transactions_rlp = {
|
let all_transactions_rlp = {
|
||||||
let mut packet = RlpStream::new_list(transactions.len());
|
let mut packet = RlpStream::new_list(transactions.len());
|
||||||
for tx in &transactions {
|
for tx in &transactions {
|
||||||
packet.append(&**tx);
|
tx.rlp_append(&mut packet);
|
||||||
}
|
}
|
||||||
packet.out()
|
packet.out()
|
||||||
};
|
};
|
||||||
@ -238,13 +238,8 @@ impl SyncPropagator {
|
|||||||
for tx in &transactions {
|
for tx in &transactions {
|
||||||
let hash = tx.hash();
|
let hash = tx.hash();
|
||||||
if to_send.contains(&hash) {
|
if to_send.contains(&hash) {
|
||||||
let mut transaction = RlpStream::new();
|
let appended =
|
||||||
tx.rlp_append(&mut transaction);
|
packet.append_raw_checked(&tx.encode(), 1, MAX_TRANSACTION_PACKET_SIZE);
|
||||||
let appended = packet.append_raw_checked(
|
|
||||||
&transaction.drain(),
|
|
||||||
1,
|
|
||||||
MAX_TRANSACTION_PACKET_SIZE,
|
|
||||||
);
|
|
||||||
if !appended {
|
if !appended {
|
||||||
// Maximal packet size reached just proceed with sending
|
// 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());
|
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 rlp::Rlp;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use tests::{helpers::TestIo, snapshot::TestSnapshotService};
|
use tests::{helpers::TestIo, snapshot::TestSnapshotService};
|
||||||
|
use types::transaction::TypedTransaction;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
super::{tests::*, *},
|
super::{tests::*, *},
|
||||||
@ -707,7 +703,9 @@ mod tests {
|
|||||||
return None;
|
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();
|
.collect();
|
||||||
assert_eq!(sent_transactions.len(), 2);
|
assert_eq!(sent_transactions.len(), 2);
|
||||||
|
@ -26,18 +26,18 @@ use ethkey::{KeyPair, Secret};
|
|||||||
use hash::keccak;
|
use hash::keccak;
|
||||||
use io::{IoChannel, IoHandler};
|
use io::{IoChannel, IoHandler};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use types::transaction::{Action, PendingTransaction, Transaction};
|
use types::transaction::{Action, PendingTransaction, Transaction, TypedTransaction};
|
||||||
use SyncConfig;
|
use SyncConfig;
|
||||||
|
|
||||||
fn new_tx(secret: &Secret, nonce: U256, chain_id: u64) -> PendingTransaction {
|
fn new_tx(secret: &Secret, nonce: U256, chain_id: u64) -> PendingTransaction {
|
||||||
let signed = Transaction {
|
let signed = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: nonce.into(),
|
nonce: nonce.into(),
|
||||||
gas_price: 0.into(),
|
gas_price: 0.into(),
|
||||||
gas: 21000.into(),
|
gas: 21000.into(),
|
||||||
action: Action::Call(Address::default()),
|
action: Action::Call(Address::default()),
|
||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
data: Vec::new(),
|
data: Vec::new(),
|
||||||
}
|
})
|
||||||
.sign(secret, Some(chain_id));
|
.sign(secret, Some(chain_id));
|
||||||
PendingTransaction::new(signed, None)
|
PendingTransaction::new(signed, None)
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,9 @@ parity-bytes = "0.1"
|
|||||||
rlp = { version = "0.3.0", features = ["ethereum"] }
|
rlp = { version = "0.3.0", features = ["ethereum"] }
|
||||||
rlp_derive = { path = "../../util/rlp-derive" }
|
rlp_derive = { path = "../../util/rlp-derive" }
|
||||||
unexpected = { path = "../../util/unexpected" }
|
unexpected = { path = "../../util/unexpected" }
|
||||||
|
serde = "1.0"
|
||||||
|
serde_json = "1.0"
|
||||||
|
serde_repr = "0.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rustc-hex = "1.0"
|
rustc-hex = "1.0"
|
||||||
|
@ -35,7 +35,7 @@ use bytes::Bytes;
|
|||||||
|
|
||||||
use header::Header;
|
use header::Header;
|
||||||
use rlp::{Decodable, DecoderError, Rlp, RlpStream};
|
use rlp::{Decodable, DecoderError, Rlp, RlpStream};
|
||||||
use transaction::UnverifiedTransaction;
|
use transaction::{TypedTransaction, UnverifiedTransaction};
|
||||||
|
|
||||||
/// A block, encoded as it is on the block chain.
|
/// A block, encoded as it is on the block chain.
|
||||||
#[derive(Default, Debug, Clone, PartialEq)]
|
#[derive(Default, Debug, Clone, PartialEq)]
|
||||||
@ -53,7 +53,7 @@ impl Block {
|
|||||||
pub fn rlp_bytes(&self) -> Bytes {
|
pub fn rlp_bytes(&self) -> Bytes {
|
||||||
let mut block_rlp = RlpStream::new_list(3);
|
let mut block_rlp = RlpStream::new_list(3);
|
||||||
block_rlp.append(&self.header);
|
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.append_list(&self.uncles);
|
||||||
block_rlp.out()
|
block_rlp.out()
|
||||||
}
|
}
|
||||||
@ -69,7 +69,7 @@ impl Decodable for Block {
|
|||||||
}
|
}
|
||||||
Ok(Block {
|
Ok(Block {
|
||||||
header: rlp.val_at(0)?,
|
header: rlp.val_at(0)?,
|
||||||
transactions: rlp.list_at(1)?,
|
transactions: TypedTransaction::decode_rlp_list(&rlp.at(1)?)?,
|
||||||
uncles: rlp.list_at(2)?,
|
uncles: rlp.list_at(2)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ extern crate heapsize;
|
|||||||
extern crate keccak_hash as hash;
|
extern crate keccak_hash as hash;
|
||||||
extern crate parity_bytes as bytes;
|
extern crate parity_bytes as bytes;
|
||||||
extern crate rlp;
|
extern crate rlp;
|
||||||
|
extern crate serde_repr;
|
||||||
extern crate unexpected;
|
extern crate unexpected;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -16,9 +16,14 @@
|
|||||||
|
|
||||||
//! Receipt
|
//! Receipt
|
||||||
|
|
||||||
|
use super::transaction::TypedTxId;
|
||||||
use ethereum_types::{Address, Bloom, H160, H256, U256};
|
use ethereum_types::{Address, Bloom, H160, H256, U256};
|
||||||
use heapsize::HeapSizeOf;
|
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 log_entry::{LocalizedLogEntry, LogEntry};
|
||||||
use BlockNumber;
|
use BlockNumber;
|
||||||
@ -36,7 +41,7 @@ pub enum TransactionOutcome {
|
|||||||
|
|
||||||
/// Information describing execution of a transaction.
|
/// Information describing execution of a transaction.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Receipt {
|
pub struct LegacyReceipt {
|
||||||
/// The total gas used in the block following execution of the transaction.
|
/// The total gas used in the block following execution of the transaction.
|
||||||
pub gas_used: U256,
|
pub gas_used: U256,
|
||||||
/// The OR-wide combination of all logs' blooms for this transaction.
|
/// The OR-wide combination of all logs' blooms for this transaction.
|
||||||
@ -47,10 +52,9 @@ pub struct Receipt {
|
|||||||
pub outcome: TransactionOutcome,
|
pub outcome: TransactionOutcome,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Receipt {
|
impl LegacyReceipt {
|
||||||
/// Create a new receipt.
|
|
||||||
pub fn new(outcome: TransactionOutcome, gas_used: U256, logs: Vec<LogEntry>) -> Self {
|
pub fn new(outcome: TransactionOutcome, gas_used: U256, logs: Vec<LogEntry>) -> Self {
|
||||||
Self {
|
LegacyReceipt {
|
||||||
gas_used,
|
gas_used,
|
||||||
log_bloom: logs.iter().fold(Bloom::default(), |mut b, l| {
|
log_bloom: logs.iter().fold(Bloom::default(), |mut b, l| {
|
||||||
b.accrue_bloom(&l.bloom());
|
b.accrue_bloom(&l.bloom());
|
||||||
@ -60,10 +64,32 @@ impl Receipt {
|
|||||||
outcome,
|
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 {
|
pub fn rlp_append(&self, s: &mut RlpStream) {
|
||||||
fn rlp_append(&self, s: &mut RlpStream) {
|
|
||||||
match self.outcome {
|
match self.outcome {
|
||||||
TransactionOutcome::Unknown => {
|
TransactionOutcome::Unknown => {
|
||||||
s.begin_list(3);
|
s.begin_list(3);
|
||||||
@ -83,42 +109,142 @@ impl Encodable for Receipt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decodable for Receipt {
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
pub enum TypedReceipt {
|
||||||
if rlp.item_count()? == 3 {
|
Legacy(LegacyReceipt),
|
||||||
Ok(Receipt {
|
AccessList(LegacyReceipt),
|
||||||
outcome: TransactionOutcome::Unknown,
|
}
|
||||||
gas_used: rlp.val_at(0)?,
|
|
||||||
log_bloom: rlp.val_at(1)?,
|
impl TypedReceipt {
|
||||||
logs: rlp.list_at(2)?,
|
/// 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 {
|
} else {
|
||||||
Ok(Receipt {
|
Self::decode(rlp.data()?)
|
||||||
gas_used: rlp.val_at(1)?,
|
}
|
||||||
log_bloom: rlp.val_at(2)?,
|
}
|
||||||
logs: rlp.list_at(3)?,
|
|
||||||
outcome: {
|
pub fn decode_rlp_list(rlp: &Rlp) -> Result<Vec<Self>, DecoderError> {
|
||||||
let first = rlp.at(0)?;
|
if !rlp.is_list() {
|
||||||
if first.is_data() && first.data()?.len() <= 1 {
|
// at least one byte needs to be present
|
||||||
TransactionOutcome::StatusCode(first.as_val()?)
|
return Err(DecoderError::RlpIncorrectListLen);
|
||||||
} else {
|
}
|
||||||
TransactionOutcome::StateRoot(first.as_val()?)
|
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 {
|
fn heap_size_of_children(&self) -> usize {
|
||||||
self.logs.heap_size_of_children()
|
self.receipt().logs.heap_size_of_children()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Receipt with additional info.
|
/// Receipt with additional info.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct RichReceipt {
|
pub struct RichReceipt {
|
||||||
|
/// Transaction type
|
||||||
|
pub transaction_type: TypedTxId,
|
||||||
/// Transaction hash.
|
/// Transaction hash.
|
||||||
pub transaction_hash: H256,
|
pub transaction_hash: H256,
|
||||||
/// Transaction index.
|
/// Transaction index.
|
||||||
@ -146,6 +272,8 @@ pub struct RichReceipt {
|
|||||||
/// Receipt with additional info.
|
/// Receipt with additional info.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct LocalizedReceipt {
|
pub struct LocalizedReceipt {
|
||||||
|
/// Transaction type
|
||||||
|
pub transaction_type: TypedTxId,
|
||||||
/// Transaction hash.
|
/// Transaction hash.
|
||||||
pub transaction_hash: H256,
|
pub transaction_hash: H256,
|
||||||
/// Transaction index.
|
/// Transaction index.
|
||||||
@ -176,59 +304,91 @@ pub struct LocalizedReceipt {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{Receipt, TransactionOutcome};
|
use super::{LegacyReceipt, TransactionOutcome, TypedReceipt, TypedTxId};
|
||||||
use log_entry::LogEntry;
|
use log_entry::LogEntry;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_no_state_root() {
|
fn test_no_state_root() {
|
||||||
let expected = ::rustc_hex::FromHex::from_hex("f9014183040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
let expected = ::rustc_hex::FromHex::from_hex("f9014183040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||||
let r = Receipt::new(
|
let r = TypedReceipt::new(
|
||||||
TransactionOutcome::Unknown,
|
TypedTxId::Legacy,
|
||||||
0x40cae.into(),
|
LegacyReceipt::new(
|
||||||
vec![LogEntry {
|
TransactionOutcome::Unknown,
|
||||||
address: "dcf421d093428b096ca501a7cd1a740855a7976f".into(),
|
0x40cae.into(),
|
||||||
topics: vec![],
|
vec![LogEntry {
|
||||||
data: vec![0u8; 32],
|
address: "dcf421d093428b096ca501a7cd1a740855a7976f".into(),
|
||||||
}],
|
topics: vec![],
|
||||||
|
data: vec![0u8; 32],
|
||||||
|
}],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
assert_eq!(&::rlp::encode(&r)[..], &expected[..]);
|
assert_eq!(r.encode(), expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_basic() {
|
fn test_basic_legacy() {
|
||||||
let expected = ::rustc_hex::FromHex::from_hex("f90162a02f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee83040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
let expected = ::rustc_hex::FromHex::from_hex("f90162a02f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee83040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||||
let r = Receipt::new(
|
let r = TypedReceipt::new(
|
||||||
TransactionOutcome::StateRoot(
|
TypedTxId::Legacy,
|
||||||
"2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee".into(),
|
LegacyReceipt::new(
|
||||||
|
TransactionOutcome::StateRoot(
|
||||||
|
"2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee".into(),
|
||||||
|
),
|
||||||
|
0x40cae.into(),
|
||||||
|
vec![LogEntry {
|
||||||
|
address: "dcf421d093428b096ca501a7cd1a740855a7976f".into(),
|
||||||
|
topics: vec![],
|
||||||
|
data: vec![0u8; 32],
|
||||||
|
}],
|
||||||
),
|
),
|
||||||
0x40cae.into(),
|
|
||||||
vec![LogEntry {
|
|
||||||
address: "dcf421d093428b096ca501a7cd1a740855a7976f".into(),
|
|
||||||
topics: vec![],
|
|
||||||
data: vec![0u8; 32],
|
|
||||||
}],
|
|
||||||
);
|
);
|
||||||
let encoded = ::rlp::encode(&r);
|
let encoded = r.encode();
|
||||||
assert_eq!(&encoded[..], &expected[..]);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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);
|
assert_eq!(decoded, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_status_code() {
|
fn test_status_code() {
|
||||||
let expected = ::rustc_hex::FromHex::from_hex("f901428083040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
let expected = ::rustc_hex::FromHex::from_hex("f901428083040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||||
let r = Receipt::new(
|
let r = TypedReceipt::new(
|
||||||
TransactionOutcome::StatusCode(0),
|
TypedTxId::Legacy,
|
||||||
0x40cae.into(),
|
LegacyReceipt::new(
|
||||||
vec![LogEntry {
|
TransactionOutcome::StatusCode(0),
|
||||||
address: "dcf421d093428b096ca501a7cd1a740855a7976f".into(),
|
0x40cae.into(),
|
||||||
topics: vec![],
|
vec![LogEntry {
|
||||||
data: vec![0u8; 32],
|
address: "dcf421d093428b096ca501a7cd1a740855a7976f".into(),
|
||||||
}],
|
topics: vec![],
|
||||||
|
data: vec![0u8; 32],
|
||||||
|
}],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
let encoded = ::rlp::encode(&r);
|
let encoded = r.encode();
|
||||||
assert_eq!(&encoded[..], &expected[..]);
|
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);
|
assert_eq!(decoded, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,6 +84,8 @@ pub enum Error {
|
|||||||
TooBig,
|
TooBig,
|
||||||
/// Invalid RLP encoding
|
/// Invalid RLP encoding
|
||||||
InvalidRlp(String),
|
InvalidRlp(String),
|
||||||
|
/// Transaciton is still not enabled.
|
||||||
|
TransactionTypeNotEnabled,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ethkey::Error> for Error {
|
impl From<ethkey::Error> for Error {
|
||||||
@ -133,6 +135,9 @@ impl fmt::Display for Error {
|
|||||||
}
|
}
|
||||||
TooBig => "Transaction too big".into(),
|
TooBig => "Transaction too big".into(),
|
||||||
InvalidRlp(ref err) => format!("Transaction has invalid RLP structure: {}.", err),
|
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))
|
f.write_fmt(format_args!("Transaction error ({})", msg))
|
||||||
|
@ -18,5 +18,6 @@
|
|||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
mod transaction;
|
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 ethereum_types::H256;
|
||||||
use hash::keccak;
|
use hash::keccak;
|
||||||
use header::Header;
|
use header::Header;
|
||||||
use transaction::{LocalizedTransaction, UnverifiedTransaction};
|
use transaction::{LocalizedTransaction, TypedTransaction, UnverifiedTransaction};
|
||||||
use views::{HeaderView, TransactionView};
|
use views::{HeaderView, TransactionView};
|
||||||
|
|
||||||
/// View onto block rlp.
|
/// View onto block rlp.
|
||||||
@ -77,7 +77,12 @@ impl<'a> BlockView<'a> {
|
|||||||
|
|
||||||
/// Return List of transactions in given block.
|
/// Return List of transactions in given block.
|
||||||
pub fn transactions(&self) -> Vec<UnverifiedTransaction> {
|
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.
|
/// 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.
|
/// Returns transaction at given index without deserializing unnecessary data.
|
||||||
pub fn transaction_at(&self, index: usize) -> Option<UnverifiedTransaction> {
|
pub fn transaction_at(&self, index: usize) -> Option<UnverifiedTransaction> {
|
||||||
self.transactions_rlp()
|
self.transactions_rlp().iter().nth(index).map(|rlp| {
|
||||||
.iter()
|
TypedTransaction::decode_rlp(&rlp.rlp).unwrap_or_else(|e| {
|
||||||
.nth(index)
|
panic!(
|
||||||
.map(|rlp| rlp.as_val())
|
"block transaction_at, view rlp is trusted and should be valid.{:?}",
|
||||||
|
e
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns localized transaction at given index.
|
/// Returns localized transaction at given index.
|
||||||
|
@ -21,7 +21,7 @@ use bytes::Bytes;
|
|||||||
use ethereum_types::H256;
|
use ethereum_types::H256;
|
||||||
use hash::keccak;
|
use hash::keccak;
|
||||||
use header::Header;
|
use header::Header;
|
||||||
use transaction::{LocalizedTransaction, UnverifiedTransaction};
|
use transaction::{LocalizedTransaction, TypedTransaction, UnverifiedTransaction};
|
||||||
use views::{HeaderView, TransactionView};
|
use views::{HeaderView, TransactionView};
|
||||||
use BlockNumber;
|
use BlockNumber;
|
||||||
|
|
||||||
@ -58,7 +58,12 @@ impl<'a> BodyView<'a> {
|
|||||||
|
|
||||||
/// Return List of transactions in given block.
|
/// Return List of transactions in given block.
|
||||||
pub fn transactions(&self) -> Vec<UnverifiedTransaction> {
|
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.
|
/// 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.
|
/// Returns transaction at given index without deserializing unnecessary data.
|
||||||
pub fn transaction_at(&self, index: usize) -> Option<UnverifiedTransaction> {
|
pub fn transaction_at(&self, index: usize) -> Option<UnverifiedTransaction> {
|
||||||
self.transactions_rlp()
|
self.transactions_rlp().iter().nth(index).map(|rlp| {
|
||||||
.iter()
|
TypedTransaction::decode_rlp(&rlp.rlp).unwrap_or_else(|e| {
|
||||||
.nth(index)
|
panic!(
|
||||||
.map(|rlp| rlp.as_val())
|
"body transaction_a, view rlp is trusted and should be valid: {:?}",
|
||||||
|
e
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns localized transaction at given index.
|
/// Returns localized transaction at given index.
|
||||||
|
@ -213,7 +213,7 @@ mod tests {
|
|||||||
access_list.insert_address(Address::from(1));
|
access_list.insert_address(Address::from(1));
|
||||||
access_list.insert_storage_key(Address::from(2), H256::from(3));
|
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, access_list_call.contains_address(&Address::from(1)));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
true,
|
true,
|
||||||
|
@ -24,6 +24,10 @@ pub const EIP2929_COLD_ACCOUNT_ACCESS_COST: usize = 2600;
|
|||||||
pub const EIP2929_WARM_STORAGE_READ_COST: usize = 100;
|
pub const EIP2929_WARM_STORAGE_READ_COST: usize = 100;
|
||||||
// Gas per sstore reset
|
// Gas per sstore reset
|
||||||
pub const EIP2929_SSTORE_RESET_GAS: usize = 5000 - EIP2929_COLD_SLOAD_COST;
|
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.
|
/// Definition of the cost schedule and other parameterisations for the EVM.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -149,6 +153,8 @@ pub struct Schedule {
|
|||||||
pub wasm: Option<WasmCosts>,
|
pub wasm: Option<WasmCosts>,
|
||||||
/// Enable EIP-2929 rules
|
/// Enable EIP-2929 rules
|
||||||
pub eip2929: bool,
|
pub eip2929: bool,
|
||||||
|
/// Enable EIP-2930 rules for optional access list transactions. it depends on EIP-2929
|
||||||
|
pub eip2930: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wasm cost table
|
/// Wasm cost table
|
||||||
@ -295,6 +301,7 @@ impl Schedule {
|
|||||||
keep_unsigned_nonce: false,
|
keep_unsigned_nonce: false,
|
||||||
wasm: None,
|
wasm: None,
|
||||||
eip2929: false,
|
eip2929: false,
|
||||||
|
eip2930: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,6 +350,7 @@ impl Schedule {
|
|||||||
|
|
||||||
schedule.eip1283 = true;
|
schedule.eip1283 = true;
|
||||||
schedule.eip2929 = true;
|
schedule.eip2929 = true;
|
||||||
|
schedule.eip2930 = true;
|
||||||
|
|
||||||
schedule.cold_sload_cost = EIP2929_COLD_SLOAD_COST;
|
schedule.cold_sload_cost = EIP2929_COLD_SLOAD_COST;
|
||||||
schedule.cold_account_access_cost = EIP2929_COLD_ACCOUNT_ACCESS_COST;
|
schedule.cold_account_access_cost = EIP2929_COLD_ACCOUNT_ACCESS_COST;
|
||||||
@ -421,6 +429,7 @@ impl Schedule {
|
|||||||
keep_unsigned_nonce: false,
|
keep_unsigned_nonce: false,
|
||||||
wasm: None,
|
wasm: None,
|
||||||
eip2929: false,
|
eip2929: false,
|
||||||
|
eip2930: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@ pub fn run_transaction<T: Informant>(
|
|||||||
let result = run(
|
let result = run(
|
||||||
&spec,
|
&spec,
|
||||||
trie_spec,
|
trie_spec,
|
||||||
transaction.gas,
|
transaction.tx().gas,
|
||||||
pre_state,
|
pre_state,
|
||||||
|mut client| {
|
|mut client| {
|
||||||
let result = client.transact(env_info, transaction, trace::NoopTracer, informant);
|
let result = client.transact(env_info, transaction, trace::NoopTracer, informant);
|
||||||
|
@ -108,6 +108,8 @@ pub struct Params {
|
|||||||
/// See `CommonParams` docs.
|
/// See `CommonParams` docs.
|
||||||
pub eip2929_transition: Option<Uint>,
|
pub eip2929_transition: Option<Uint>,
|
||||||
/// See `CommonParams` docs.
|
/// See `CommonParams` docs.
|
||||||
|
pub eip2930_transition: Option<Uint>,
|
||||||
|
/// See `CommonParams` docs.
|
||||||
pub dust_protection_transition: Option<Uint>,
|
pub dust_protection_transition: Option<Uint>,
|
||||||
/// See `CommonParams` docs.
|
/// See `CommonParams` docs.
|
||||||
pub nonce_cap_increment: Option<Uint>,
|
pub nonce_cap_increment: Option<Uint>,
|
||||||
|
@ -20,9 +20,9 @@ use std::{fmt, sync::Arc, time::Duration};
|
|||||||
|
|
||||||
use io::IoHandler;
|
use io::IoHandler;
|
||||||
use kvdb::KeyValueDB;
|
use kvdb::KeyValueDB;
|
||||||
use rlp::Rlp;
|
|
||||||
use types::transaction::{
|
use types::transaction::{
|
||||||
Condition as TransactionCondition, PendingTransaction, SignedTransaction, UnverifiedTransaction,
|
Condition as TransactionCondition, PendingTransaction, SignedTransaction, TypedTransaction,
|
||||||
|
UnverifiedTransaction,
|
||||||
};
|
};
|
||||||
|
|
||||||
extern crate common_types as types;
|
extern crate common_types as types;
|
||||||
@ -98,7 +98,7 @@ struct TransactionEntry {
|
|||||||
|
|
||||||
impl TransactionEntry {
|
impl TransactionEntry {
|
||||||
fn into_pending(self) -> Option<PendingTransaction> {
|
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) => {
|
Err(e) => {
|
||||||
warn!(target: "local_store", "Invalid persistent transaction stored: {}", e);
|
warn!(target: "local_store", "Invalid persistent transaction stored: {}", e);
|
||||||
return None;
|
return None;
|
||||||
@ -120,7 +120,7 @@ impl TransactionEntry {
|
|||||||
impl From<PendingTransaction> for TransactionEntry {
|
impl From<PendingTransaction> for TransactionEntry {
|
||||||
fn from(pending: PendingTransaction) -> Self {
|
fn from(pending: PendingTransaction) -> Self {
|
||||||
TransactionEntry {
|
TransactionEntry {
|
||||||
rlp_bytes: ::rlp::encode(&pending.transaction),
|
rlp_bytes: pending.transaction.encode(),
|
||||||
condition: pending.condition.map(Into::into),
|
condition: pending.condition.map(Into::into),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -239,7 +239,7 @@ mod tests {
|
|||||||
|
|
||||||
use ethkey::{Brain, Generator};
|
use ethkey::{Brain, Generator};
|
||||||
use std::sync::Arc;
|
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.
|
// we want to test: round-trip of good transactions.
|
||||||
// failure to roundtrip bad transactions (but that it doesn't panic)
|
// 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 keypair = Brain::new("abcd".into()).generate().unwrap();
|
||||||
let transactions: Vec<_> = (0..10u64)
|
let transactions: Vec<_> = (0..10u64)
|
||||||
.map(|nonce| {
|
.map(|nonce| {
|
||||||
let mut tx = Transaction::default();
|
let mut tx = TypedTransaction::Legacy(Transaction::default());
|
||||||
tx.nonce = nonce.into();
|
tx.tx_mut().nonce = nonce.into();
|
||||||
|
|
||||||
let signed = tx.sign(keypair.secret(), None);
|
let signed = tx.sign(keypair.secret(), None);
|
||||||
let condition = match nonce {
|
let condition = match nonce {
|
||||||
@ -308,8 +308,8 @@ mod tests {
|
|||||||
let keypair = Brain::new("abcd".into()).generate().unwrap();
|
let keypair = Brain::new("abcd".into()).generate().unwrap();
|
||||||
let mut transactions: Vec<_> = (0..10u64)
|
let mut transactions: Vec<_> = (0..10u64)
|
||||||
.map(|nonce| {
|
.map(|nonce| {
|
||||||
let mut tx = Transaction::default();
|
let mut tx = TypedTransaction::Legacy(Transaction::default());
|
||||||
tx.nonce = nonce.into();
|
tx.tx_mut().nonce = nonce.into();
|
||||||
|
|
||||||
let signed = tx.sign(keypair.secret(), None);
|
let signed = tx.sign(keypair.secret(), None);
|
||||||
|
|
||||||
@ -318,8 +318,8 @@ mod tests {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
transactions.push({
|
transactions.push({
|
||||||
let mut tx = Transaction::default();
|
let mut tx = TypedTransaction::Legacy(Transaction::default());
|
||||||
tx.nonce = 10.into();
|
tx.tx_mut().nonce = 10.into();
|
||||||
|
|
||||||
let signed = tx.fake_sign(Default::default());
|
let signed = tx.fake_sign(Default::default());
|
||||||
PendingTransaction::new(signed, None)
|
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:?}] Sender: {sender}, nonce: {nonce}, gasPrice: {gas_price}, gas: {gas}, value: {value}, dataLen: {data}))",
|
||||||
hash = tx.hash(),
|
hash = tx.hash(),
|
||||||
sender = tx.sender(),
|
sender = tx.sender(),
|
||||||
nonce = tx.signed().nonce,
|
nonce = tx.signed().tx().nonce,
|
||||||
gas_price = tx.signed().gas_price,
|
gas_price = tx.signed().tx().gas_price,
|
||||||
gas = tx.signed().gas,
|
gas = tx.signed().tx().gas,
|
||||||
value = tx.signed().value,
|
value = tx.signed().tx().value,
|
||||||
data = tx.signed().data.len(),
|
data = tx.signed().tx().data.len(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(old) = old {
|
if let Some(old) = old {
|
||||||
@ -150,7 +150,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
*received.lock(),
|
*received.lock(),
|
||||||
vec![
|
vec![
|
||||||
"13aff4201ac1dc49daf6a7cf07b558ed956511acbaabf9502bdacc353953766d"
|
"de96bdcdf864c95eb7f81eff1e3290be24a0f327732e0c4251c1896a565a80db"
|
||||||
.parse()
|
.parse()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
]
|
]
|
||||||
@ -158,14 +158,14 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new_tx() -> Arc<Transaction> {
|
fn new_tx() -> Arc<Transaction> {
|
||||||
let signed = transaction::Transaction {
|
let signed = transaction::TypedTransaction::Legacy(transaction::Transaction {
|
||||||
action: transaction::Action::Create,
|
action: transaction::Action::Create,
|
||||||
data: vec![1, 2, 3],
|
data: vec![1, 2, 3],
|
||||||
nonce: 5.into(),
|
nonce: 5.into(),
|
||||||
gas: 21_000.into(),
|
gas: 21_000.into(),
|
||||||
gas_price: 5.into(),
|
gas_price: 5.into(),
|
||||||
value: 0.into(),
|
value: 0.into(),
|
||||||
}
|
})
|
||||||
.fake_sign(5.into());
|
.fake_sign(5.into());
|
||||||
|
|
||||||
Arc::new(Transaction::from_pending_block_transaction(signed))
|
Arc::new(Transaction::from_pending_block_transaction(signed))
|
||||||
|
@ -340,14 +340,14 @@ mod tests {
|
|||||||
|
|
||||||
fn new_tx<T: Into<U256>>(nonce: T) -> Arc<Transaction> {
|
fn new_tx<T: Into<U256>>(nonce: T) -> Arc<Transaction> {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate().unwrap();
|
||||||
let signed = transaction::Transaction {
|
let signed = transaction::TypedTransaction::Legacy(transaction::Transaction {
|
||||||
action: transaction::Action::Create,
|
action: transaction::Action::Create,
|
||||||
value: U256::from(100),
|
value: U256::from(100),
|
||||||
data: Default::default(),
|
data: Default::default(),
|
||||||
gas: U256::from(10),
|
gas: U256::from(10),
|
||||||
gas_price: U256::from(1245),
|
gas_price: U256::from(1245),
|
||||||
nonce: nonce.into(),
|
nonce: nonce.into(),
|
||||||
}
|
})
|
||||||
.sign(keypair.secret(), None);
|
.sign(keypair.secret(), None);
|
||||||
|
|
||||||
let mut tx = Transaction::from_pending_block_transaction(signed);
|
let mut tx = Transaction::from_pending_block_transaction(signed);
|
||||||
|
@ -192,11 +192,11 @@ impl ScoredTransaction for VerifiedTransaction {
|
|||||||
|
|
||||||
/// Gets transaction gas price.
|
/// Gets transaction gas price.
|
||||||
fn gas_price(&self) -> &U256 {
|
fn gas_price(&self) -> &U256 {
|
||||||
&self.transaction.gas_price
|
&self.transaction.tx().gas_price
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets transaction nonce.
|
/// Gets transaction nonce.
|
||||||
fn nonce(&self) -> U256 {
|
fn nonce(&self) -> U256 {
|
||||||
self.transaction.nonce
|
self.transaction.tx().nonce
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -519,7 +519,7 @@ impl TransactionQueue {
|
|||||||
.read()
|
.read()
|
||||||
.pending_from_sender(state_readiness, address)
|
.pending_from_sender(state_readiness, address)
|
||||||
.last()
|
.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.
|
/// Retrieve a transaction from the pool.
|
||||||
@ -573,7 +573,7 @@ impl TransactionQueue {
|
|||||||
/// Returns gas price of currently the worst transaction in the pool.
|
/// Returns gas price of currently the worst transaction in the pool.
|
||||||
pub fn current_worst_gas_price(&self) -> U256 {
|
pub fn current_worst_gas_price(&self) -> U256 {
|
||||||
match self.pool.read().worst_transaction() {
|
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,
|
None => self.options.read().minimal_gas_price,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -660,7 +660,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
for tx in pending {
|
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 {
|
fn is_ready(&mut self, tx: &VerifiedTransaction) -> txpool::Readiness {
|
||||||
// Check max nonce
|
// Check max nonce
|
||||||
match self.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;
|
return txpool::Readiness::Future;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -81,7 +81,7 @@ impl<C: NonceClient> txpool::Ready<VerifiedTransaction> for State<C> {
|
|||||||
let state = &self.state;
|
let state = &self.state;
|
||||||
let state_nonce = || state.account_nonce(sender);
|
let state_nonce = || state.account_nonce(sender);
|
||||||
let nonce = self.nonces.entry(*sender).or_insert_with(state_nonce);
|
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
|
// Before marking as future check for stale ids
|
||||||
cmp::Ordering::Greater => match self.stale_id {
|
cmp::Ordering::Greater => match self.stale_id {
|
||||||
Some(id) if tx.insertion_id() < id => txpool::Readiness::Stale,
|
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
|
let nonce = self
|
||||||
.nonces
|
.nonces
|
||||||
.entry(*sender)
|
.entry(*sender)
|
||||||
.or_insert_with(|| state(sender).unwrap_or_else(|| tx.transaction.nonce));
|
.or_insert_with(|| state(sender).unwrap_or_else(|| tx.transaction.tx().nonce));
|
||||||
match tx.transaction.nonce.cmp(nonce) {
|
match tx.transaction.tx().nonce.cmp(nonce) {
|
||||||
cmp::Ordering::Greater => txpool::Readiness::Future,
|
cmp::Ordering::Greater => txpool::Readiness::Future,
|
||||||
cmp::Ordering::Less => txpool::Readiness::Stale,
|
cmp::Ordering::Less => txpool::Readiness::Stale,
|
||||||
cmp::Ordering::Equal => {
|
cmp::Ordering::Equal => {
|
||||||
|
@ -67,7 +67,7 @@ impl NonceAndGasPrice {
|
|||||||
return true;
|
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 ethereum_types::{Address, H256, U256};
|
||||||
use rlp::Rlp;
|
use rlp::Rlp;
|
||||||
use types::transaction::{self, SignedTransaction, Transaction, UnverifiedTransaction};
|
use types::transaction::{
|
||||||
|
self, SignedTransaction, Transaction, TypedTransaction, UnverifiedTransaction,
|
||||||
|
};
|
||||||
|
|
||||||
use pool::{self, client::AccountDetails};
|
use pool::{self, client::AccountDetails};
|
||||||
|
|
||||||
@ -150,7 +152,7 @@ impl pool::client::Client for TestClient {
|
|||||||
if rlp.as_raw().len() > self.max_transaction_size {
|
if rlp.as_raw().len() > self.max_transaction_size {
|
||||||
return Err(transaction::Error::TooBig);
|
return Err(transaction::Error::TooBig);
|
||||||
}
|
}
|
||||||
rlp.as_val()
|
TypedTransaction::decode(transaction)
|
||||||
.map_err(|e| transaction::Error::InvalidRlp(e.to_string()))
|
.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 (tx1, tx2) = Tx::gas_price(2).signed_pair();
|
||||||
let sender = tx1.sender();
|
let sender = tx1.sender();
|
||||||
let nonce = tx1.nonce;
|
let nonce = tx1.tx().nonce;
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let r1 = txq.import(TestClient::new(), vec![tx1].retracted());
|
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 (tx1, tx2) = Tx::gas_price(2).signed_pair();
|
||||||
let sender = tx1.sender();
|
let sender = tx1.sender();
|
||||||
let nonce = tx1.nonce;
|
let nonce = tx1.tx().nonce;
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let r1 = txq.import(TestClient::new(), vec![tx1].local());
|
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!(
|
assert_eq!(
|
||||||
txq.pending(client.clone(), PendingSettings::all_prioritized(0, 0))[0]
|
txq.pending(client.clone(), PendingSettings::all_prioritized(0, 0))[0]
|
||||||
.signed()
|
.signed()
|
||||||
|
.tx()
|
||||||
.gas_price,
|
.gas_price,
|
||||||
U256::from(20)
|
U256::from(20)
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
txq.pending(client.clone(), PendingSettings::all_prioritized(0, 0))[1]
|
txq.pending(client.clone(), PendingSettings::all_prioritized(0, 0))[1]
|
||||||
.signed()
|
.signed()
|
||||||
|
.tx()
|
||||||
.gas_price,
|
.gas_price,
|
||||||
U256::from(2)
|
U256::from(2)
|
||||||
);
|
);
|
||||||
@ -688,7 +690,7 @@ fn should_return_correct_nonce_when_transactions_from_given_address_exist() {
|
|||||||
let txq = new_queue();
|
let txq = new_queue();
|
||||||
let tx = Tx::default().signed();
|
let tx = Tx::default().signed();
|
||||||
let from = tx.sender();
|
let from = tx.sender();
|
||||||
let nonce = tx.nonce;
|
let nonce = tx.tx().nonce;
|
||||||
|
|
||||||
// when
|
// when
|
||||||
txq.import(TestClient::new(), vec![tx.local()]);
|
txq.import(TestClient::new(), vec![tx.local()]);
|
||||||
|
@ -17,7 +17,9 @@
|
|||||||
use ethereum_types::{H256, U256};
|
use ethereum_types::{H256, U256};
|
||||||
use ethkey::{Generator, Random};
|
use ethkey::{Generator, Random};
|
||||||
use rustc_hex::FromHex;
|
use rustc_hex::FromHex;
|
||||||
use types::transaction::{self, SignedTransaction, Transaction, UnverifiedTransaction};
|
use types::transaction::{
|
||||||
|
self, SignedTransaction, Transaction, TypedTransaction, UnverifiedTransaction,
|
||||||
|
};
|
||||||
|
|
||||||
use pool::{verifier, VerifiedTransaction};
|
use pool::{verifier, VerifiedTransaction};
|
||||||
|
|
||||||
@ -76,20 +78,20 @@ impl Tx {
|
|||||||
(tx1, tx2)
|
(tx1, tx2)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unsigned(self) -> Transaction {
|
pub fn unsigned(self) -> TypedTransaction {
|
||||||
Transaction {
|
TypedTransaction::Legacy(Transaction {
|
||||||
action: transaction::Action::Create,
|
action: transaction::Action::Create,
|
||||||
value: U256::from(100),
|
value: U256::from(100),
|
||||||
data: "3331600055".from_hex().unwrap(),
|
data: "3331600055".from_hex().unwrap(),
|
||||||
gas: self.gas.into(),
|
gas: self.gas.into(),
|
||||||
gas_price: self.gas_price.into(),
|
gas_price: self.gas_price.into(),
|
||||||
nonce: self.nonce.into(),
|
nonce: self.nonce.into(),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn big_one(self) -> SignedTransaction {
|
pub fn big_one(self) -> SignedTransaction {
|
||||||
let keypair = Random.generate().unwrap();
|
let keypair = Random.generate().unwrap();
|
||||||
let tx = Transaction {
|
let tx = TypedTransaction::Legacy(Transaction {
|
||||||
action: transaction::Action::Create,
|
action: transaction::Action::Create,
|
||||||
value: U256::from(100),
|
value: U256::from(100),
|
||||||
data: include_str!("../res/big_transaction.data")
|
data: include_str!("../res/big_transaction.data")
|
||||||
@ -98,7 +100,7 @@ impl Tx {
|
|||||||
gas: self.gas.into(),
|
gas: self.gas.into(),
|
||||||
gas_price: self.gas_price.into(),
|
gas_price: self.gas_price.into(),
|
||||||
nonce: self.nonce.into(),
|
nonce: self.nonce.into(),
|
||||||
};
|
});
|
||||||
tx.sign(keypair.secret(), None)
|
tx.sign(keypair.secret(), None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,6 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use ethereum_types::{H256, U256};
|
use ethereum_types::{H256, U256};
|
||||||
use rlp::Encodable;
|
|
||||||
use txpool;
|
use txpool;
|
||||||
use types::transaction;
|
use types::transaction;
|
||||||
|
|
||||||
@ -97,21 +96,21 @@ impl Transaction {
|
|||||||
/// Return transaction gas price
|
/// Return transaction gas price
|
||||||
pub fn gas_price(&self) -> &U256 {
|
pub fn gas_price(&self) -> &U256 {
|
||||||
match *self {
|
match *self {
|
||||||
Transaction::Unverified(ref tx) => &tx.gas_price,
|
Transaction::Unverified(ref tx) => &tx.tx().gas_price,
|
||||||
Transaction::Retracted(ref tx) => &tx.gas_price,
|
Transaction::Retracted(ref tx) => &tx.tx().gas_price,
|
||||||
Transaction::Local(ref tx) => &tx.gas_price,
|
Transaction::Local(ref tx) => &tx.tx().gas_price,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gas(&self) -> &U256 {
|
fn gas(&self) -> &U256 {
|
||||||
match *self {
|
match *self {
|
||||||
Transaction::Unverified(ref tx) => &tx.gas,
|
Transaction::Unverified(ref tx) => &tx.tx().gas,
|
||||||
Transaction::Retracted(ref tx) => &tx.gas,
|
Transaction::Retracted(ref tx) => &tx.tx().gas,
|
||||||
Transaction::Local(ref tx) => &tx.gas,
|
Transaction::Local(ref tx) => &tx.tx().gas,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transaction(&self) -> &transaction::Transaction {
|
fn transaction(&self) -> &transaction::TypedTransaction {
|
||||||
match *self {
|
match *self {
|
||||||
Transaction::Unverified(ref tx) => &*tx,
|
Transaction::Unverified(ref tx) => &*tx,
|
||||||
Transaction::Retracted(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 {
|
if tx.gas() < &minimal_gas {
|
||||||
trace!(target: "txqueue",
|
trace!(target: "txqueue",
|
||||||
"[{:?}] Rejected transaction with insufficient gas: {} < {}",
|
"[{:?}] 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: {} < {})",
|
"[{:?}] Rejected tx early, cause it doesn't have any chance to get to the pool: (gas price: {} < {})",
|
||||||
hash,
|
hash,
|
||||||
tx.gas_price(),
|
tx.gas_price(),
|
||||||
vtx.transaction.gas_price,
|
vtx.transaction.tx().gas_price,
|
||||||
);
|
);
|
||||||
return Err(transaction::Error::TooCheapToReplace {
|
return Err(transaction::Error::TooCheapToReplace {
|
||||||
prev: Some(vtx.transaction.gas_price),
|
prev: Some(vtx.transaction.tx().gas_price),
|
||||||
new: Some(*tx.gas_price()),
|
new: Some(*tx.gas_price()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -273,7 +272,7 @@ impl<C: Client> txpool::Verifier<Transaction>
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Verify RLP payload
|
// 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);
|
debug!(target: "txqueue", "[{:?}] Rejected transaction's rlp payload", err);
|
||||||
bail!(err)
|
bail!(err)
|
||||||
}
|
}
|
||||||
@ -281,7 +280,7 @@ impl<C: Client> txpool::Verifier<Transaction>
|
|||||||
let sender = transaction.sender();
|
let sender = transaction.sender();
|
||||||
let account_details = self.client.account_details(&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);
|
let transaction_type = self.client.transaction_type(&transaction);
|
||||||
if let TransactionType::Service = transaction_type {
|
if let TransactionType::Service = transaction_type {
|
||||||
debug!(target: "txqueue", "Service tx {:?} below minimal gas price accepted", hash);
|
debug!(target: "txqueue", "Service tx {:?} below minimal gas price accepted", hash);
|
||||||
@ -292,18 +291,21 @@ impl<C: Client> txpool::Verifier<Transaction>
|
|||||||
target: "txqueue",
|
target: "txqueue",
|
||||||
"[{:?}] Rejected tx below minimal gas price threshold: {} < {}",
|
"[{:?}] Rejected tx below minimal gas price threshold: {} < {}",
|
||||||
hash,
|
hash,
|
||||||
transaction.gas_price,
|
transaction.tx().gas_price,
|
||||||
self.options.minimal_gas_price,
|
self.options.minimal_gas_price,
|
||||||
);
|
);
|
||||||
bail!(transaction::Error::InsufficientGasPrice {
|
bail!(transaction::Error::InsufficientGasPrice {
|
||||||
minimal: self.options.minimal_gas_price,
|
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 (full_gas_price, overflow_1) = transaction
|
||||||
let (cost, overflow_2) = transaction.value.overflowing_add(full_gas_price);
|
.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 {
|
if overflow_1 || overflow_2 {
|
||||||
trace!(
|
trace!(
|
||||||
target: "txqueue",
|
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!(
|
debug!(
|
||||||
target: "txqueue",
|
target: "txqueue",
|
||||||
"[{:?}] Rejected tx with old nonce ({} < {})",
|
"[{:?}] Rejected tx with old nonce ({} < {})",
|
||||||
hash,
|
hash,
|
||||||
transaction.nonce,
|
transaction.tx().nonce,
|
||||||
account_details.nonce,
|
account_details.nonce,
|
||||||
);
|
);
|
||||||
bail!(transaction::Error::Old);
|
bail!(transaction::Error::Old);
|
||||||
|
@ -45,7 +45,7 @@ impl ServiceTransactionChecker {
|
|||||||
) -> Result<bool, String> {
|
) -> Result<bool, String> {
|
||||||
let sender = tx.sender();
|
let sender = tx.sender();
|
||||||
// Skip checking the contract if the transaction does not have zero gas price
|
// 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);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,6 +120,7 @@ impl<C: miner::BlockChainClient + BlockChainClient, M: MinerService> Dispatcher
|
|||||||
};
|
};
|
||||||
|
|
||||||
Box::new(future::ok(FilledTransactionRequest {
|
Box::new(future::ok(FilledTransactionRequest {
|
||||||
|
tx_type: request.tx_type,
|
||||||
from,
|
from,
|
||||||
used_default_from: request.from.is_none(),
|
used_default_from: request.from.is_none(),
|
||||||
to: request.to,
|
to: request.to,
|
||||||
@ -133,6 +134,7 @@ impl<C: miner::BlockChainClient + BlockChainClient, M: MinerService> Dispatcher
|
|||||||
value: request.value.unwrap_or_else(|| 0.into()),
|
value: request.value.unwrap_or_else(|| 0.into()),
|
||||||
data: request.data.unwrap_or_else(Vec::new),
|
data: request.data.unwrap_or_else(Vec::new),
|
||||||
condition: request.condition,
|
condition: request.condition,
|
||||||
|
access_list: request.access_list,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,10 @@ use bytes::Bytes;
|
|||||||
use crypto::DEFAULT_MAC;
|
use crypto::DEFAULT_MAC;
|
||||||
use ethereum_types::{Address, H256, U256};
|
use ethereum_types::{Address, H256, U256};
|
||||||
use ethkey::Signature;
|
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 jsonrpc_core::Result;
|
||||||
use v1::helpers::{errors, FilledTransactionRequest};
|
use v1::helpers::{errors, FilledTransactionRequest};
|
||||||
@ -48,16 +51,28 @@ impl super::Accounts for Signer {
|
|||||||
nonce: U256,
|
nonce: U256,
|
||||||
password: SignWith,
|
password: SignWith,
|
||||||
) -> Result<WithToken<SignedTransaction>> {
|
) -> Result<WithToken<SignedTransaction>> {
|
||||||
let t = Transaction {
|
let legacy_tx = Transaction {
|
||||||
nonce: nonce,
|
nonce,
|
||||||
action: filled.to.map_or(Action::Create, Action::Call),
|
action: filled.to.map_or(Action::Create, Action::Call),
|
||||||
gas: filled.gas,
|
gas: filled.gas,
|
||||||
gas_price: filled.gas_price,
|
gas_price: filled.gas_price,
|
||||||
value: filled.value,
|
value: filled.value,
|
||||||
data: filled.data,
|
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)?;
|
let signature = signature(&*self.accounts, filled.from, hash, password)?;
|
||||||
|
|
||||||
Ok(signature.map(|sig| {
|
Ok(signature.map(|sig| {
|
||||||
|
@ -399,7 +399,8 @@ pub fn transaction_message(error: &TransactionError) -> String {
|
|||||||
CodeBanned => "Code is banned in local queue.".into(),
|
CodeBanned => "Code is banned in local queue.".into(),
|
||||||
NotAllowed => "Transaction is not permitted.".into(),
|
NotAllowed => "Transaction is not permitted.".into(),
|
||||||
TooBig => "Transaction is too big, see chain specification for the limit.".into(),
|
TooBig => "Transaction is too big, see chain specification for the limit.".into(),
|
||||||
InvalidRlp(ref descr) => format!("Invalid RLP data: {}", descr),
|
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 {
|
fn request() -> ConfirmationPayload {
|
||||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||||
|
tx_type: Default::default(),
|
||||||
from: Address::from(1),
|
from: Address::from(1),
|
||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: Some(Address::from(2)),
|
to: Some(Address::from(2)),
|
||||||
@ -265,6 +266,7 @@ mod test {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
condition: None,
|
condition: None,
|
||||||
|
access_list: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,9 @@
|
|||||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
use types::transaction::{Action, SignedTransaction, Transaction};
|
use types::transaction::{
|
||||||
|
AccessListTx, Action, SignedTransaction, Transaction, TypedTransaction, TypedTxId,
|
||||||
|
};
|
||||||
|
|
||||||
use ethereum_types::U256;
|
use ethereum_types::U256;
|
||||||
use jsonrpc_core::Error;
|
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 max_gas = U256::from(500_000_000);
|
||||||
let gas = min(request.gas.unwrap_or(max_gas), max_gas);
|
let gas = min(request.gas.unwrap_or(max_gas), max_gas);
|
||||||
let from = request.from.unwrap_or_default();
|
let from = request.from.unwrap_or_default();
|
||||||
|
let tx_legacy = Transaction {
|
||||||
Ok(Transaction {
|
|
||||||
nonce: request.nonce.unwrap_or_default(),
|
nonce: request.nonce.unwrap_or_default(),
|
||||||
action: request.to.map_or(Action::Create, Action::Call),
|
action: request.to.map_or(Action::Create, Action::Call),
|
||||||
gas,
|
gas,
|
||||||
gas_price: request.gas_price.unwrap_or_default(),
|
gas_price: request.gas_price.unwrap_or_default(),
|
||||||
value: request.value.unwrap_or_default(),
|
value: request.value.unwrap_or_default(),
|
||||||
data: request.data.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 bytes::Bytes;
|
||||||
use ethereum_types::{Address, H256, U256};
|
use ethereum_types::{Address, H256, U256};
|
||||||
|
use types::transaction::{AccessList, TypedTxId};
|
||||||
|
|
||||||
use v1::types::{Origin, TransactionCondition};
|
use v1::types::{Origin, TransactionCondition};
|
||||||
|
|
||||||
/// Transaction request coming from RPC
|
/// Transaction request coming from RPC
|
||||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Default, Eq, PartialEq, Hash)]
|
||||||
pub struct TransactionRequest {
|
pub struct TransactionRequest {
|
||||||
|
/// type of transaction.
|
||||||
|
pub tx_type: TypedTxId,
|
||||||
/// Sender
|
/// Sender
|
||||||
pub from: Option<Address>,
|
pub from: Option<Address>,
|
||||||
/// Recipient
|
/// Recipient
|
||||||
@ -38,11 +41,15 @@ pub struct TransactionRequest {
|
|||||||
pub nonce: Option<U256>,
|
pub nonce: Option<U256>,
|
||||||
/// Delay until this condition is met.
|
/// Delay until this condition is met.
|
||||||
pub condition: Option<TransactionCondition>,
|
pub condition: Option<TransactionCondition>,
|
||||||
|
/// Access list
|
||||||
|
pub access_list: Option<AccessList>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transaction request coming from RPC with default values filled in.
|
/// Transaction request coming from RPC with default values filled in.
|
||||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Default, Eq, PartialEq, Hash)]
|
||||||
pub struct FilledTransactionRequest {
|
pub struct FilledTransactionRequest {
|
||||||
|
/// type of transaction.
|
||||||
|
pub tx_type: TypedTxId,
|
||||||
/// Sender
|
/// Sender
|
||||||
pub from: Address,
|
pub from: Address,
|
||||||
/// Indicates if the sender was filled by default value.
|
/// Indicates if the sender was filled by default value.
|
||||||
@ -61,11 +68,14 @@ pub struct FilledTransactionRequest {
|
|||||||
pub nonce: Option<U256>,
|
pub nonce: Option<U256>,
|
||||||
/// Delay until this condition is met.
|
/// Delay until this condition is met.
|
||||||
pub condition: Option<TransactionCondition>,
|
pub condition: Option<TransactionCondition>,
|
||||||
|
/// Access list
|
||||||
|
pub access_list: Option<AccessList>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FilledTransactionRequest> for TransactionRequest {
|
impl From<FilledTransactionRequest> for TransactionRequest {
|
||||||
fn from(r: FilledTransactionRequest) -> Self {
|
fn from(r: FilledTransactionRequest) -> Self {
|
||||||
TransactionRequest {
|
TransactionRequest {
|
||||||
|
tx_type: r.tx_type,
|
||||||
from: Some(r.from),
|
from: Some(r.from),
|
||||||
to: r.to,
|
to: r.to,
|
||||||
gas_price: Some(r.gas_price),
|
gas_price: Some(r.gas_price),
|
||||||
@ -74,6 +84,7 @@ impl From<FilledTransactionRequest> for TransactionRequest {
|
|||||||
data: Some(r.data),
|
data: Some(r.data),
|
||||||
nonce: r.nonce,
|
nonce: r.nonce,
|
||||||
condition: r.condition,
|
condition: r.condition,
|
||||||
|
access_list: r.access_list,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,6 +92,8 @@ impl From<FilledTransactionRequest> for TransactionRequest {
|
|||||||
/// Call request
|
/// Call request
|
||||||
#[derive(Debug, Default, PartialEq)]
|
#[derive(Debug, Default, PartialEq)]
|
||||||
pub struct CallRequest {
|
pub struct CallRequest {
|
||||||
|
/// type of transaction.
|
||||||
|
pub tx_type: TypedTxId,
|
||||||
/// From
|
/// From
|
||||||
pub from: Option<Address>,
|
pub from: Option<Address>,
|
||||||
/// To
|
/// To
|
||||||
@ -95,6 +108,8 @@ pub struct CallRequest {
|
|||||||
pub data: Option<Vec<u8>>,
|
pub data: Option<Vec<u8>>,
|
||||||
/// Nonce
|
/// Nonce
|
||||||
pub nonce: Option<U256>,
|
pub nonce: Option<U256>,
|
||||||
|
/// Access list
|
||||||
|
pub access_list: Option<AccessList>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Confirmation object
|
/// Confirmation object
|
||||||
|
@ -24,7 +24,6 @@ use std::{
|
|||||||
|
|
||||||
use ethereum_types::{Address, H160, H256, H64, U256, U64};
|
use ethereum_types::{Address, H160, H256, H64, U256, U64};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use rlp::Rlp;
|
|
||||||
|
|
||||||
use ethash::{self, SeedHashCompute};
|
use ethash::{self, SeedHashCompute};
|
||||||
use ethcore::{
|
use ethcore::{
|
||||||
@ -42,7 +41,7 @@ use types::{
|
|||||||
encoded,
|
encoded,
|
||||||
filter::Filter as EthcoreFilter,
|
filter::Filter as EthcoreFilter,
|
||||||
header::Header,
|
header::Header,
|
||||||
transaction::{LocalizedTransaction, SignedTransaction},
|
transaction::{LocalizedTransaction, SignedTransaction, TypedTransaction},
|
||||||
BlockNumber as EthBlockNumber,
|
BlockNumber as EthBlockNumber,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1065,8 +1064,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn send_raw_transaction(&self, raw: Bytes) -> Result<H256> {
|
fn send_raw_transaction(&self, raw: Bytes) -> Result<H256> {
|
||||||
Rlp::new(&raw.into_vec())
|
TypedTransaction::decode(&raw.into_vec())
|
||||||
.as_val()
|
|
||||||
.map_err(errors::rlp)
|
.map_err(errors::rlp)
|
||||||
.and_then(|tx| SignedTransaction::new(tx).map_err(errors::transaction))
|
.and_then(|tx| SignedTransaction::new(tx).map_err(errors::transaction))
|
||||||
.and_then(|signed_transaction| {
|
.and_then(|signed_transaction| {
|
||||||
|
@ -22,8 +22,7 @@ use ethereum_types::U256;
|
|||||||
use ethkey;
|
use ethkey;
|
||||||
use parity_runtime::Executor;
|
use parity_runtime::Executor;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use rlp::Rlp;
|
use types::transaction::{PendingTransaction, SignedTransaction, TypedTransaction};
|
||||||
use types::transaction::{PendingTransaction, SignedTransaction};
|
|
||||||
|
|
||||||
use jsonrpc_core::{
|
use jsonrpc_core::{
|
||||||
futures::{future, future::Either, Future, IntoFuture},
|
futures::{future, future::Either, Future, IntoFuture},
|
||||||
@ -161,17 +160,17 @@ impl<D: Dispatcher + 'static> SignerClient<D> {
|
|||||||
where
|
where
|
||||||
F: FnOnce(PendingTransaction) -> Result<ConfirmationResponse>,
|
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)
|
let signed_transaction = SignedTransaction::new(signed_transaction)
|
||||||
.map_err(|e| errors::invalid_params("Invalid signature.", e))?;
|
.map_err(|e| errors::invalid_params("Invalid signature.", e))?;
|
||||||
let sender = signed_transaction.sender();
|
let sender = signed_transaction.sender();
|
||||||
|
|
||||||
// Verification
|
// Verification
|
||||||
let sender_matches = sender == request.from;
|
let sender_matches = sender == request.from;
|
||||||
let data_matches = signed_transaction.data == request.data;
|
let data_matches = signed_transaction.tx().data == request.data;
|
||||||
let value_matches = signed_transaction.value == request.value;
|
let value_matches = signed_transaction.tx().value == request.value;
|
||||||
let nonce_matches = match request.nonce {
|
let nonce_matches = match request.nonce {
|
||||||
Some(nonce) => signed_transaction.nonce == nonce,
|
Some(nonce) => signed_transaction.tx().nonce == nonce,
|
||||||
None => true,
|
None => true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,8 +22,7 @@ use ethcore::client::{
|
|||||||
BlockChainClient, BlockId, Call, CallAnalytics, StateClient, StateInfo, TraceId, TransactionId,
|
BlockChainClient, BlockId, Call, CallAnalytics, StateClient, StateInfo, TraceId, TransactionId,
|
||||||
};
|
};
|
||||||
use ethereum_types::H256;
|
use ethereum_types::H256;
|
||||||
use rlp::Rlp;
|
use types::transaction::{SignedTransaction, TypedTransaction};
|
||||||
use types::transaction::SignedTransaction;
|
|
||||||
|
|
||||||
use jsonrpc_core::Result;
|
use jsonrpc_core::Result;
|
||||||
use v1::{
|
use v1::{
|
||||||
@ -194,9 +193,8 @@ where
|
|||||||
) -> Result<TraceResults> {
|
) -> Result<TraceResults> {
|
||||||
let block = block.unwrap_or_default();
|
let block = block.unwrap_or_default();
|
||||||
|
|
||||||
let tx = Rlp::new(&raw_transaction.into_vec())
|
let tx = TypedTransaction::decode(&raw_transaction.0)
|
||||||
.as_val()
|
.map_err(|e| errors::invalid_params("Transaction is not in valid Format", e))?;
|
||||||
.map_err(|e| errors::invalid_params("Transaction is not valid RLP", e))?;
|
|
||||||
let signed = SignedTransaction::new(tx).map_err(errors::transaction)?;
|
let signed = SignedTransaction::new(tx).map_err(errors::transaction)?;
|
||||||
|
|
||||||
let id = match block {
|
let id = match block {
|
||||||
|
@ -30,14 +30,13 @@ use ethereum_types::{Address, Bloom, H160, H256, U256};
|
|||||||
use miner::external::ExternalMiner;
|
use miner::external::ExternalMiner;
|
||||||
use parity_runtime::Runtime;
|
use parity_runtime::Runtime;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use rlp;
|
|
||||||
use rustc_hex::{FromHex, ToHex};
|
use rustc_hex::{FromHex, ToHex};
|
||||||
use sync::SyncState;
|
use sync::SyncState;
|
||||||
use types::{
|
use types::{
|
||||||
ids::{BlockId, TransactionId},
|
ids::{BlockId, TransactionId},
|
||||||
log_entry::{LocalizedLogEntry, LogEntry},
|
log_entry::{LocalizedLogEntry, LogEntry},
|
||||||
receipt::{LocalizedReceipt, RichReceipt, TransactionOutcome},
|
receipt::{LocalizedReceipt, RichReceipt, TransactionOutcome},
|
||||||
transaction::{Action, Transaction},
|
transaction::{Action, Transaction, TypedTransaction, TypedTxId},
|
||||||
};
|
};
|
||||||
|
|
||||||
use jsonrpc_core::IoHandler;
|
use jsonrpc_core::IoHandler;
|
||||||
@ -694,13 +693,12 @@ fn rpc_eth_transaction_count_by_number_pending() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn rpc_eth_pending_transaction_by_hash() {
|
fn rpc_eth_pending_transaction_by_hash() {
|
||||||
use ethereum_types::H256;
|
use ethereum_types::H256;
|
||||||
use rlp;
|
|
||||||
use types::transaction::SignedTransaction;
|
use types::transaction::SignedTransaction;
|
||||||
|
|
||||||
let tester = EthTester::default();
|
let tester = EthTester::default();
|
||||||
{
|
{
|
||||||
let bytes = FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap();
|
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();
|
let tx = SignedTransaction::new(tx).unwrap();
|
||||||
tester
|
tester
|
||||||
.miner
|
.miner
|
||||||
@ -1050,6 +1048,23 @@ fn rpc_eth_estimate_gas_default_block() {
|
|||||||
fn rpc_eth_send_raw_transaction_error() {
|
fn rpc_eth_send_raw_transaction_error() {
|
||||||
let tester = EthTester::default();
|
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#"{
|
let req = r#"{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"method": "eth_sendRawTransaction",
|
"method": "eth_sendRawTransaction",
|
||||||
@ -1075,7 +1090,7 @@ fn rpc_eth_send_raw_transaction() {
|
|||||||
.unlock_account_permanently(address, "abcd".into())
|
.unlock_account_permanently(address, "abcd".into())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: U256::zero(),
|
nonce: U256::zero(),
|
||||||
gas_price: U256::from(0x9184e72a000u64),
|
gas_price: U256::from(0x9184e72a000u64),
|
||||||
gas: U256::from(0x76c0),
|
gas: U256::from(0x76c0),
|
||||||
@ -1084,14 +1099,14 @@ fn rpc_eth_send_raw_transaction() {
|
|||||||
),
|
),
|
||||||
value: U256::from(0x9184e72au64),
|
value: U256::from(0x9184e72au64),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
};
|
});
|
||||||
let signature = tester
|
let signature = tester
|
||||||
.accounts_provider
|
.accounts_provider
|
||||||
.sign(address, None, t.hash(None))
|
.sign(address, None, t.signature_hash(None))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let t = t.with_signature(signature, None);
|
let t = t.with_signature(signature, None);
|
||||||
|
|
||||||
let rlp = rlp::encode(&t).to_hex();
|
let rlp = t.encode().to_hex();
|
||||||
|
|
||||||
let req = r#"{
|
let req = r#"{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
@ -1118,6 +1133,7 @@ fn rpc_eth_transaction_receipt() {
|
|||||||
to: Some(H160::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
to: Some(H160::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||||
transaction_hash: H256::zero(),
|
transaction_hash: H256::zero(),
|
||||||
transaction_index: 0,
|
transaction_index: 0,
|
||||||
|
transaction_type: TypedTxId::Legacy,
|
||||||
block_hash: H256::from_str(
|
block_hash: H256::from_str(
|
||||||
"ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5",
|
"ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5",
|
||||||
)
|
)
|
||||||
@ -1204,6 +1220,7 @@ fn rpc_eth_pending_receipt() {
|
|||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
transaction_index: 0,
|
transaction_index: 0,
|
||||||
|
transaction_type: TypedTxId::Legacy,
|
||||||
cumulative_gas_used: U256::from(0x20),
|
cumulative_gas_used: U256::from(0x20),
|
||||||
gas_used: U256::from(0x10),
|
gas_used: U256::from(0x10),
|
||||||
contract_address: None,
|
contract_address: None,
|
||||||
|
@ -21,7 +21,10 @@ use ethstore::ethkey::{Generator, Random};
|
|||||||
use miner::pool::local_transactions::Status as LocalTransactionStatus;
|
use miner::pool::local_transactions::Status as LocalTransactionStatus;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use sync::ManageNetwork;
|
use sync::ManageNetwork;
|
||||||
use types::receipt::{LocalizedReceipt, TransactionOutcome};
|
use types::{
|
||||||
|
receipt::{LocalizedReceipt, TransactionOutcome},
|
||||||
|
transaction::TypedTxId,
|
||||||
|
};
|
||||||
|
|
||||||
use super::manage_network::TestManageNetwork;
|
use super::manage_network::TestManageNetwork;
|
||||||
use jsonrpc_core::IoHandler;
|
use jsonrpc_core::IoHandler;
|
||||||
@ -368,16 +371,17 @@ fn rpc_parity_transactions_stats() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rpc_parity_local_transactions() {
|
fn rpc_parity_local_transactions() {
|
||||||
|
use types::transaction::{Transaction, TypedTransaction};
|
||||||
let deps = Dependencies::new();
|
let deps = Dependencies::new();
|
||||||
let io = deps.default_client();
|
let io = deps.default_client();
|
||||||
let tx = ::types::transaction::Transaction {
|
let tx = TypedTransaction::Legacy(Transaction {
|
||||||
value: 5.into(),
|
value: 5.into(),
|
||||||
gas: 3.into(),
|
gas: 3.into(),
|
||||||
gas_price: 2.into(),
|
gas_price: 2.into(),
|
||||||
action: ::types::transaction::Action::Create,
|
action: ::types::transaction::Action::Create,
|
||||||
data: vec![1, 2, 3],
|
data: vec![1, 2, 3],
|
||||||
nonce: 0.into(),
|
nonce: 0.into(),
|
||||||
}
|
})
|
||||||
.fake_sign(3.into());
|
.fake_sign(3.into());
|
||||||
let tx = Arc::new(::miner::pool::VerifiedTransaction::from_pending_block_transaction(tx));
|
let tx = Arc::new(::miner::pool::VerifiedTransaction::from_pending_block_transaction(tx));
|
||||||
deps.miner
|
deps.miner
|
||||||
@ -466,6 +470,7 @@ fn rpc_parity_block_receipts() {
|
|||||||
TransactionId::Hash(1.into()),
|
TransactionId::Hash(1.into()),
|
||||||
LocalizedReceipt {
|
LocalizedReceipt {
|
||||||
transaction_hash: 1.into(),
|
transaction_hash: 1.into(),
|
||||||
|
transaction_type: TypedTxId::Legacy,
|
||||||
transaction_index: 0,
|
transaction_index: 0,
|
||||||
block_hash: 3.into(),
|
block_hash: 3.into(),
|
||||||
block_number: 0,
|
block_number: 0,
|
||||||
|
@ -178,7 +178,7 @@ fn rpc_parity_set_hash_content() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rpc_parity_remove_transaction() {
|
fn rpc_parity_remove_transaction() {
|
||||||
use types::transaction::{Action, Transaction};
|
use types::transaction::{Action, Transaction, TypedTransaction};
|
||||||
|
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
let client = client_service();
|
let client = client_service();
|
||||||
@ -187,14 +187,14 @@ fn rpc_parity_remove_transaction() {
|
|||||||
let mut io = IoHandler::new();
|
let mut io = IoHandler::new();
|
||||||
io.extend_with(parity_set_client(&client, &miner, &network).to_delegate());
|
io.extend_with(parity_set_client(&client, &miner, &network).to_delegate());
|
||||||
|
|
||||||
let tx = Transaction {
|
let tx = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: 1.into(),
|
nonce: 1.into(),
|
||||||
gas_price: 0x9184e72a000u64.into(),
|
gas_price: 0x9184e72a000u64.into(),
|
||||||
gas: 0x76c0.into(),
|
gas: 0x76c0.into(),
|
||||||
action: Action::Call(5.into()),
|
action: Action::Call(5.into()),
|
||||||
value: 0x9184e72au64.into(),
|
value: 0x9184e72au64.into(),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
};
|
});
|
||||||
let signed = tx.fake_sign(2.into());
|
let signed = tx.fake_sign(2.into());
|
||||||
let hash = signed.hash();
|
let hash = signed.hash();
|
||||||
|
|
||||||
@ -202,7 +202,7 @@ fn rpc_parity_remove_transaction() {
|
|||||||
.to_owned()
|
.to_owned()
|
||||||
+ &format!("0x{:x}", hash)
|
+ &format!("0x{:x}", hash)
|
||||||
+ r#""], "id": 1}"#;
|
+ 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);
|
miner.pending_transactions.lock().insert(hash, signed);
|
||||||
assert_eq!(io.handle_request_sync(&request), Some(response.to_owned()));
|
assert_eq!(io.handle_request_sync(&request), Some(response.to_owned()));
|
||||||
|
@ -24,7 +24,7 @@ use hash::keccak;
|
|||||||
use jsonrpc_core::IoHandler;
|
use jsonrpc_core::IoHandler;
|
||||||
use parity_runtime::Runtime;
|
use parity_runtime::Runtime;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use types::transaction::{Action, Transaction};
|
use types::transaction::{Action, Transaction, TypedTransaction};
|
||||||
|
|
||||||
use ethkey::Secret;
|
use ethkey::Secret;
|
||||||
use serde_json::to_value;
|
use serde_json::to_value;
|
||||||
@ -91,9 +91,6 @@ fn setup_with(c: Config) -> PersonalTester {
|
|||||||
tester
|
tester
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
use rustc_hex::ToHex;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn accounts() {
|
fn accounts() {
|
||||||
let tester = setup();
|
let tester = setup();
|
||||||
@ -265,7 +262,7 @@ fn sign_and_send_test(method: &str) {
|
|||||||
"id": 1
|
"id": 1
|
||||||
}"#;
|
}"#;
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: U256::zero(),
|
nonce: U256::zero(),
|
||||||
gas_price: U256::from(0x9184e72a000u64),
|
gas_price: U256::from(0x9184e72a000u64),
|
||||||
gas: U256::from(0x76c0),
|
gas: U256::from(0x76c0),
|
||||||
@ -274,12 +271,15 @@ fn sign_and_send_test(method: &str) {
|
|||||||
),
|
),
|
||||||
value: U256::from(0x9184e72au64),
|
value: U256::from(0x9184e72au64),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
};
|
});
|
||||||
tester
|
tester
|
||||||
.accounts
|
.accounts
|
||||||
.unlock_account_temporarily(address, "password123".into())
|
.unlock_account_temporarily(address, "password123".into())
|
||||||
.unwrap();
|
.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 t = t.with_signature(signature, None);
|
||||||
|
|
||||||
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned()
|
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);
|
tester.miner.increment_nonce(&address);
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: U256::one(),
|
nonce: U256::one(),
|
||||||
gas_price: U256::from(0x9184e72a000u64),
|
gas_price: U256::from(0x9184e72a000u64),
|
||||||
gas: U256::from(0x76c0),
|
gas: U256::from(0x76c0),
|
||||||
@ -302,12 +302,15 @@ fn sign_and_send_test(method: &str) {
|
|||||||
),
|
),
|
||||||
value: U256::from(0x9184e72au64),
|
value: U256::from(0x9184e72au64),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
};
|
});
|
||||||
tester
|
tester
|
||||||
.accounts
|
.accounts
|
||||||
.unlock_account_temporarily(address, "password123".into())
|
.unlock_account_temporarily(address, "password123".into())
|
||||||
.unwrap();
|
.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 t = t.with_signature(signature, None);
|
||||||
|
|
||||||
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned()
|
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned()
|
||||||
|
@ -22,8 +22,7 @@ use accounts::AccountProvider;
|
|||||||
use ethcore::client::TestBlockChainClient;
|
use ethcore::client::TestBlockChainClient;
|
||||||
use parity_runtime::Runtime;
|
use parity_runtime::Runtime;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use rlp::encode;
|
use types::transaction::{Action, SignedTransaction, Transaction, TypedTransaction};
|
||||||
use types::transaction::{Action, SignedTransaction, Transaction};
|
|
||||||
|
|
||||||
use jsonrpc_core::IoHandler;
|
use jsonrpc_core::IoHandler;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
@ -92,6 +91,7 @@ fn should_return_list_of_items_to_confirm() {
|
|||||||
.signer
|
.signer
|
||||||
.add_request(
|
.add_request(
|
||||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||||
|
tx_type: Default::default(),
|
||||||
from: Address::from(1),
|
from: Address::from(1),
|
||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||||
@ -101,6 +101,7 @@ fn should_return_list_of_items_to_confirm() {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
condition: None,
|
condition: None,
|
||||||
|
access_list: None,
|
||||||
}),
|
}),
|
||||||
Origin::Unknown,
|
Origin::Unknown,
|
||||||
)
|
)
|
||||||
@ -137,6 +138,7 @@ fn should_reject_transaction_from_queue_without_dispatching() {
|
|||||||
.signer
|
.signer
|
||||||
.add_request(
|
.add_request(
|
||||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||||
|
tx_type: Default::default(),
|
||||||
from: Address::from(1),
|
from: Address::from(1),
|
||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||||
@ -146,6 +148,7 @@ fn should_reject_transaction_from_queue_without_dispatching() {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
condition: None,
|
condition: None,
|
||||||
|
access_list: None,
|
||||||
}),
|
}),
|
||||||
Origin::Unknown,
|
Origin::Unknown,
|
||||||
)
|
)
|
||||||
@ -173,6 +176,7 @@ fn should_not_remove_transaction_if_password_is_invalid() {
|
|||||||
.signer
|
.signer
|
||||||
.add_request(
|
.add_request(
|
||||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||||
|
tx_type: Default::default(),
|
||||||
from: Address::from(1),
|
from: Address::from(1),
|
||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||||
@ -182,6 +186,7 @@ fn should_not_remove_transaction_if_password_is_invalid() {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
condition: None,
|
condition: None,
|
||||||
|
access_list: None,
|
||||||
}),
|
}),
|
||||||
Origin::Unknown,
|
Origin::Unknown,
|
||||||
)
|
)
|
||||||
@ -237,6 +242,7 @@ fn should_confirm_transaction_and_dispatch() {
|
|||||||
.signer
|
.signer
|
||||||
.add_request(
|
.add_request(
|
||||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||||
|
tx_type: Default::default(),
|
||||||
from: address,
|
from: address,
|
||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: Some(recipient),
|
to: Some(recipient),
|
||||||
@ -246,24 +252,28 @@ fn should_confirm_transaction_and_dispatch() {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
condition: None,
|
condition: None,
|
||||||
|
access_list: None,
|
||||||
}),
|
}),
|
||||||
Origin::Unknown,
|
Origin::Unknown,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: U256::zero(),
|
nonce: U256::zero(),
|
||||||
gas_price: U256::from(0x1000),
|
gas_price: U256::from(0x1000),
|
||||||
gas: U256::from(0x50505),
|
gas: U256::from(0x50505),
|
||||||
action: Action::Call(recipient),
|
action: Action::Call(recipient),
|
||||||
value: U256::from(0x1),
|
value: U256::from(0x1),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
};
|
});
|
||||||
tester
|
tester
|
||||||
.accounts
|
.accounts
|
||||||
.unlock_account_temporarily(address, "test".into())
|
.unlock_account_temporarily(address, "test".into())
|
||||||
.unwrap();
|
.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 t = t.with_signature(signature, None);
|
||||||
|
|
||||||
assert_eq!(tester.signer.requests().len(), 1);
|
assert_eq!(tester.signer.requests().len(), 1);
|
||||||
@ -297,6 +307,7 @@ fn should_alter_the_sender_and_nonce() {
|
|||||||
.signer
|
.signer
|
||||||
.add_request(
|
.add_request(
|
||||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||||
|
tx_type: Default::default(),
|
||||||
from: 0.into(),
|
from: 0.into(),
|
||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: Some(recipient),
|
to: Some(recipient),
|
||||||
@ -306,24 +317,25 @@ fn should_alter_the_sender_and_nonce() {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: Some(10.into()),
|
nonce: Some(10.into()),
|
||||||
condition: None,
|
condition: None,
|
||||||
|
access_list: None,
|
||||||
}),
|
}),
|
||||||
Origin::Unknown,
|
Origin::Unknown,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: U256::zero(),
|
nonce: U256::zero(),
|
||||||
gas_price: U256::from(0x1000),
|
gas_price: U256::from(0x1000),
|
||||||
gas: U256::from(0x50505),
|
gas: U256::from(0x50505),
|
||||||
action: Action::Call(recipient),
|
action: Action::Call(recipient),
|
||||||
value: U256::from(0x1),
|
value: U256::from(0x1),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
};
|
});
|
||||||
|
|
||||||
let address = tester.accounts.new_account(&"test".into()).unwrap();
|
let address = tester.accounts.new_account(&"test".into()).unwrap();
|
||||||
let signature = tester
|
let signature = tester
|
||||||
.accounts
|
.accounts
|
||||||
.sign(address, Some("test".into()), t.hash(None))
|
.sign(address, Some("test".into()), t.signature_hash(None))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let t = t.with_signature(signature, None);
|
let t = t.with_signature(signature, None);
|
||||||
|
|
||||||
@ -361,6 +373,7 @@ fn should_confirm_transaction_with_token() {
|
|||||||
.signer
|
.signer
|
||||||
.add_request(
|
.add_request(
|
||||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||||
|
tx_type: Default::default(),
|
||||||
from: address,
|
from: address,
|
||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: Some(recipient),
|
to: Some(recipient),
|
||||||
@ -370,22 +383,23 @@ fn should_confirm_transaction_with_token() {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
condition: None,
|
condition: None,
|
||||||
|
access_list: None,
|
||||||
}),
|
}),
|
||||||
Origin::Unknown,
|
Origin::Unknown,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: U256::zero(),
|
nonce: U256::zero(),
|
||||||
gas_price: U256::from(0x1000),
|
gas_price: U256::from(0x1000),
|
||||||
gas: U256::from(10_000_000),
|
gas: U256::from(10_000_000),
|
||||||
action: Action::Call(recipient),
|
action: Action::Call(recipient),
|
||||||
value: U256::from(0x1),
|
value: U256::from(0x1),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
};
|
});
|
||||||
let (signature, token) = tester
|
let (signature, token) = tester
|
||||||
.accounts
|
.accounts
|
||||||
.sign_with_token(address, "test".into(), t.hash(None))
|
.sign_with_token(address, "test".into(), t.signature_hash(None))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let t = t.with_signature(signature, None);
|
let t = t.with_signature(signature, None);
|
||||||
|
|
||||||
@ -427,6 +441,7 @@ fn should_confirm_transaction_with_rlp() {
|
|||||||
.signer
|
.signer
|
||||||
.add_request(
|
.add_request(
|
||||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||||
|
tx_type: Default::default(),
|
||||||
from: address,
|
from: address,
|
||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: Some(recipient),
|
to: Some(recipient),
|
||||||
@ -436,25 +451,26 @@ fn should_confirm_transaction_with_rlp() {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
condition: None,
|
condition: None,
|
||||||
|
access_list: None,
|
||||||
}),
|
}),
|
||||||
Origin::Unknown,
|
Origin::Unknown,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: U256::zero(),
|
nonce: U256::zero(),
|
||||||
gas_price: U256::from(0x1000),
|
gas_price: U256::from(0x1000),
|
||||||
gas: U256::from(10_000_000),
|
gas: U256::from(10_000_000),
|
||||||
action: Action::Call(recipient),
|
action: Action::Call(recipient),
|
||||||
value: U256::from(0x1),
|
value: U256::from(0x1),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
};
|
});
|
||||||
let signature = tester
|
let signature = tester
|
||||||
.accounts
|
.accounts
|
||||||
.sign(address, Some("test".into()), t.hash(None))
|
.sign(address, Some("test".into()), t.signature_hash(None))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let t = t.with_signature(signature, None);
|
let t = t.with_signature(signature, None);
|
||||||
let rlp = encode(&t);
|
let rlp = t.encode();
|
||||||
|
|
||||||
assert_eq!(tester.signer.requests().len(), 1);
|
assert_eq!(tester.signer.requests().len(), 1);
|
||||||
|
|
||||||
@ -491,6 +507,7 @@ fn should_return_error_when_sender_does_not_match() {
|
|||||||
.signer
|
.signer
|
||||||
.add_request(
|
.add_request(
|
||||||
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
ConfirmationPayload::SendTransaction(FilledTransactionRequest {
|
||||||
|
tx_type: Default::default(),
|
||||||
from: Address::default(),
|
from: Address::default(),
|
||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: Some(recipient),
|
to: Some(recipient),
|
||||||
@ -500,26 +517,30 @@ fn should_return_error_when_sender_does_not_match() {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
condition: None,
|
condition: None,
|
||||||
|
access_list: None,
|
||||||
}),
|
}),
|
||||||
Origin::Unknown,
|
Origin::Unknown,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: U256::zero(),
|
nonce: U256::zero(),
|
||||||
gas_price: U256::from(0x1000),
|
gas_price: U256::from(0x1000),
|
||||||
gas: U256::from(10_000_000),
|
gas: U256::from(10_000_000),
|
||||||
action: Action::Call(recipient),
|
action: Action::Call(recipient),
|
||||||
value: U256::from(0x1),
|
value: U256::from(0x1),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
};
|
});
|
||||||
tester
|
tester
|
||||||
.accounts
|
.accounts
|
||||||
.unlock_account_temporarily(address, "test".into())
|
.unlock_account_temporarily(address, "test".into())
|
||||||
.unwrap();
|
.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 t = t.with_signature(signature, None);
|
||||||
let rlp = encode(&t);
|
let rlp = t.encode();
|
||||||
|
|
||||||
assert_eq!(tester.signer.requests().len(), 1);
|
assert_eq!(tester.signer.requests().len(), 1);
|
||||||
|
|
||||||
@ -553,6 +574,7 @@ fn should_confirm_sign_transaction_with_rlp() {
|
|||||||
.signer
|
.signer
|
||||||
.add_request(
|
.add_request(
|
||||||
ConfirmationPayload::SignTransaction(FilledTransactionRequest {
|
ConfirmationPayload::SignTransaction(FilledTransactionRequest {
|
||||||
|
tx_type: Default::default(),
|
||||||
from: address,
|
from: address,
|
||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: Some(recipient),
|
to: Some(recipient),
|
||||||
@ -562,26 +584,27 @@ fn should_confirm_sign_transaction_with_rlp() {
|
|||||||
data: vec![],
|
data: vec![],
|
||||||
nonce: None,
|
nonce: None,
|
||||||
condition: None,
|
condition: None,
|
||||||
|
access_list: None,
|
||||||
}),
|
}),
|
||||||
Origin::Unknown,
|
Origin::Unknown,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(tester.signer.requests().len(), 1);
|
assert_eq!(tester.signer.requests().len(), 1);
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: U256::zero(),
|
nonce: U256::zero(),
|
||||||
gas_price: U256::from(0x1000),
|
gas_price: U256::from(0x1000),
|
||||||
gas: U256::from(10_000_000),
|
gas: U256::from(10_000_000),
|
||||||
action: Action::Call(recipient),
|
action: Action::Call(recipient),
|
||||||
value: U256::from(0x1),
|
value: U256::from(0x1),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
};
|
});
|
||||||
let signature = tester
|
let signature = tester
|
||||||
.accounts
|
.accounts
|
||||||
.sign(address, Some("test".into()), t.hash(None))
|
.sign(address, Some("test".into()), t.signature_hash(None))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let t = SignedTransaction::new(t.with_signature(signature.clone(), None)).unwrap();
|
let t = SignedTransaction::new(t.with_signature(signature.clone(), None)).unwrap();
|
||||||
let rlp = encode(&t);
|
let rlp = t.encode();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let request = r#"{
|
let request = r#"{
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use rlp;
|
|
||||||
use std::{str::FromStr, sync::Arc, thread, time::Duration};
|
use std::{str::FromStr, sync::Arc, thread, time::Duration};
|
||||||
|
|
||||||
use jsonrpc_core::{futures::Future, IoHandler, Success};
|
use jsonrpc_core::{futures::Future, IoHandler, Success};
|
||||||
@ -40,7 +39,7 @@ use ethstore::ethkey::{Generator, Random};
|
|||||||
use parity_runtime::{Executor, Runtime};
|
use parity_runtime::{Executor, Runtime};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use types::transaction::{Action, SignedTransaction, Transaction};
|
use types::transaction::{Action, SignedTransaction, Transaction, TypedTransaction};
|
||||||
|
|
||||||
struct SigningTester {
|
struct SigningTester {
|
||||||
pub runtime: Runtime,
|
pub runtime: Runtime,
|
||||||
@ -379,7 +378,7 @@ fn should_add_sign_transaction_to_the_queue() {
|
|||||||
"id": 1
|
"id": 1
|
||||||
}"#;
|
}"#;
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: U256::one(),
|
nonce: U256::one(),
|
||||||
gas_price: U256::from(0x9184e72a000u64),
|
gas_price: U256::from(0x9184e72a000u64),
|
||||||
gas: U256::from(0x76c0),
|
gas: U256::from(0x76c0),
|
||||||
@ -388,15 +387,15 @@ fn should_add_sign_transaction_to_the_queue() {
|
|||||||
),
|
),
|
||||||
value: U256::from(0x9184e72au64),
|
value: U256::from(0x9184e72au64),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
};
|
});
|
||||||
let signature = tester
|
let signature = tester
|
||||||
.accounts
|
.accounts
|
||||||
.sign(address, Some("test".into()), t.hash(None))
|
.sign(address, Some("test".into()), t.signature_hash(None))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let t = t.with_signature(signature, None);
|
let t = t.with_signature(signature, None);
|
||||||
let t = SignedTransaction::new(t).unwrap();
|
let t = SignedTransaction::new(t).unwrap();
|
||||||
let signature = t.signature();
|
let signature = t.signature();
|
||||||
let rlp = rlp::encode(&t);
|
let rlp = t.encode();
|
||||||
|
|
||||||
let response = r#"{"jsonrpc":"2.0","result":{"#.to_owned()
|
let response = r#"{"jsonrpc":"2.0","result":{"#.to_owned()
|
||||||
+ r#""raw":"0x"#
|
+ r#""raw":"0x"#
|
||||||
@ -459,7 +458,7 @@ fn should_dispatch_transaction_if_account_is_unlock() {
|
|||||||
.unlock_account_permanently(acc, "test".into())
|
.unlock_account_permanently(acc, "test".into())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: U256::zero(),
|
nonce: U256::zero(),
|
||||||
gas_price: U256::from(0x9184e72a000u64),
|
gas_price: U256::from(0x9184e72a000u64),
|
||||||
gas: U256::from(0x76c0),
|
gas: U256::from(0x76c0),
|
||||||
@ -468,8 +467,11 @@ fn should_dispatch_transaction_if_account_is_unlock() {
|
|||||||
),
|
),
|
||||||
value: U256::from(0x9184e72au64),
|
value: U256::from(0x9184e72au64),
|
||||||
data: vec![],
|
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);
|
let t = t.with_signature(signature, None);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
|
@ -21,9 +21,7 @@ use ethcore::client::TestBlockChainClient;
|
|||||||
use ethereum_types::{Address, U256};
|
use ethereum_types::{Address, U256};
|
||||||
use parity_runtime::Runtime;
|
use parity_runtime::Runtime;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use rlp;
|
use types::transaction::{Action, Transaction, TypedTransaction};
|
||||||
use rustc_hex::ToHex;
|
|
||||||
use types::transaction::{Action, Transaction};
|
|
||||||
|
|
||||||
use jsonrpc_core::IoHandler;
|
use jsonrpc_core::IoHandler;
|
||||||
use v1::{
|
use v1::{
|
||||||
@ -117,7 +115,7 @@ fn rpc_eth_send_transaction() {
|
|||||||
"id": 1
|
"id": 1
|
||||||
}"#;
|
}"#;
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: U256::zero(),
|
nonce: U256::zero(),
|
||||||
gas_price: U256::from(0x9184e72a000u64),
|
gas_price: U256::from(0x9184e72a000u64),
|
||||||
gas: U256::from(0x76c0),
|
gas: U256::from(0x76c0),
|
||||||
@ -126,10 +124,10 @@ fn rpc_eth_send_transaction() {
|
|||||||
),
|
),
|
||||||
value: U256::from(0x9184e72au64),
|
value: U256::from(0x9184e72au64),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
};
|
});
|
||||||
let signature = tester
|
let signature = tester
|
||||||
.accounts_provider
|
.accounts_provider
|
||||||
.sign(address, None, t.hash(None))
|
.sign(address, None, t.signature_hash(None))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let t = t.with_signature(signature, None);
|
let t = t.with_signature(signature, None);
|
||||||
|
|
||||||
@ -141,7 +139,7 @@ fn rpc_eth_send_transaction() {
|
|||||||
|
|
||||||
tester.miner.increment_nonce(&address);
|
tester.miner.increment_nonce(&address);
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: U256::one(),
|
nonce: U256::one(),
|
||||||
gas_price: U256::from(0x9184e72a000u64),
|
gas_price: U256::from(0x9184e72a000u64),
|
||||||
gas: U256::from(0x76c0),
|
gas: U256::from(0x76c0),
|
||||||
@ -150,10 +148,10 @@ fn rpc_eth_send_transaction() {
|
|||||||
),
|
),
|
||||||
value: U256::from(0x9184e72au64),
|
value: U256::from(0x9184e72au64),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
};
|
});
|
||||||
let signature = tester
|
let signature = tester
|
||||||
.accounts_provider
|
.accounts_provider
|
||||||
.sign(address, None, t.hash(None))
|
.sign(address, None, t.signature_hash(None))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let t = t.with_signature(signature, None);
|
let t = t.with_signature(signature, None);
|
||||||
|
|
||||||
@ -166,6 +164,7 @@ fn rpc_eth_send_transaction() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rpc_eth_sign_transaction() {
|
fn rpc_eth_sign_transaction() {
|
||||||
|
use rustc_hex::ToHex;
|
||||||
let tester = EthTester::default();
|
let tester = EthTester::default();
|
||||||
let address = tester.accounts_provider.new_account(&"".into()).unwrap();
|
let address = tester.accounts_provider.new_account(&"".into()).unwrap();
|
||||||
tester
|
tester
|
||||||
@ -188,7 +187,7 @@ fn rpc_eth_sign_transaction() {
|
|||||||
"id": 1
|
"id": 1
|
||||||
}"#;
|
}"#;
|
||||||
|
|
||||||
let t = Transaction {
|
let t = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: U256::one(),
|
nonce: U256::one(),
|
||||||
gas_price: U256::from(0x9184e72a000u64),
|
gas_price: U256::from(0x9184e72a000u64),
|
||||||
gas: U256::from(0x76c0),
|
gas: U256::from(0x76c0),
|
||||||
@ -197,14 +196,14 @@ fn rpc_eth_sign_transaction() {
|
|||||||
),
|
),
|
||||||
value: U256::from(0x9184e72au64),
|
value: U256::from(0x9184e72au64),
|
||||||
data: vec![],
|
data: vec![],
|
||||||
};
|
});
|
||||||
let signature = tester
|
let signature = tester
|
||||||
.accounts_provider
|
.accounts_provider
|
||||||
.sign(address, None, t.hash(None))
|
.sign(address, None, t.signature_hash(None))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let t = t.with_signature(signature, None);
|
let t = t.with_signature(signature, None);
|
||||||
let signature = t.signature();
|
let signature = t.signature();
|
||||||
let rlp = rlp::encode(&t);
|
let rlp = t.encode();
|
||||||
|
|
||||||
let response = r#"{"jsonrpc":"2.0","result":{"#.to_owned()
|
let response = r#"{"jsonrpc":"2.0","result":{"#.to_owned()
|
||||||
+ r#""raw":"0x"#
|
+ r#""raw":"0x"#
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use ethereum_types::{H160, U256};
|
use ethereum_types::{H160, U256};
|
||||||
|
use types::transaction::{AccessList, TypedTxId};
|
||||||
use v1::{helpers::CallRequest as Request, types::Bytes};
|
use v1::{helpers::CallRequest as Request, types::Bytes};
|
||||||
|
|
||||||
/// Call request
|
/// Call request
|
||||||
@ -22,6 +23,9 @@ use v1::{helpers::CallRequest as Request, types::Bytes};
|
|||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct CallRequest {
|
pub struct CallRequest {
|
||||||
|
/// transaction type
|
||||||
|
#[serde(default)]
|
||||||
|
pub tx_type: TypedTxId,
|
||||||
/// From
|
/// From
|
||||||
pub from: Option<H160>,
|
pub from: Option<H160>,
|
||||||
/// To
|
/// To
|
||||||
@ -36,11 +40,14 @@ pub struct CallRequest {
|
|||||||
pub data: Option<Bytes>,
|
pub data: Option<Bytes>,
|
||||||
/// Nonce
|
/// Nonce
|
||||||
pub nonce: Option<U256>,
|
pub nonce: Option<U256>,
|
||||||
|
/// Access list
|
||||||
|
pub access_list: Option<AccessList>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<Request> for CallRequest {
|
impl Into<Request> for CallRequest {
|
||||||
fn into(self) -> Request {
|
fn into(self) -> Request {
|
||||||
Request {
|
Request {
|
||||||
|
tx_type: self.tx_type,
|
||||||
from: self.from.map(Into::into),
|
from: self.from.map(Into::into),
|
||||||
to: self.to.map(Into::into),
|
to: self.to.map(Into::into),
|
||||||
gas_price: self.gas_price.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),
|
value: self.value.map(Into::into),
|
||||||
data: self.data.map(Into::into),
|
data: self.data.map(Into::into),
|
||||||
nonce: self.nonce.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!(
|
assert_eq!(
|
||||||
deserialized,
|
deserialized,
|
||||||
CallRequest {
|
CallRequest {
|
||||||
|
tx_type: Default::default(),
|
||||||
from: Some(H160::from(1)),
|
from: Some(H160::from(1)),
|
||||||
to: Some(H160::from(2)),
|
to: Some(H160::from(2)),
|
||||||
gas_price: Some(U256::from(1)),
|
gas_price: Some(U256::from(1)),
|
||||||
@ -83,6 +92,7 @@ mod tests {
|
|||||||
value: Some(U256::from(3)),
|
value: Some(U256::from(3)),
|
||||||
data: Some(vec![0x12, 0x34, 0x56].into()),
|
data: Some(vec![0x12, 0x34, 0x56].into()),
|
||||||
nonce: Some(U256::from(4)),
|
nonce: Some(U256::from(4)),
|
||||||
|
access_list: None,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -100,13 +110,15 @@ mod tests {
|
|||||||
let deserialized: CallRequest = serde_json::from_str(s).unwrap();
|
let deserialized: CallRequest = serde_json::from_str(s).unwrap();
|
||||||
|
|
||||||
assert_eq!(deserialized, CallRequest {
|
assert_eq!(deserialized, CallRequest {
|
||||||
|
tx_type: Default::default(),
|
||||||
from: Some(H160::from_str("b60e8dd61c5d32be8058bb8eb970870f07233155").unwrap()),
|
from: Some(H160::from_str("b60e8dd61c5d32be8058bb8eb970870f07233155").unwrap()),
|
||||||
to: Some(H160::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
to: Some(H160::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||||
gas_price: Some(U256::from_str("9184e72a000").unwrap()),
|
gas_price: Some(U256::from_str("9184e72a000").unwrap()),
|
||||||
gas: Some(U256::from_str("76c0").unwrap()),
|
gas: Some(U256::from_str("76c0").unwrap()),
|
||||||
value: Some(U256::from_str("9184e72a").unwrap()),
|
value: Some(U256::from_str("9184e72a").unwrap()),
|
||||||
data: Some("d46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675".from_hex().unwrap().into()),
|
data: Some("d46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675".from_hex().unwrap().into()),
|
||||||
nonce: None
|
nonce: None,
|
||||||
|
access_list: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,6 +130,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
deserialized,
|
deserialized,
|
||||||
CallRequest {
|
CallRequest {
|
||||||
|
tx_type: Default::default(),
|
||||||
from: Some(H160::from(1)),
|
from: Some(H160::from(1)),
|
||||||
to: None,
|
to: None,
|
||||||
gas_price: None,
|
gas_price: None,
|
||||||
@ -125,6 +138,7 @@ mod tests {
|
|||||||
value: None,
|
value: None,
|
||||||
data: None,
|
data: None,
|
||||||
nonce: None,
|
nonce: None,
|
||||||
|
access_list: None,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -331,6 +331,7 @@ mod tests {
|
|||||||
id: 15.into(),
|
id: 15.into(),
|
||||||
payload: helpers::ConfirmationPayload::SendTransaction(
|
payload: helpers::ConfirmationPayload::SendTransaction(
|
||||||
helpers::FilledTransactionRequest {
|
helpers::FilledTransactionRequest {
|
||||||
|
tx_type: Default::default(),
|
||||||
from: 0.into(),
|
from: 0.into(),
|
||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: None,
|
to: None,
|
||||||
@ -340,6 +341,7 @@ mod tests {
|
|||||||
data: vec![1, 2, 3],
|
data: vec![1, 2, 3],
|
||||||
nonce: Some(1.into()),
|
nonce: Some(1.into()),
|
||||||
condition: None,
|
condition: None,
|
||||||
|
access_list: None,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
origin: Origin::Signer { session: 5.into() },
|
origin: Origin::Signer { session: 5.into() },
|
||||||
@ -360,6 +362,7 @@ mod tests {
|
|||||||
id: 15.into(),
|
id: 15.into(),
|
||||||
payload: helpers::ConfirmationPayload::SignTransaction(
|
payload: helpers::ConfirmationPayload::SignTransaction(
|
||||||
helpers::FilledTransactionRequest {
|
helpers::FilledTransactionRequest {
|
||||||
|
tx_type: Default::default(),
|
||||||
from: 0.into(),
|
from: 0.into(),
|
||||||
used_default_from: false,
|
used_default_from: false,
|
||||||
to: None,
|
to: None,
|
||||||
@ -369,6 +372,7 @@ mod tests {
|
|||||||
data: vec![1, 2, 3],
|
data: vec![1, 2, 3],
|
||||||
nonce: Some(1.into()),
|
nonce: Some(1.into()),
|
||||||
condition: None,
|
condition: None,
|
||||||
|
access_list: None,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
origin: Origin::Unknown,
|
origin: Origin::Unknown,
|
||||||
|
@ -15,13 +15,19 @@
|
|||||||
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use ethereum_types::{Bloom as H2048, H160, H256, U256, U64};
|
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;
|
use v1::types::Log;
|
||||||
|
|
||||||
/// Receipt
|
/// Receipt
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Receipt {
|
pub struct Receipt {
|
||||||
|
/// Transaction Type
|
||||||
|
#[serde(skip_serializing)]
|
||||||
|
pub transaction_type: TypedTxId,
|
||||||
/// Transaction Hash
|
/// Transaction Hash
|
||||||
pub transaction_hash: Option<H256>,
|
pub transaction_hash: Option<H256>,
|
||||||
/// Transaction index
|
/// Transaction index
|
||||||
@ -75,6 +81,7 @@ impl From<LocalizedReceipt> for Receipt {
|
|||||||
Receipt {
|
Receipt {
|
||||||
to: r.to.map(Into::into),
|
to: r.to.map(Into::into),
|
||||||
from: Some(r.from),
|
from: Some(r.from),
|
||||||
|
transaction_type: r.transaction_type,
|
||||||
transaction_hash: Some(r.transaction_hash),
|
transaction_hash: Some(r.transaction_hash),
|
||||||
transaction_index: Some(r.transaction_index.into()),
|
transaction_index: Some(r.transaction_index.into()),
|
||||||
block_hash: Some(r.block_hash),
|
block_hash: Some(r.block_hash),
|
||||||
@ -95,6 +102,7 @@ impl From<RichReceipt> for Receipt {
|
|||||||
Receipt {
|
Receipt {
|
||||||
from: Some(r.from),
|
from: Some(r.from),
|
||||||
to: r.to.map(Into::into),
|
to: r.to.map(Into::into),
|
||||||
|
transaction_type: r.transaction_type,
|
||||||
transaction_hash: Some(r.transaction_hash),
|
transaction_hash: Some(r.transaction_hash),
|
||||||
transaction_index: Some(r.transaction_index.into()),
|
transaction_index: Some(r.transaction_index.into()),
|
||||||
block_hash: None,
|
block_hash: None,
|
||||||
@ -110,11 +118,14 @@ impl From<RichReceipt> for Receipt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<EthReceipt> for Receipt {
|
impl From<TypedReceipt> for Receipt {
|
||||||
fn from(r: EthReceipt) -> Self {
|
fn from(r: TypedReceipt) -> Self {
|
||||||
|
let transaction_type = r.tx_type();
|
||||||
|
let r = r.receipt().clone();
|
||||||
Receipt {
|
Receipt {
|
||||||
from: None,
|
from: None,
|
||||||
to: None,
|
to: None,
|
||||||
|
transaction_type,
|
||||||
transaction_hash: None,
|
transaction_hash: None,
|
||||||
transaction_index: None,
|
transaction_index: None,
|
||||||
block_hash: None,
|
block_hash: None,
|
||||||
@ -142,6 +153,7 @@ mod tests {
|
|||||||
let receipt = Receipt {
|
let receipt = Receipt {
|
||||||
from: None,
|
from: None,
|
||||||
to: None,
|
to: None,
|
||||||
|
transaction_type: Default::default(),
|
||||||
transaction_hash: Some(0.into()),
|
transaction_hash: Some(0.into()),
|
||||||
transaction_index: Some(0.into()),
|
transaction_index: Some(0.into()),
|
||||||
block_hash: Some(
|
block_hash: Some(
|
||||||
|
@ -20,7 +20,10 @@ use ethcore::{contract_address, CreateContractAddress};
|
|||||||
use ethereum_types::{H160, H256, H512, U256, U64};
|
use ethereum_types::{H160, H256, H512, U256, U64};
|
||||||
use miner;
|
use miner;
|
||||||
use serde::{ser::SerializeStruct, Serialize, Serializer};
|
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};
|
use v1::types::{Bytes, TransactionCondition};
|
||||||
|
|
||||||
/// Transaction
|
/// Transaction
|
||||||
@ -67,6 +70,12 @@ pub struct Transaction {
|
|||||||
pub s: U256,
|
pub s: U256,
|
||||||
/// Transaction activates at specified block.
|
/// Transaction activates at specified block.
|
||||||
pub condition: Option<TransactionCondition>,
|
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
|
/// Local Transaction Status
|
||||||
@ -176,26 +185,35 @@ impl Transaction {
|
|||||||
pub fn from_localized(mut t: LocalizedTransaction) -> Transaction {
|
pub fn from_localized(mut t: LocalizedTransaction) -> Transaction {
|
||||||
let signature = t.signature();
|
let signature = t.signature();
|
||||||
let scheme = CreateContractAddress::FromSenderAndNonce;
|
let scheme = CreateContractAddress::FromSenderAndNonce;
|
||||||
|
|
||||||
|
let access_list = if let TypedTransaction::AccessList(al) = t.as_unsigned() {
|
||||||
|
al.access_list.clone()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
|
||||||
Transaction {
|
Transaction {
|
||||||
hash: t.hash(),
|
hash: t.hash(),
|
||||||
nonce: t.nonce,
|
nonce: t.tx().nonce,
|
||||||
block_hash: Some(t.block_hash),
|
block_hash: Some(t.block_hash),
|
||||||
block_number: Some(t.block_number.into()),
|
block_number: Some(t.block_number.into()),
|
||||||
transaction_index: Some(t.transaction_index.into()),
|
transaction_index: Some(t.transaction_index.into()),
|
||||||
from: t.sender(),
|
from: t.sender(),
|
||||||
to: match t.action {
|
to: match t.tx().action {
|
||||||
Action::Create => None,
|
Action::Create => None,
|
||||||
Action::Call(ref address) => Some(*address),
|
Action::Call(ref address) => Some(*address),
|
||||||
},
|
},
|
||||||
value: t.value,
|
value: t.tx().value,
|
||||||
gas_price: t.gas_price,
|
gas_price: t.tx().gas_price,
|
||||||
gas: t.gas,
|
gas: t.tx().gas,
|
||||||
input: Bytes::new(t.data.clone()),
|
input: Bytes::new(t.tx().data.clone()),
|
||||||
creates: match t.action {
|
creates: match t.tx().action {
|
||||||
Action::Create => Some(contract_address(scheme, &t.sender(), &t.nonce, &t.data).0),
|
Action::Create => {
|
||||||
|
Some(contract_address(scheme, &t.sender(), &t.tx().nonce, &t.tx().data).0)
|
||||||
|
}
|
||||||
Action::Call(_) => None,
|
Action::Call(_) => None,
|
||||||
},
|
},
|
||||||
raw: ::rlp::encode(&t.signed).into(),
|
raw: Bytes::new(t.signed.encode()),
|
||||||
public_key: t.recover_public().ok().map(Into::into),
|
public_key: t.recover_public().ok().map(Into::into),
|
||||||
chain_id: t.chain_id().map(U64::from),
|
chain_id: t.chain_id().map(U64::from),
|
||||||
standard_v: t.standard_v().into(),
|
standard_v: t.standard_v().into(),
|
||||||
@ -203,6 +221,8 @@ impl Transaction {
|
|||||||
r: signature.r().into(),
|
r: signature.r().into(),
|
||||||
s: signature.s().into(),
|
s: signature.s().into(),
|
||||||
condition: None,
|
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 {
|
pub fn from_signed(t: SignedTransaction) -> Transaction {
|
||||||
let signature = t.signature();
|
let signature = t.signature();
|
||||||
let scheme = CreateContractAddress::FromSenderAndNonce;
|
let scheme = CreateContractAddress::FromSenderAndNonce;
|
||||||
|
let access_list = if let TypedTransaction::AccessList(al) = t.as_unsigned() {
|
||||||
|
al.access_list.clone()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
Transaction {
|
Transaction {
|
||||||
hash: t.hash(),
|
hash: t.hash(),
|
||||||
nonce: t.nonce,
|
nonce: t.tx().nonce,
|
||||||
block_hash: None,
|
block_hash: None,
|
||||||
block_number: None,
|
block_number: None,
|
||||||
transaction_index: None,
|
transaction_index: None,
|
||||||
from: t.sender(),
|
from: t.sender(),
|
||||||
to: match t.action {
|
to: match t.tx().action {
|
||||||
Action::Create => None,
|
Action::Create => None,
|
||||||
Action::Call(ref address) => Some(*address),
|
Action::Call(ref address) => Some(*address),
|
||||||
},
|
},
|
||||||
value: t.value,
|
value: t.tx().value,
|
||||||
gas_price: t.gas_price,
|
gas_price: t.tx().gas_price,
|
||||||
gas: t.gas,
|
gas: t.tx().gas,
|
||||||
input: Bytes::new(t.data.clone()),
|
input: Bytes::new(t.tx().data.clone()),
|
||||||
creates: match t.action {
|
creates: match t.tx().action {
|
||||||
Action::Create => Some(contract_address(scheme, &t.sender(), &t.nonce, &t.data).0),
|
Action::Create => {
|
||||||
|
Some(contract_address(scheme, &t.sender(), &t.tx().nonce, &t.tx().data).0)
|
||||||
|
}
|
||||||
Action::Call(_) => None,
|
Action::Call(_) => None,
|
||||||
},
|
},
|
||||||
raw: ::rlp::encode(&t).into(),
|
raw: t.encode().into(),
|
||||||
public_key: t.public_key().map(Into::into),
|
public_key: t.public_key().map(Into::into),
|
||||||
chain_id: t.chain_id().map(U64::from),
|
chain_id: t.chain_id().map(U64::from),
|
||||||
standard_v: t.standard_v().into(),
|
standard_v: t.standard_v().into(),
|
||||||
@ -237,6 +264,8 @@ impl Transaction {
|
|||||||
r: signature.r().into(),
|
r: signature.r().into(),
|
||||||
s: signature.s().into(),
|
s: signature.s().into(),
|
||||||
condition: None,
|
condition: None,
|
||||||
|
transaction_type: t.tx_type() as u8,
|
||||||
|
access_list,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,7 +294,7 @@ impl LocalTransactionStatus {
|
|||||||
Canceled(tx) => LocalTransactionStatus::Canceled(convert(tx)),
|
Canceled(tx) => LocalTransactionStatus::Canceled(convert(tx)),
|
||||||
Replaced { old, new } => LocalTransactionStatus::Replaced(
|
Replaced { old, new } => LocalTransactionStatus::Replaced(
|
||||||
convert(old),
|
convert(old),
|
||||||
new.signed().gas_price,
|
new.signed().tx().gas_price,
|
||||||
new.signed().hash(),
|
new.signed().hash(),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
use ansi_term::Colour;
|
use ansi_term::Colour;
|
||||||
use ethereum_types::{H160, U256};
|
use ethereum_types::{H160, U256};
|
||||||
|
use types::transaction::{AccessList, TypedTxId};
|
||||||
use v1::{
|
use v1::{
|
||||||
helpers,
|
helpers,
|
||||||
types::{Bytes, TransactionCondition},
|
types::{Bytes, TransactionCondition},
|
||||||
@ -30,6 +31,10 @@ use std::fmt;
|
|||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct TransactionRequest {
|
pub struct TransactionRequest {
|
||||||
|
/// type of transaction. If none we assume it is legacy
|
||||||
|
#[serde(default)]
|
||||||
|
#[serde(skip_serializing)]
|
||||||
|
pub tx_type: TypedTxId,
|
||||||
/// Sender
|
/// Sender
|
||||||
pub from: Option<H160>,
|
pub from: Option<H160>,
|
||||||
/// Recipient
|
/// Recipient
|
||||||
@ -46,6 +51,9 @@ pub struct TransactionRequest {
|
|||||||
pub nonce: Option<U256>,
|
pub nonce: Option<U256>,
|
||||||
/// Delay until this block condition.
|
/// Delay until this block condition.
|
||||||
pub condition: Option<TransactionCondition>,
|
pub condition: Option<TransactionCondition>,
|
||||||
|
/// Access list
|
||||||
|
#[serde(skip_serializing)]
|
||||||
|
pub access_list: Option<AccessList>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format_ether(i: U256) -> String {
|
pub fn format_ether(i: U256) -> String {
|
||||||
@ -97,6 +105,7 @@ impl fmt::Display for TransactionRequest {
|
|||||||
impl From<helpers::TransactionRequest> for TransactionRequest {
|
impl From<helpers::TransactionRequest> for TransactionRequest {
|
||||||
fn from(r: helpers::TransactionRequest) -> Self {
|
fn from(r: helpers::TransactionRequest) -> Self {
|
||||||
TransactionRequest {
|
TransactionRequest {
|
||||||
|
tx_type: r.tx_type,
|
||||||
from: r.from.map(Into::into),
|
from: r.from.map(Into::into),
|
||||||
to: r.to.map(Into::into),
|
to: r.to.map(Into::into),
|
||||||
gas_price: r.gas_price.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),
|
data: r.data.map(Into::into),
|
||||||
nonce: r.nonce.map(Into::into),
|
nonce: r.nonce.map(Into::into),
|
||||||
condition: r.condition.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 {
|
impl From<helpers::FilledTransactionRequest> for TransactionRequest {
|
||||||
fn from(r: helpers::FilledTransactionRequest) -> Self {
|
fn from(r: helpers::FilledTransactionRequest) -> Self {
|
||||||
TransactionRequest {
|
TransactionRequest {
|
||||||
|
tx_type: r.tx_type,
|
||||||
from: Some(r.from),
|
from: Some(r.from),
|
||||||
to: r.to,
|
to: r.to,
|
||||||
gas_price: Some(r.gas_price),
|
gas_price: Some(r.gas_price),
|
||||||
@ -120,6 +131,7 @@ impl From<helpers::FilledTransactionRequest> for TransactionRequest {
|
|||||||
data: Some(r.data.into()),
|
data: Some(r.data.into()),
|
||||||
nonce: r.nonce,
|
nonce: r.nonce,
|
||||||
condition: r.condition,
|
condition: r.condition,
|
||||||
|
access_list: r.access_list,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,6 +139,7 @@ impl From<helpers::FilledTransactionRequest> for TransactionRequest {
|
|||||||
impl Into<helpers::TransactionRequest> for TransactionRequest {
|
impl Into<helpers::TransactionRequest> for TransactionRequest {
|
||||||
fn into(self) -> helpers::TransactionRequest {
|
fn into(self) -> helpers::TransactionRequest {
|
||||||
helpers::TransactionRequest {
|
helpers::TransactionRequest {
|
||||||
|
tx_type: self.tx_type,
|
||||||
from: self.from.map(Into::into),
|
from: self.from.map(Into::into),
|
||||||
to: self.to.map(Into::into),
|
to: self.to.map(Into::into),
|
||||||
gas_price: self.gas_price.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),
|
data: self.data.map(Into::into),
|
||||||
nonce: self.nonce.map(Into::into),
|
nonce: self.nonce.map(Into::into),
|
||||||
condition: self.condition.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!(
|
assert_eq!(
|
||||||
deserialized,
|
deserialized,
|
||||||
TransactionRequest {
|
TransactionRequest {
|
||||||
|
tx_type: Default::default(),
|
||||||
from: Some(H160::from(1)),
|
from: Some(H160::from(1)),
|
||||||
to: Some(H160::from(2)),
|
to: Some(H160::from(2)),
|
||||||
gas_price: Some(U256::from(1)),
|
gas_price: Some(U256::from(1)),
|
||||||
@ -173,6 +188,7 @@ mod tests {
|
|||||||
data: Some(vec![0x12, 0x34, 0x56].into()),
|
data: Some(vec![0x12, 0x34, 0x56].into()),
|
||||||
nonce: Some(U256::from(4)),
|
nonce: Some(U256::from(4)),
|
||||||
condition: Some(TransactionCondition::Number(0x13)),
|
condition: Some(TransactionCondition::Number(0x13)),
|
||||||
|
access_list: None,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -190,6 +206,7 @@ mod tests {
|
|||||||
let deserialized: TransactionRequest = serde_json::from_str(s).unwrap();
|
let deserialized: TransactionRequest = serde_json::from_str(s).unwrap();
|
||||||
|
|
||||||
assert_eq!(deserialized, TransactionRequest {
|
assert_eq!(deserialized, TransactionRequest {
|
||||||
|
tx_type: Default::default(),
|
||||||
from: Some(H160::from_str("b60e8dd61c5d32be8058bb8eb970870f07233155").unwrap()),
|
from: Some(H160::from_str("b60e8dd61c5d32be8058bb8eb970870f07233155").unwrap()),
|
||||||
to: Some(H160::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
to: Some(H160::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||||
gas_price: Some(U256::from_str("9184e72a000").unwrap()),
|
gas_price: Some(U256::from_str("9184e72a000").unwrap()),
|
||||||
@ -197,7 +214,8 @@ mod tests {
|
|||||||
value: Some(U256::from_str("9184e72a").unwrap()),
|
value: Some(U256::from_str("9184e72a").unwrap()),
|
||||||
data: Some("d46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675".from_hex().unwrap().into()),
|
data: Some("d46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675".from_hex().unwrap().into()),
|
||||||
nonce: None,
|
nonce: None,
|
||||||
condition: None,
|
condition: None,
|
||||||
|
access_list: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,6 +227,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
deserialized,
|
deserialized,
|
||||||
TransactionRequest {
|
TransactionRequest {
|
||||||
|
tx_type: Default::default(),
|
||||||
from: Some(H160::from(1).into()),
|
from: Some(H160::from(1).into()),
|
||||||
to: None,
|
to: None,
|
||||||
gas_price: None,
|
gas_price: None,
|
||||||
@ -217,6 +236,7 @@ mod tests {
|
|||||||
data: None,
|
data: None,
|
||||||
nonce: None,
|
nonce: None,
|
||||||
condition: None,
|
condition: None,
|
||||||
|
access_list: None,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -236,6 +256,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
deserialized,
|
deserialized,
|
||||||
TransactionRequest {
|
TransactionRequest {
|
||||||
|
tx_type: Default::default(),
|
||||||
from: Some(H160::from_str("b5f7502a2807cb23615c7456055e1d65b2508625").unwrap()),
|
from: Some(H160::from_str("b5f7502a2807cb23615c7456055e1d65b2508625").unwrap()),
|
||||||
to: Some(H160::from_str("895d32f2db7d01ebb50053f9e48aacf26584fe40").unwrap()),
|
to: Some(H160::from_str("895d32f2db7d01ebb50053f9e48aacf26584fe40").unwrap()),
|
||||||
gas_price: Some(U256::from_str("0ba43b7400").unwrap()),
|
gas_price: Some(U256::from_str("0ba43b7400").unwrap()),
|
||||||
@ -244,6 +265,7 @@ mod tests {
|
|||||||
data: Some(vec![0x85, 0x95, 0xba, 0xb1].into()),
|
data: Some(vec![0x85, 0x95, 0xba, 0xb1].into()),
|
||||||
nonce: None,
|
nonce: None,
|
||||||
condition: None,
|
condition: None,
|
||||||
|
access_list: None,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use call_contract::RegistryInfo;
|
use call_contract::RegistryInfo;
|
||||||
use common_types::transaction::{Action, SignedTransaction, Transaction};
|
use common_types::transaction::{Action, SignedTransaction, Transaction, TypedTransaction};
|
||||||
use ethcore::{
|
use ethcore::{
|
||||||
client::{BlockChainClient, BlockId, ChainInfo, Client, Nonce},
|
client::{BlockChainClient, BlockId, ChainInfo, Client, Nonce},
|
||||||
miner::{Miner, MinerService},
|
miner::{Miner, MinerService},
|
||||||
@ -89,16 +89,18 @@ impl TrustedClient {
|
|||||||
.upgrade()
|
.upgrade()
|
||||||
.ok_or_else(|| Error::Internal("cannot submit tx when miner is offline".into()))?;
|
.ok_or_else(|| Error::Internal("cannot submit tx when miner is offline".into()))?;
|
||||||
let engine = client.engine();
|
let engine = client.engine();
|
||||||
let transaction = Transaction {
|
let transaction = TypedTransaction::Legacy(Transaction {
|
||||||
nonce: client.latest_nonce(&self.self_key_pair.address()),
|
nonce: client.latest_nonce(&self.self_key_pair.address()),
|
||||||
action: Action::Call(contract),
|
action: Action::Call(contract),
|
||||||
gas: miner.authoring_params().gas_range_target.0,
|
gas: miner.authoring_params().gas_range_target.0,
|
||||||
gas_price: miner.sensible_gas_price(),
|
gas_price: miner.sensible_gas_price(),
|
||||||
value: Default::default(),
|
value: Default::default(),
|
||||||
data: tx_data,
|
data: tx_data,
|
||||||
};
|
});
|
||||||
let chain_id = engine.signing_chain_id(&client.latest_env_info());
|
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))?;
|
let signed = SignedTransaction::new(transaction.with_signature(signature, chain_id))?;
|
||||||
miner
|
miner
|
||||||
.import_own_transaction(&*client, signed.into())
|
.import_own_transaction(&*client, signed.into())
|
||||||
|
Loading…
Reference in New Issue
Block a user