plonky2/evm/src/cpu/kernel/tests/receipt.rs
Alonso González f49fbc8e9b
Transactions trie support (#1232)
* Implement transactions.

* Fix receipts and transactions

* Add some fixes

* Update tests

* Remove changes added for debugging purposes only

* Clippy

* Remove additional debug changes

* Remove unused

* Apply comments

---------

Co-authored-by: Linda Guiga <lindaguiga3@gmail.com>
Co-authored-by: Robin Salen <salenrobin@gmail.com>
2023-09-27 10:00:16 -04:00

618 lines
27 KiB
Rust

use anyhow::{anyhow, Result};
use ethereum_types::{Address, U256};
use hex_literal::hex;
use keccak_hash::keccak;
use rand::{thread_rng, Rng};
use crate::cpu::kernel::aggregator::KERNEL;
use crate::cpu::kernel::constants::global_metadata::GlobalMetadata;
use crate::cpu::kernel::constants::txn_fields::NormalizedTxnField;
use crate::cpu::kernel::interpreter::Interpreter;
use crate::generation::mpt::{all_mpt_prover_inputs_reversed, LegacyReceiptRlp, LogRlp};
use crate::memory::segments::Segment;
#[test]
fn test_process_receipt() -> Result<()> {
/* Tests process_receipt, which:
- computes the cumulative gas
- computes the bloom filter
- inserts the receipt data in MPT_TRIE_DATA
- inserts a node in receipt_trie
- resets the bloom filter to 0 for the next transaction. */
let process_receipt = KERNEL.global_labels["process_receipt"];
let success = U256::from(1);
let leftover_gas = U256::from(4000);
let prev_cum_gas = U256::from(1000);
let retdest = 0xDEADBEEFu32.into();
// Log.
let address: Address = thread_rng().gen();
let num_topics = 1;
let mut topic = vec![0_u8; 32];
topic[31] = 4;
// Compute the expected Bloom filter.
let test_logs_list = vec![(address.to_fixed_bytes().to_vec(), vec![topic])];
let expected_bloom = logs_bloom_bytes_fn(test_logs_list).to_vec();
// Set memory.
let num_nibbles = 2.into();
let initial_stack: Vec<U256> = vec![
retdest,
num_nibbles,
0.into(),
prev_cum_gas,
leftover_gas,
success,
];
let mut interpreter = Interpreter::new_with_kernel(process_receipt, initial_stack);
interpreter.set_memory_segment(
Segment::LogsData,
vec![
56.into(), // payload len
U256::from_big_endian(&address.to_fixed_bytes()), // address
num_topics.into(), // num_topics
4.into(), // topic
0.into(), // data_len
],
);
interpreter.set_txn_field(NormalizedTxnField::GasLimit, U256::from(5000));
interpreter.set_memory_segment(Segment::TxnBloom, vec![0.into(); 256]);
interpreter.set_memory_segment(Segment::BlockBloom, vec![0.into(); 256]);
interpreter.set_memory_segment(Segment::Logs, vec![0.into()]);
interpreter.set_global_metadata_field(GlobalMetadata::LogsPayloadLen, 58.into());
interpreter.set_global_metadata_field(GlobalMetadata::LogsLen, U256::from(1));
interpreter.set_global_metadata_field(GlobalMetadata::ReceiptTrieRoot, 500.into());
interpreter.run()?;
let segment_read = interpreter.get_memory_segment(Segment::TrieData);
// The expected TrieData has the form [payload_len, status, cum_gas_used, bloom_filter, logs_payload_len, num_logs, [logs]]
let mut expected_trie_data: Vec<U256> = vec![323.into(), success, 2000.into()];
expected_trie_data.extend(
expected_bloom
.into_iter()
.map(|elt| elt.into())
.collect::<Vec<U256>>(),
);
expected_trie_data.push(58.into()); // logs_payload_len
expected_trie_data.push(1.into()); // num_logs
expected_trie_data.extend(vec![
56.into(), // payload len
U256::from_big_endian(&address.to_fixed_bytes()), // address
num_topics.into(), // num_topics
4.into(), // topic
0.into(), // data_len
]);
assert_eq!(
expected_trie_data,
segment_read[0..expected_trie_data.len()]
);
Ok(())
}
/// Values taken from the block 1000000 of Goerli: https://goerli.etherscan.io/txs?block=1000000
#[test]
fn test_receipt_encoding() -> Result<()> {
// Initialize interpreter.
let success = U256::from(1);
let retdest = 0xDEADBEEFu32.into();
let num_topics = 3;
let encode_receipt = KERNEL.global_labels["encode_receipt"];
// Logs and receipt in encodable form.
let log_1 = LogRlp {
address: hex!("7ef66b77759e12Caf3dDB3E4AFF524E577C59D8D").into(),
topics: vec![
hex!("8a22ee899102a366ac8ad0495127319cb1ff2403cfae855f83a89cda1266674d").into(),
hex!("0000000000000000000000000000000000000000000000000000000000000004").into(),
hex!("00000000000000000000000000000000000000000000000000000000004920ea").into(),
],
data: hex!("a814f7df6a2203dc0e472e8828be95957c6b329fee8e2b1bb6f044c1eb4fc243")
.to_vec()
.into(),
};
let receipt_1 = LegacyReceiptRlp {
status: true,
cum_gas_used: 0x02dcb6u64.into(),
bloom: hex!("00000000000000000000000000000000000000000000000000800000000000000040000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000008000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000400000000000000000000000000000002000040000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000008000000000000000000000000").to_vec().into(),
logs: vec![log_1],
};
// Get the expected RLP encoding.
let expected_rlp = rlp::encode(&rlp::encode(&receipt_1));
let initial_stack: Vec<U256> = vec![retdest, 0.into(), 0.into()];
let mut interpreter = Interpreter::new_with_kernel(encode_receipt, initial_stack);
// Write data to memory.
let expected_bloom_bytes = vec![
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 0x80, 00, 00, 00, 00, 00, 00, 00, 0x40, 00, 00, 00, 00, 0x10, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x02, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 0x08, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 0x01, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 0x01, 00, 00, 00, 0x40, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 0x20, 00, 0x04, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x80, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x08,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
];
let expected_bloom: Vec<U256> = expected_bloom_bytes
.into_iter()
.map(|elt| elt.into())
.collect();
let addr = U256::from([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x7e, 0xf6, 0x6b, 0x77, 0x75, 0x9e, 0x12, 0xca, 0xf3,
0xdd, 0xb3, 0xe4, 0xaf, 0xf5, 0x24, 0xe5, 0x77, 0xc5, 0x9d, 0x8d,
]);
let topic1 = U256::from([
0x8a, 0x22, 0xee, 0x89, 0x91, 0x02, 0xa3, 0x66, 0xac, 0x8a, 0xd0, 0x49, 0x51, 0x27, 0x31,
0x9c, 0xb1, 0xff, 0x24, 0x03, 0xcf, 0xae, 0x85, 0x5f, 0x83, 0xa8, 0x9c, 0xda, 0x12, 0x66,
0x67, 0x4d,
]);
let topic2 = 4.into();
let topic3 = 0x4920ea.into();
let mut logs = vec![
155.into(), // unused
addr,
num_topics.into(), // num_topics
topic1, // topic1
topic2, // topic2
topic3, // topic3
32.into(), // data length
];
let cur_data = hex!("a814f7df6a2203dc0e472e8828be95957c6b329fee8e2b1bb6f044c1eb4fc243")
.iter()
.copied()
.map(U256::from);
logs.extend(cur_data);
let mut receipt = vec![423.into(), success, receipt_1.cum_gas_used];
receipt.extend(expected_bloom.clone());
receipt.push(157.into()); // logs_payload_len
receipt.push(1.into()); // num_logs
receipt.extend(logs.clone());
interpreter.set_memory_segment(Segment::LogsData, logs);
interpreter.set_memory_segment(Segment::TxnBloom, expected_bloom);
interpreter.set_memory_segment(Segment::Logs, vec![0.into()]);
interpreter.set_global_metadata_field(GlobalMetadata::LogsLen, 1.into());
interpreter.set_global_metadata_field(GlobalMetadata::LogsPayloadLen, 157.into());
interpreter.set_memory_segment(Segment::TrieData, receipt);
interpreter.run()?;
let rlp_pos = interpreter.pop();
let rlp_read: Vec<u8> = interpreter.get_rlp_memory();
assert_eq!(rlp_pos.as_usize(), expected_rlp.len());
for i in 0..rlp_read.len() {
assert_eq!(rlp_read[i], expected_rlp[i]);
}
Ok(())
}
/// Values taken from the block 1000000 of Goerli: https://goerli.etherscan.io/txs?block=1000000
#[test]
fn test_receipt_bloom_filter() -> Result<()> {
let logs_bloom = KERNEL.global_labels["logs_bloom"];
let num_topics = 3;
// Expected bloom
let first_bloom_bytes = vec![
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 0x80, 00, 00, 00, 00, 00, 00, 00, 0x40, 00, 00, 00, 00, 0x50, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x02, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 0x08, 00, 0x08, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x50, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x10,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x20, 00, 00, 00, 00, 00, 0x08, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
];
let retdest = 0xDEADBEEFu32.into();
let addr = U256::from([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x7e, 0xf6, 0x6b, 0x77, 0x75, 0x9e, 0x12, 0xca, 0xf3,
0xdd, 0xb3, 0xe4, 0xaf, 0xf5, 0x24, 0xe5, 0x77, 0xc5, 0x9d, 0x8d,
]);
let topic1 = U256::from([
0x8a, 0x22, 0xee, 0x89, 0x91, 0x02, 0xa3, 0x66, 0xac, 0x8a, 0xd0, 0x49, 0x51, 0x27, 0x31,
0x9c, 0xb1, 0xff, 0x24, 0x03, 0xcf, 0xae, 0x85, 0x5f, 0x83, 0xa8, 0x9c, 0xda, 0x12, 0x66,
0x67, 0x4d,
]);
let topic02 = 0x2a.into();
let topic03 = 0xbd9fe6.into();
// Set logs memory and initialize TxnBloom and BlockBloom segments.
let initial_stack: Vec<U256> = vec![retdest];
let mut interpreter = Interpreter::new_with_kernel(logs_bloom, initial_stack);
let mut logs = vec![
0.into(), // unused
addr,
num_topics.into(), // num_topics
topic1, // topic1
topic02, // topic2
topic03, // topic3
32.into(), // data_len
];
let cur_data = hex!("a814f7df6a2203dc0e472e8828be95957c6b329fee8e2b1bb6f044c1eb4fc243")
.iter()
.copied()
.map(U256::from);
logs.extend(cur_data);
// The Bloom filter initialization is required for this test to ensure we have the correct length for the filters. Otherwise, some trailing zeroes could be missing.
interpreter.set_memory_segment(Segment::TxnBloom, vec![0.into(); 256]); // Initialize transaction Bloom filter.
interpreter.set_memory_segment(Segment::BlockBloom, vec![0.into(); 256]); // Initialize block Bloom filter.
interpreter.set_memory_segment(Segment::LogsData, logs);
interpreter.set_memory_segment(Segment::Logs, vec![0.into()]);
interpreter.set_global_metadata_field(GlobalMetadata::LogsLen, U256::from(1));
interpreter.run()?;
// Second transaction.
let loaded_bloom_u256 = interpreter.get_memory_segment(Segment::TxnBloom);
let loaded_bloom: Vec<u8> = loaded_bloom_u256
.into_iter()
.map(|elt| elt.0[0] as u8)
.collect();
assert_eq!(first_bloom_bytes, loaded_bloom);
let topic12 = 0x4.into();
let topic13 = 0x4920ea.into();
let mut logs2 = vec![
0.into(), // unused
addr,
num_topics.into(), // num_topics
topic1, // topic1
topic12, // topic2
topic13, // topic3
32.into(), // data_len
];
let cur_data = hex!("a814f7df6a2203dc0e472e8828be95957c6b329fee8e2b1bb6f044c1eb4fc243")
.iter()
.copied()
.map(U256::from);
logs2.extend(cur_data);
interpreter.push(retdest);
interpreter.generation_state.registers.program_counter = logs_bloom;
interpreter.set_memory_segment(Segment::TxnBloom, vec![0.into(); 256]); // Initialize transaction Bloom filter.
interpreter.set_memory_segment(Segment::LogsData, logs2);
interpreter.set_memory_segment(Segment::Logs, vec![0.into()]);
interpreter.set_global_metadata_field(GlobalMetadata::LogsLen, U256::from(1));
interpreter.run()?;
let second_bloom_bytes = vec![
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 0x80, 00, 00, 00, 00, 00, 00, 00, 0x40, 00, 00, 00, 00, 0x10, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x02, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 0x08, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 0x01, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 0x01, 00, 00, 00, 0x40, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 0x20, 00, 0x04, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x80, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x08,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
];
let second_loaded_bloom_u256 = interpreter.get_memory_segment(Segment::TxnBloom);
let second_loaded_bloom: Vec<u8> = second_loaded_bloom_u256
.into_iter()
.map(|elt| elt.0[0] as u8)
.collect();
assert_eq!(second_bloom_bytes, second_loaded_bloom);
// Check the final block Bloom.
let block_bloom = hex!("00000000000000000000000000000000000000000000000000800000000000000040000000005000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000008000000000000000000000000000000000000000001000000080008000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000500000000000000000000000000000002000040000000000000000000000000000000000000000000000008000000000000000000000100000000000000000000000000020000000000008000000000000000000000000").to_vec();
let loaded_block_bloom: Vec<u8> = interpreter
.get_memory_segment(Segment::BlockBloom)
.into_iter()
.map(|elt| elt.0[0] as u8)
.collect();
assert_eq!(block_bloom, loaded_block_bloom);
Ok(())
}
#[test]
fn test_mpt_insert_receipt() -> Result<()> {
// This test simulates a receipt processing to test `mpt_insert_receipt_trie`.
// For this, we need to set the data correctly in memory.
// In TrieData, we need to insert a receipt of the form:
// `[payload_len, status, cum_gas_used, bloom, logs_payload_len, num_logs, [logs]]`.
// We also need to set TrieDataSize correctly.
let retdest = 0xDEADBEEFu32.into();
let trie_inputs = Default::default();
let load_all_mpts = KERNEL.global_labels["load_all_mpts"];
let mpt_insert = KERNEL.global_labels["mpt_insert_receipt_trie"];
let num_topics = 3; // Both transactions have the same number of topics.
let payload_len = 423; // Total payload length for each receipt.
let logs_payload_len = 157; // Payload length for all logs.
let log_payload_len = 155; // Payload length for one log.
let num_logs = 1;
// Receipt_0:
let status_0 = 1;
let cum_gas_used_0 = 0x016e5b;
let logs_bloom_0_bytes = vec![
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 0x80, 00, 00, 00, 00, 00, 00, 00, 0x40, 00, 00, 00, 00, 0x50, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x02, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 0x08, 00, 0x08, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x50, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x10,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x20, 00, 00, 00, 00, 00, 0x08, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
];
// Logs_0:
let logs_bloom_0: Vec<U256> = logs_bloom_0_bytes
.into_iter()
.map(|elt| elt.into())
.collect();
let addr = U256::from([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x7e, 0xf6, 0x6b, 0x77, 0x75, 0x9e, 0x12, 0xca, 0xf3,
0xdd, 0xb3, 0xe4, 0xaf, 0xf5, 0x24, 0xe5, 0x77, 0xc5, 0x9d, 0x8d,
]);
// The first topic is shared by the two transactions.
let topic1 = U256::from([
0x8a, 0x22, 0xee, 0x89, 0x91, 0x02, 0xa3, 0x66, 0xac, 0x8a, 0xd0, 0x49, 0x51, 0x27, 0x31,
0x9c, 0xb1, 0xff, 0x24, 0x03, 0xcf, 0xae, 0x85, 0x5f, 0x83, 0xa8, 0x9c, 0xda, 0x12, 0x66,
0x67, 0x4d,
]);
let topic02 = 0x2a.into();
let topic03 = 0xbd9fe6.into();
let mut logs_0 = vec![
log_payload_len.into(), // payload_len
addr,
num_topics.into(), // num_topics
topic1, // topic1
topic02, // topic2
topic03, // topic3
32.into(), // data_len
];
let cur_data = hex!("f7af1cc94b1aef2e0fa15f1b4baefa86eb60e78fa4bd082372a0a446d197fb58")
.iter()
.copied()
.map(U256::from);
logs_0.extend(cur_data);
let mut receipt: Vec<U256> = vec![423.into(), status_0.into(), cum_gas_used_0.into()];
receipt.extend(logs_bloom_0);
receipt.push(logs_payload_len.into()); // logs_payload_len
receipt.push(num_logs.into()); // num_logs
receipt.extend(logs_0.clone());
// First, we load all mpts.
let initial_stack: Vec<U256> = vec![retdest];
let mut interpreter = Interpreter::new_with_kernel(load_all_mpts, initial_stack);
interpreter.generation_state.mpt_prover_inputs =
all_mpt_prover_inputs_reversed(&trie_inputs)
.map_err(|err| anyhow!("Invalid MPT data: {:?}", err))?;
interpreter.run()?;
// If TrieData is empty, we need to push 0 because the first value is always 0.
let mut cur_trie_data = interpreter.get_memory_segment(Segment::TrieData);
if cur_trie_data.is_empty() {
cur_trie_data.push(0.into());
}
// stack: transaction_nb, value_ptr, retdest
let num_nibbles = 2;
let initial_stack: Vec<U256> = vec![
retdest,
cur_trie_data.len().into(),
0x80.into(),
num_nibbles.into(),
];
for i in 0..initial_stack.len() {
interpreter.push(initial_stack[i]);
}
interpreter.generation_state.registers.program_counter = mpt_insert;
// Set memory.
cur_trie_data.extend(receipt);
interpreter.set_memory_segment(Segment::TrieData, cur_trie_data.clone());
interpreter.set_global_metadata_field(GlobalMetadata::TrieDataSize, cur_trie_data.len().into());
// First insertion.
interpreter.run()?;
// receipt_1:
let status_1 = 1;
let cum_gas_used_1 = 0x02dcb6;
let logs_bloom_1_bytes = vec![
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 0x80, 00, 00, 00, 00, 00, 00, 00, 0x40, 00, 00, 00, 00, 0x10, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x02, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 0x08, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 0x01, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 0x01, 00, 00, 00, 0x40, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 0x20, 00, 0x04, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x80, 00, 00, 00, 00, 00, 00, 00, 00, 00,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x08,
00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
];
// Logs_1:
let logs_bloom_1: Vec<U256> = logs_bloom_1_bytes
.into_iter()
.map(|elt| elt.into())
.collect();
let topic12 = 4.into();
let topic13 = 0x4920ea.into();
let mut logs_1 = vec![
log_payload_len.into(), // payload length
addr,
num_topics.into(), // nb topics
topic1, // topic1
topic12, // topic2
topic13, // topic3
32.into(), // data length
];
let cur_data = hex!("a814f7df6a2203dc0e472e8828be95957c6b329fee8e2b1bb6f044c1eb4fc243")
.iter()
.copied()
.map(U256::from);
logs_1.extend(cur_data);
let mut receipt_1: Vec<U256> = vec![payload_len.into(), status_1.into(), cum_gas_used_1.into()];
receipt_1.extend(logs_bloom_1);
receipt_1.push(logs_payload_len.into()); // logs payload len
receipt_1.push(num_logs.into()); // nb logs
receipt_1.extend(logs_1.clone());
// Get updated TrieData segment.
cur_trie_data = interpreter.get_memory_segment(Segment::TrieData);
let num_nibbles = 2;
let initial_stack2: Vec<U256> = vec![
retdest,
cur_trie_data.len().into(),
0x01.into(),
num_nibbles.into(),
];
for i in 0..initial_stack2.len() {
interpreter.push(initial_stack2[i]);
}
cur_trie_data.extend(receipt_1);
// Set memory.
interpreter.generation_state.registers.program_counter = mpt_insert;
interpreter.set_memory_segment(Segment::TrieData, cur_trie_data.clone());
interpreter.set_global_metadata_field(GlobalMetadata::TrieDataSize, cur_trie_data.len().into());
interpreter.run()?;
// Finally, check that the hashes correspond.
let mpt_hash_receipt = KERNEL.global_labels["mpt_hash_receipt_trie"];
interpreter.generation_state.registers.program_counter = mpt_hash_receipt;
interpreter.push(retdest);
interpreter.run()?;
assert_eq!(
interpreter.stack()[0],
U256::from(hex!(
"da46cdd329bfedace32da95f2b344d314bc6f55f027d65f9f4ac04ee425e1f98"
))
);
Ok(())
}
#[test]
fn test_bloom_two_logs() -> Result<()> {
// Tests the Bloom filter computation with two logs in one transaction.
// address
let to = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x09, 0x5e, 0x7b, 0xae, 0xa6, 0xa6, 0xc7, 0xc4, 0xc2,
0xdf, 0xeb, 0x97, 0x7e, 0xfa, 0xc3, 0x26, 0xaf, 0x55, 0x2d, 0x87,
];
let retdest = 0xDEADBEEFu32.into();
let logs_bloom = KERNEL.global_labels["logs_bloom"];
let initial_stack: Vec<U256> = vec![retdest];
// Set memory.
let logs = vec![
0.into(), // unused
to.into(), // address
0.into(), // num_topics
0.into(), // data_len,
0.into(), // unused: rlp
to.into(),
2.into(), // num_topics
0x62.into(),
0x63.into(),
5.into(),
[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xa1,
0xb2, 0xc3, 0xd4, 0xe5,
]
.into(),
];
let mut interpreter = Interpreter::new_with_kernel(logs_bloom, initial_stack);
interpreter.set_memory_segment(Segment::TxnBloom, vec![0.into(); 256]); // Initialize transaction Bloom filter.
interpreter.set_memory_segment(Segment::BlockBloom, vec![0.into(); 256]); // Initialize block Bloom filter.
interpreter.set_memory_segment(Segment::LogsData, logs);
interpreter.set_memory_segment(Segment::Logs, vec![0.into(), 4.into()]);
interpreter.set_global_metadata_field(GlobalMetadata::LogsLen, U256::from(2));
interpreter.run()?;
let loaded_bloom_bytes: Vec<u8> = interpreter
.get_memory_segment(Segment::TxnBloom)
.into_iter()
.map(|elt| elt.0[0] as u8)
.collect();
let expected = hex!("00000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000004000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000400000000000040000000000000000000000000002000000000000000000000000000").to_vec();
assert_eq!(expected, loaded_bloom_bytes);
Ok(())
}
pub fn logs_bloom_bytes_fn(logs_list: Vec<(Vec<u8>, Vec<Vec<u8>>)>) -> [u8; 256] {
// The first element of logs_list.
let mut bloom = [0_u8; 256];
for log in logs_list {
let cur_addr = log.0;
let topics = log.1;
add_to_bloom(&mut bloom, &cur_addr);
for topic in topics {
add_to_bloom(&mut bloom, &topic);
}
}
bloom
}
fn add_to_bloom(bloom: &mut [u8; 256], bloom_entry: &[u8]) {
let bloom_hash = keccak(bloom_entry).to_fixed_bytes();
for idx in 0..3 {
let bit_pair = u16::from_be_bytes(bloom_hash[2 * idx..2 * (idx + 1)].try_into().unwrap());
let bit_to_set = 0x07FF - (bit_pair & 0x07FF);
let byte_index = bit_to_set / 8;
let bit_value = 1 << (7 - bit_to_set % 8);
bloom[byte_index as usize] |= bit_value;
}
}