EIP-98: Optional transaction state root (#4296)
* EIP98: Optional receipt state root * Use if-else * Fixing tests
This commit is contained in:
parent
f5a4b55dae
commit
c012dfc3ef
@ -268,7 +268,7 @@ mod tests {
|
||||
#[test]
|
||||
fn check_receipts() {
|
||||
let receipts = (0..5).map(|_| Receipt {
|
||||
state_root: H256::random(),
|
||||
state_root: Some(H256::random()),
|
||||
gas_used: 21_000u64.into(),
|
||||
log_bloom: Default::default(),
|
||||
logs: Vec::new(),
|
||||
|
@ -29,7 +29,8 @@
|
||||
"networkID" : "0x1",
|
||||
"chainID": "0x3d",
|
||||
"forkBlock": "0x1d4c00",
|
||||
"forkCanonHash": "0x94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f"
|
||||
"forkCanonHash": "0x94365e3a8c0b35089c1d1195081fe7489b528a84b22199c916180db8b28ade7f",
|
||||
"eip98Transition": "0x7fffffffffffff"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
|
@ -22,7 +22,8 @@
|
||||
"accountStartNonce": "0x00",
|
||||
"maximumExtraDataSize": "0x20",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID" : "0x1"
|
||||
"networkID" : "0x1",
|
||||
"eip98Transition": "0x7fffffffffffffff"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
|
@ -22,7 +22,8 @@
|
||||
"accountStartNonce": "0x00",
|
||||
"maximumExtraDataSize": "0x20",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID" : "0x1"
|
||||
"networkID" : "0x1",
|
||||
"eip98Transition": "0x7fffffffffffffff"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
|
@ -28,7 +28,8 @@
|
||||
"maximumExtraDataSize": "0x20",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID": "0x1",
|
||||
"subprotocolName": "exp"
|
||||
"subprotocolName": "exp",
|
||||
"eip98Transition": "0x7fffffffffffff"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
|
@ -146,7 +146,8 @@
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID" : "0x1",
|
||||
"forkBlock": "0x1d4c00",
|
||||
"forkCanonHash": "0x4985f5ca3d2afbec36529aa96f74de3cc10a2a4a6c44f2157a57d2c6059a11bb"
|
||||
"forkCanonHash": "0x4985f5ca3d2afbec36529aa96f74de3cc10a2a4a6c44f2157a57d2c6059a11bb",
|
||||
"eip98Transition": "0x7fffffffffffff"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
|
@ -142,7 +142,8 @@
|
||||
"accountStartNonce": "0x00",
|
||||
"maximumExtraDataSize": "0x20",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID" : "0x1"
|
||||
"networkID" : "0x1",
|
||||
"eip98Transition": "0x7fffffffffffff"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
|
@ -22,7 +22,8 @@
|
||||
"accountStartNonce": "0x00",
|
||||
"maximumExtraDataSize": "0x20",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID" : "0x1"
|
||||
"networkID" : "0x1",
|
||||
"eip98Transition": "0x7fffffffffffff"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
|
@ -22,7 +22,8 @@
|
||||
"accountStartNonce": "0x00",
|
||||
"maximumExtraDataSize": "0x20",
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID" : "0x1"
|
||||
"networkID" : "0x1",
|
||||
"eip98Transition": "0x7fffffffffffff"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
|
@ -29,7 +29,8 @@
|
||||
"networkID" : "0x2",
|
||||
"chainID": "0x3e",
|
||||
"forkBlock": "0x1b34d8",
|
||||
"forkCanonHash": "0xf376243aeff1f256d970714c3de9fd78fa4e63cf63e32a51fe1169e375d98145"
|
||||
"forkCanonHash": "0xf376243aeff1f256d970714c3de9fd78fa4e63cf63e32a51fe1169e375d98145",
|
||||
"eip98Transition": "0x7fffffffffffff"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
|
@ -22,7 +22,8 @@
|
||||
"accountStartNonce": "0x00",
|
||||
"maximumExtraDataSize": "0x0400",
|
||||
"minGasLimit": "125000",
|
||||
"networkID" : "0x0"
|
||||
"networkID" : "0x0",
|
||||
"eip98Transition": "0x7fffffffffffff"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
|
@ -26,7 +26,8 @@
|
||||
"minGasLimit": "0x1388",
|
||||
"networkID" : "0x3",
|
||||
"forkBlock": 333922,
|
||||
"forkCanonHash": "0x8737eb141d4f05db57af63fc8d3b4d4d8f9cddb0c4e1ab855de8c288fdc1924f"
|
||||
"forkCanonHash": "0x8737eb141d4f05db57af63fc8d3b4d4d8f9cddb0c4e1ab855de8c288fdc1924f",
|
||||
"eip98Transition": "0x7fffffffffffff"
|
||||
},
|
||||
"genesis": {
|
||||
"seal": {
|
||||
|
@ -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(),
|
||||
|
@ -49,6 +49,10 @@ pub struct Params {
|
||||
/// Expected fork block hash.
|
||||
#[serde(rename="forkCanonHash")]
|
||||
pub fork_hash: Option<H256>,
|
||||
|
||||
/// See `CommonParams` docs.
|
||||
#[serde(rename="eip98Transition")]
|
||||
pub eip98_transition: Option<Uint>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -969,7 +969,7 @@ fn rpc_eth_transaction_receipt() {
|
||||
log_index: 1,
|
||||
}],
|
||||
log_bloom: 0.into(),
|
||||
state_root: 0.into(),
|
||||
state_root: Some(0.into()),
|
||||
};
|
||||
|
||||
let hash = H256::from_str("b903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238").unwrap();
|
||||
|
@ -45,7 +45,7 @@ pub struct Receipt {
|
||||
pub logs: Vec<Log>,
|
||||
/// State Root
|
||||
#[serde(rename="root")]
|
||||
pub state_root: H256,
|
||||
pub state_root: Option<H256>,
|
||||
/// Logs bloom
|
||||
#[serde(rename="logsBloom")]
|
||||
pub logs_bloom: H2048,
|
||||
@ -62,7 +62,7 @@ impl From<LocalizedReceipt> for Receipt {
|
||||
gas_used: Some(r.gas_used.into()),
|
||||
contract_address: r.contract_address.map(Into::into),
|
||||
logs: r.logs.into_iter().map(Into::into).collect(),
|
||||
state_root: r.state_root.into(),
|
||||
state_root: r.state_root.map(Into::into),
|
||||
logs_bloom: r.log_bloom.into(),
|
||||
}
|
||||
}
|
||||
@ -79,7 +79,7 @@ impl From<RichReceipt> for Receipt {
|
||||
gas_used: Some(r.gas_used.into()),
|
||||
contract_address: r.contract_address.map(Into::into),
|
||||
logs: r.logs.into_iter().map(Into::into).collect(),
|
||||
state_root: r.state_root.into(),
|
||||
state_root: r.state_root.map(Into::into),
|
||||
logs_bloom: r.log_bloom.into(),
|
||||
}
|
||||
}
|
||||
@ -96,7 +96,7 @@ impl From<EthReceipt> for Receipt {
|
||||
gas_used: None,
|
||||
contract_address: None,
|
||||
logs: r.logs.into_iter().map(Into::into).collect(),
|
||||
state_root: r.state_root.into(),
|
||||
state_root: r.state_root.map(Into::into),
|
||||
logs_bloom: r.log_bloom.into(),
|
||||
}
|
||||
}
|
||||
@ -135,7 +135,7 @@ mod tests {
|
||||
log_type: "mined".into(),
|
||||
}],
|
||||
logs_bloom: 15.into(),
|
||||
state_root: 10.into(),
|
||||
state_root: Some(10.into()),
|
||||
};
|
||||
|
||||
let serialized = serde_json::to_string(&receipt).unwrap();
|
||||
|
Loading…
Reference in New Issue
Block a user