EIP-98: Optional transaction state root (#4296)
* EIP98: Optional receipt state root * Use if-else * Fixing tests
This commit is contained in:
committed by
Gav Wood
parent
f5a4b55dae
commit
c012dfc3ef
@@ -375,6 +375,9 @@ impl<'x> OpenBlock<'x> {
|
||||
let unclosed_state = s.block.state.clone();
|
||||
|
||||
s.engine.on_close_block(&mut s.block);
|
||||
if let Err(e) = s.block.state.commit() {
|
||||
warn!("Encountered error on state commit: {}", e);
|
||||
}
|
||||
s.block.header.set_transactions_root(ordered_trie_root(s.block.transactions.iter().map(|e| e.rlp_bytes().to_vec())));
|
||||
let uncle_bytes = s.block.uncles.iter().fold(RlpStream::new_list(s.block.uncles.len()), |mut s, u| {s.append_raw(&u.rlp(Seal::With), 1); s} ).out();
|
||||
s.block.header.set_uncles_hash(uncle_bytes.sha3());
|
||||
@@ -396,6 +399,10 @@ impl<'x> OpenBlock<'x> {
|
||||
let mut s = self;
|
||||
|
||||
s.engine.on_close_block(&mut s.block);
|
||||
|
||||
if let Err(e) = s.block.state.commit() {
|
||||
warn!("Encountered error on state commit: {}", e);
|
||||
}
|
||||
if s.block.header.transactions_root().is_zero() || s.block.header.transactions_root() == &SHA3_NULL_RLP {
|
||||
s.block.header.set_transactions_root(ordered_trie_root(s.block.transactions.iter().map(|e| e.rlp_bytes().to_vec())));
|
||||
}
|
||||
|
||||
@@ -1896,7 +1896,7 @@ mod tests {
|
||||
let db = new_db(temp.as_str());
|
||||
let bc = new_chain(&genesis, db.clone());
|
||||
insert_block(&db, &bc, &b1, vec![Receipt {
|
||||
state_root: H256::default(),
|
||||
state_root: Some(H256::default()),
|
||||
gas_used: 10_000.into(),
|
||||
log_bloom: Default::default(),
|
||||
logs: vec![
|
||||
@@ -1905,7 +1905,7 @@ mod tests {
|
||||
],
|
||||
},
|
||||
Receipt {
|
||||
state_root: H256::default(),
|
||||
state_root: Some(H256::default()),
|
||||
gas_used: 10_000.into(),
|
||||
log_bloom: Default::default(),
|
||||
logs: vec![
|
||||
@@ -1914,7 +1914,7 @@ mod tests {
|
||||
}]);
|
||||
insert_block(&db, &bc, &b2, vec![
|
||||
Receipt {
|
||||
state_root: H256::default(),
|
||||
state_root: Some(H256::default()),
|
||||
gas_used: 10_000.into(),
|
||||
log_bloom: Default::default(),
|
||||
logs: vec![
|
||||
|
||||
@@ -1713,7 +1713,7 @@ mod tests {
|
||||
|
||||
let block_number = 1;
|
||||
let block_hash = 5.into();
|
||||
let state_root = 99.into();
|
||||
let state_root = Some(99.into());
|
||||
let gas_used = 10.into();
|
||||
let raw_tx = Transaction {
|
||||
nonce: 0.into(),
|
||||
|
||||
@@ -591,7 +591,7 @@ impl BlockChainClient for TestBlockChainClient {
|
||||
// starts with 'f' ?
|
||||
if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") {
|
||||
let receipt = BlockReceipts::new(vec![Receipt::new(
|
||||
H256::zero(),
|
||||
Some(H256::zero()),
|
||||
U256::zero(),
|
||||
vec![])]);
|
||||
let mut rlp = RlpStream::new();
|
||||
|
||||
@@ -53,6 +53,8 @@ pub struct CommonParams {
|
||||
pub min_gas_limit: U256,
|
||||
/// Fork block to check.
|
||||
pub fork_block: Option<(BlockNumber, H256)>,
|
||||
/// Number of first block where EIP-98 rules begin.
|
||||
pub eip98_transition: BlockNumber,
|
||||
}
|
||||
|
||||
impl From<ethjson::spec::Params> for CommonParams {
|
||||
@@ -65,6 +67,7 @@ impl From<ethjson::spec::Params> for CommonParams {
|
||||
subprotocol_name: p.subprotocol_name.unwrap_or_else(|| "eth".to_owned()),
|
||||
min_gas_limit: p.min_gas_limit.into(),
|
||||
fork_block: if let (Some(n), Some(h)) = (p.fork_block, p.fork_hash) { Some((n.into(), h.into())) } else { None },
|
||||
eip98_transition: p.eip98_transition.map_or(0, Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -519,8 +519,13 @@ impl State {
|
||||
|
||||
// TODO uncomment once to_pod() works correctly.
|
||||
// trace!("Applied transaction. Diff:\n{}\n", state_diff::diff_pod(&old, &self.to_pod()));
|
||||
self.commit()?;
|
||||
let receipt = Receipt::new(self.root().clone(), e.cumulative_gas_used, e.logs);
|
||||
let state_root = if env_info.number < engine.params().eip98_transition {
|
||||
self.commit()?;
|
||||
Some(self.root().clone())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let receipt = Receipt::new(state_root, e.cumulative_gas_used, e.logs);
|
||||
trace!(target: "state", "Transaction receipt: {:?}", receipt);
|
||||
Ok(ApplyOutcome{receipt: receipt, trace: e.trace})
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ use log_entry::{LogEntry, LocalizedLogEntry};
|
||||
#[derive(Default, Debug, Clone)]
|
||||
#[cfg_attr(feature = "ipc", binary)]
|
||||
pub struct Receipt {
|
||||
/// The state root after executing the transaction.
|
||||
pub state_root: H256,
|
||||
/// The state root after executing the transaction. Optional since EIP98
|
||||
pub state_root: Option<H256>,
|
||||
/// The total gas used in the block following execution of the transaction.
|
||||
pub gas_used: U256,
|
||||
/// The OR-wide combination of all logs' blooms for this transaction.
|
||||
@@ -40,7 +40,7 @@ pub struct Receipt {
|
||||
|
||||
impl Receipt {
|
||||
/// Create a new receipt.
|
||||
pub fn new(state_root: H256, gas_used: U256, logs: Vec<LogEntry>) -> Receipt {
|
||||
pub fn new(state_root: Option<H256>, gas_used: U256, logs: Vec<LogEntry>) -> Receipt {
|
||||
Receipt {
|
||||
state_root: state_root,
|
||||
gas_used: gas_used,
|
||||
@@ -52,8 +52,12 @@ impl Receipt {
|
||||
|
||||
impl Encodable for Receipt {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(4);
|
||||
s.append(&self.state_root);
|
||||
if let Some(ref root) = self.state_root {
|
||||
s.begin_list(4);
|
||||
s.append(root);
|
||||
} else {
|
||||
s.begin_list(3);
|
||||
}
|
||||
s.append(&self.gas_used);
|
||||
s.append(&self.log_bloom);
|
||||
s.append(&self.logs);
|
||||
@@ -63,13 +67,21 @@ impl Encodable for Receipt {
|
||||
impl Decodable for Receipt {
|
||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||
let d = decoder.as_rlp();
|
||||
let receipt = Receipt {
|
||||
state_root: d.val_at(0)?,
|
||||
gas_used: d.val_at(1)?,
|
||||
log_bloom: d.val_at(2)?,
|
||||
logs: d.val_at(3)?,
|
||||
};
|
||||
Ok(receipt)
|
||||
if d.item_count() == 3 {
|
||||
Ok(Receipt {
|
||||
state_root: None,
|
||||
gas_used: d.val_at(0)?,
|
||||
log_bloom: d.val_at(1)?,
|
||||
logs: d.val_at(2)?,
|
||||
})
|
||||
} else {
|
||||
Ok(Receipt {
|
||||
state_root: d.val_at(0)?,
|
||||
gas_used: d.val_at(1)?,
|
||||
log_bloom: d.val_at(2)?,
|
||||
logs: d.val_at(3)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +110,7 @@ pub struct RichReceipt {
|
||||
/// Logs bloom
|
||||
pub log_bloom: LogBloom,
|
||||
/// State root
|
||||
pub state_root: H256,
|
||||
pub state_root: Option<H256>,
|
||||
}
|
||||
|
||||
/// Receipt with additional info.
|
||||
@@ -124,14 +136,29 @@ pub struct LocalizedReceipt {
|
||||
/// Logs bloom
|
||||
pub log_bloom: LogBloom,
|
||||
/// State root
|
||||
pub state_root: H256,
|
||||
pub state_root: Option<H256>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_basic() {
|
||||
let expected = ::rustc_serialize::hex::FromHex::from_hex("f90162a02f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee83040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||
fn test_no_state_root() {
|
||||
let expected = ::rustc_serialize::hex::FromHex::from_hex("f9014183040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||
let r = Receipt::new(
|
||||
"2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee".into(),
|
||||
None,
|
||||
0x40cae.into(),
|
||||
vec![LogEntry {
|
||||
address: "dcf421d093428b096ca501a7cd1a740855a7976f".into(),
|
||||
topics: vec![],
|
||||
data: vec![0u8; 32]
|
||||
}]
|
||||
);
|
||||
assert_eq!(&encode(&r)[..], &expected[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_basic() {
|
||||
let expected = ::rustc_serialize::hex::FromHex::from_hex("f90162a02f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee83040caeb9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000f838f794dcf421d093428b096ca501a7cd1a740855a7976fc0a00000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||
let r = Receipt::new(
|
||||
Some("2f697d671e9ae4ee24a43c4b0d7e15f1cb4ba6de1561120d43b9a4e8c4a8a6ee".into()),
|
||||
0x40cae.into(),
|
||||
vec![LogEntry {
|
||||
address: "dcf421d093428b096ca501a7cd1a740855a7976f".into(),
|
||||
|
||||
Reference in New Issue
Block a user