hypersync_client/simple_types.rs
1//! Base object types for the Hypersync client.
2use std::{collections::HashMap, sync::Arc};
3
4use arrayvec::ArrayVec;
5use hypersync_format::{
6 AccessList, Address, Authorization, BlockNumber, BloomFilter, Data, Hash, LogArgument,
7 LogIndex, Nonce, Quantity, TransactionIndex, TransactionStatus, TransactionType, Withdrawal,
8};
9use hypersync_net_types::{
10 block::BlockField, log::LogField, transaction::TransactionField, FieldSelection,
11};
12use nohash_hasher::IntMap;
13use serde::{Deserialize, Serialize};
14use xxhash_rust::xxh3::Xxh3Builder;
15
16use crate::types::ResponseData;
17
18/// An Ethereum event object.
19#[derive(Debug, Default, Clone, PartialEq)]
20pub struct Event {
21 /// An Ethereum event transaction object.
22 pub transaction: Option<Arc<Transaction>>,
23 /// An Ethereum event block object.
24 pub block: Option<Arc<Block>>,
25 /// An Ethereum event log object.
26 pub log: Log,
27}
28
29// Field lists for implementing event based API, these fields are used for joining
30// so they should always be added to the field selection.
31const BLOCK_JOIN_FIELD: BlockField = BlockField::Number;
32const TX_JOIN_FIELD: TransactionField = TransactionField::Hash;
33const LOG_JOIN_FIELD_WITH_TX: LogField = LogField::TransactionHash;
34const LOG_JOIN_FIELD_WITH_BLOCK: LogField = LogField::BlockNumber;
35
36enum InternalJoinStrategy {
37 NotSelected,
38 OnlyLogJoinField,
39 FullJoin,
40}
41
42/// Internal event join strategy for determining how to join blocks and transactions with logs
43pub(crate) struct InternalEventJoinStrategy {
44 block: InternalJoinStrategy,
45 transaction: InternalJoinStrategy,
46}
47
48impl From<&FieldSelection> for InternalEventJoinStrategy {
49 fn from(field_selection: &FieldSelection) -> Self {
50 let block_fields_num = field_selection.block.len();
51 let transaction_fields_num = field_selection.transaction.len();
52
53 Self {
54 block: if block_fields_num == 0 {
55 InternalJoinStrategy::NotSelected
56 } else if block_fields_num == 1 && field_selection.block.contains(&BLOCK_JOIN_FIELD) {
57 InternalJoinStrategy::OnlyLogJoinField
58 } else {
59 InternalJoinStrategy::FullJoin
60 },
61 transaction: if transaction_fields_num == 0 {
62 InternalJoinStrategy::NotSelected
63 } else if transaction_fields_num == 1
64 && field_selection.transaction.contains(&TX_JOIN_FIELD)
65 {
66 InternalJoinStrategy::OnlyLogJoinField
67 } else {
68 InternalJoinStrategy::FullJoin
69 },
70 }
71 }
72}
73
74impl InternalEventJoinStrategy {
75 /// Add join fields to field selection based on the event join strategy
76 pub(crate) fn add_join_fields_to_selection(&self, field_selection: &mut FieldSelection) {
77 match self.block {
78 InternalJoinStrategy::NotSelected => (),
79 InternalJoinStrategy::OnlyLogJoinField => {
80 field_selection.log.insert(LOG_JOIN_FIELD_WITH_BLOCK);
81 field_selection.block.remove(&BLOCK_JOIN_FIELD);
82 }
83 InternalJoinStrategy::FullJoin => {
84 field_selection.log.insert(LOG_JOIN_FIELD_WITH_BLOCK);
85 field_selection.block.insert(BLOCK_JOIN_FIELD);
86 }
87 }
88
89 match self.transaction {
90 InternalJoinStrategy::NotSelected => (),
91 InternalJoinStrategy::OnlyLogJoinField => {
92 field_selection.log.insert(LOG_JOIN_FIELD_WITH_TX);
93 field_selection.transaction.remove(&TX_JOIN_FIELD);
94 }
95 InternalJoinStrategy::FullJoin => {
96 field_selection.log.insert(LOG_JOIN_FIELD_WITH_TX);
97 field_selection.transaction.insert(TX_JOIN_FIELD);
98 }
99 }
100 }
101
102 /// Join response data into events based on the event join strategy
103 pub(crate) fn join_from_response_data(&self, data: ResponseData) -> Vec<Event> {
104 let blocks = data
105 .blocks
106 .into_iter()
107 .flat_map(|blocks| {
108 blocks
109 .into_iter()
110 .map(|block| (block.number.unwrap(), Arc::new(block)))
111 })
112 .collect::<IntMap<u64, _>>();
113
114 let transactions = data
115 .transactions
116 .into_iter()
117 .flat_map(|txs| {
118 txs.into_iter()
119 .map(|tx| (tx.hash.clone().unwrap(), Arc::new(tx)))
120 })
121 .collect::<HashMap<_, _, Xxh3Builder>>();
122
123 data.logs
124 .into_iter()
125 .flat_map(|logs| {
126 logs.into_iter().map(|log| {
127 let block = match self.block {
128 InternalJoinStrategy::NotSelected => None,
129 InternalJoinStrategy::OnlyLogJoinField => Some(Arc::new(Block {
130 number: Some(log.block_number.unwrap().into()),
131 ..Block::default()
132 })),
133 InternalJoinStrategy::FullJoin => {
134 blocks.get(&log.block_number.unwrap().into()).cloned()
135 }
136 };
137 let transaction = match self.transaction {
138 InternalJoinStrategy::NotSelected => None,
139 InternalJoinStrategy::OnlyLogJoinField => Some(Arc::new(Transaction {
140 hash: log.transaction_hash.clone(),
141 ..Transaction::default()
142 })),
143 InternalJoinStrategy::FullJoin => transactions
144 .get(log.transaction_hash.as_ref().unwrap())
145 .cloned(),
146 };
147
148 Event {
149 transaction,
150 block,
151 log,
152 }
153 })
154 })
155 .collect()
156 }
157}
158
159/// Block object
160#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
161pub struct Block {
162 /// A scalar value equal to the number of ancestor blocks. The genesis block has a number of
163 /// zero; formally Hi.
164 pub number: Option<u64>,
165 /// The Keccak 256-bit hash of the block
166 pub hash: Option<Hash>,
167 /// The Keccak 256-bit hash of the parent
168 /// block’s header, in its entirety; formally Hp.
169 pub parent_hash: Option<Hash>,
170 /// A 64-bit value which, combined with the mixhash, proves that a sufficient amount of
171 /// computation has been carried out on this block; formally Hn.
172 pub nonce: Option<Nonce>,
173 /// The Keccak 256-bit hash of the ommers/uncles list portion of this block; formally Ho.
174 pub sha3_uncles: Option<Hash>,
175 /// The Bloom filter composed from indexable information (logger address and log topics)
176 /// contained in each log entry from the receipt of each transaction in the transactions list;
177 /// formally Hb.
178 pub logs_bloom: Option<BloomFilter>,
179 /// The Keccak 256-bit hash of the root node of the trie structure populated with each
180 /// transaction in the transactions list portion of the block; formally Ht.
181 pub transactions_root: Option<Hash>,
182 /// The Keccak 256-bit hash of the root node of the state trie, after all transactions are
183 /// executed and finalisations applied; formally Hr.
184 pub state_root: Option<Hash>,
185 /// The Keccak 256-bit hash of the root node of the trie structure populated with each
186 /// transaction in the transactions list portion of the block; formally Ht.
187 pub receipts_root: Option<Hash>,
188 /// The 160-bit address to which all fees collected from the successful mining of this block
189 /// be transferred; formally Hc.
190 pub miner: Option<Address>,
191 /// A scalar value corresponding to the difficulty level of this block. This can be calculated
192 /// from the previous block’s difficulty level and the timestamp; formally Hd.
193 pub difficulty: Option<Quantity>,
194 /// The cumulative sum of the difficulty of all blocks that have been mined in the Ethereum
195 /// network since the inception of the network.
196 /// It measures the overall security and integrity of the Ethereum network.
197 pub total_difficulty: Option<Quantity>,
198 /// An arbitrary byte array containing data relevant to this block. This must be 32 bytes or
199 /// fewer; formally Hx.
200 pub extra_data: Option<Data>,
201 /// The size of this block in bytes as an integer value, encoded as hexadecimal.
202 pub size: Option<Quantity>,
203 /// A scalar value equal to the current limit of gas expenditure per block; formally Hl.
204 pub gas_limit: Option<Quantity>,
205 /// A scalar value equal to the total gas used in transactions in this block; formally Hg.
206 pub gas_used: Option<Quantity>,
207 /// A scalar value equal to the reasonable output of Unix’s time() at this block’s inception;
208 /// formally Hs.
209 pub timestamp: Option<Quantity>,
210 /// Ommers/uncles header.
211 pub uncles: Option<Vec<Hash>>,
212 /// A scalar representing EIP1559 base fee which can move up or down each block according
213 /// to a formula which is a function of gas used in parent block and gas target
214 /// (block gas limit divided by elasticity multiplier) of parent block.
215 /// The algorithm results in the base fee per gas increasing when blocks are
216 /// above the gas target, and decreasing when blocks are below the gas target. The base fee per
217 /// gas is burned.
218 pub base_fee_per_gas: Option<Quantity>,
219 /// The total amount of blob gas consumed by the transactions within the block, added in
220 /// EIP-4844.
221 pub blob_gas_used: Option<Quantity>,
222 /// A running total of blob gas consumed in excess of the target, prior to the block. Blocks
223 /// with above-target blob gas consumption increase this value, blocks with below-target blob
224 /// gas consumption decrease it (bounded at 0). This was added in EIP-4844.
225 pub excess_blob_gas: Option<Quantity>,
226 /// The hash of the parent beacon block's root is included in execution blocks, as proposed by
227 /// EIP-4788.
228 ///
229 /// This enables trust-minimized access to consensus state, supporting staking pools, bridges,
230 /// and more.
231 ///
232 /// The beacon roots contract handles root storage, enhancing Ethereum's functionalities.
233 pub parent_beacon_block_root: Option<Hash>,
234 /// The Keccak 256-bit hash of the withdrawals list portion of this block.
235 ///
236 /// See [EIP-4895](https://eips.ethereum.org/EIPS/eip-4895).
237 pub withdrawals_root: Option<Hash>,
238 /// Withdrawal represents a validator withdrawal from the consensus layer.
239 pub withdrawals: Option<Vec<Withdrawal>>,
240 /// The L1 block number that would be used for block.number calls.
241 pub l1_block_number: Option<BlockNumber>,
242 /// The number of L2 to L1 messages since Nitro genesis.
243 pub send_count: Option<Quantity>,
244 /// The Merkle root of the outbox tree state.
245 pub send_root: Option<Hash>,
246 /// A 256-bit hash which, combined with the
247 /// nonce, proves that a sufficient amount of computation has been carried out on this block;
248 /// formally Hm.
249 pub mix_hash: Option<Hash>,
250}
251
252/// Transaction object
253#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
254pub struct Transaction {
255 /// The Keccak 256-bit hash of the block
256 pub block_hash: Option<Hash>,
257 /// A scalar value equal to the number of ancestor blocks. The genesis block has a number of
258 /// zero; formally Hi.
259 pub block_number: Option<BlockNumber>,
260 /// The 160-bit address of the message call’s sender
261 pub from: Option<Address>,
262 /// A scalar value equal to the maximum
263 /// amount of gas that should be used in executing
264 /// this transaction. This is paid up-front, before any
265 /// computation is done and may not be increased
266 /// later; formally Tg.
267 pub gas: Option<Quantity>,
268 /// A scalar value equal to the number of
269 /// Wei to be paid per unit of gas for all computation
270 /// costs incurred as a result of the execution of this transaction; formally Tp.
271 pub gas_price: Option<Quantity>,
272 /// A transaction hash is a keccak hash of an RLP encoded signed transaction.
273 pub hash: Option<Hash>,
274 /// Input has two uses depending if transaction is Create or Call (if `to` field is None or
275 /// Some). pub init: An unlimited size byte array specifying the
276 /// EVM-code for the account initialisation procedure CREATE,
277 /// data: An unlimited size byte array specifying the
278 /// input data of the message call, formally Td.
279 pub input: Option<Data>,
280 /// A scalar value equal to the number of transactions sent by the sender; formally Tn.
281 pub nonce: Option<Quantity>,
282 /// The 160-bit address of the message call’s recipient or, for a contract creation
283 /// transaction, ∅, used here to denote the only member of B0 ; formally Tt.
284 pub to: Option<Address>,
285 /// Index of the transaction in the block
286 pub transaction_index: Option<TransactionIndex>,
287 /// A scalar value equal to the number of Wei to
288 /// be transferred to the message call’s recipient or,
289 /// in the case of contract creation, as an endowment
290 /// to the newly created account; formally Tv.
291 pub value: Option<Quantity>,
292 /// Replay protection value based on chain_id. See EIP-155 for more info.
293 pub v: Option<Quantity>,
294 /// The R field of the signature; the point on the curve.
295 pub r: Option<Quantity>,
296 /// The S field of the signature; the point on the curve.
297 pub s: Option<Quantity>,
298 /// yParity: Signature Y parity; formally Ty
299 pub y_parity: Option<Quantity>,
300 /// Max Priority fee that transaction is paying
301 ///
302 /// As ethereum circulation is around 120mil eth as of 2022 that is around
303 /// 120000000000000000000000000 wei we are safe to use u128 as its max number is:
304 /// 340282366920938463463374607431768211455
305 ///
306 /// This is also known as `GasTipCap`
307 pub max_priority_fee_per_gas: Option<Quantity>,
308 /// A scalar value equal to the maximum
309 /// amount of gas that should be used in executing
310 /// this transaction. This is paid up-front, before any
311 /// computation is done and may not be increased
312 /// later; formally Tg.
313 ///
314 /// As ethereum circulation is around 120mil eth as of 2022 that is around
315 /// 120000000000000000000000000 wei we are safe to use u128 as its max number is:
316 /// 340282366920938463463374607431768211455
317 ///
318 /// This is also known as `GasFeeCap`
319 pub max_fee_per_gas: Option<Quantity>,
320 /// Added as EIP-pub 155: Simple replay attack protection
321 pub chain_id: Option<Quantity>,
322 /// The accessList specifies a list of addresses and storage keys;
323 /// these addresses and storage keys are added into the `accessed_addresses`
324 /// and `accessed_storage_keys` global sets (introduced in EIP-2929).
325 /// A gas cost is charged, though at a discount relative to the cost of
326 /// accessing outside the list.
327 pub access_list: Option<Vec<AccessList>>,
328 /// The authorization_list specifies a list of authorizations for the transaction
329 /// (introduced in EIP-7702)
330 pub authorization_list: Option<Vec<Authorization>>,
331 /// Max fee per data gas
332 ///
333 /// aka BlobFeeCap or blobGasFeeCap
334 pub max_fee_per_blob_gas: Option<Quantity>,
335 /// It contains a vector of fixed size hash(32 bytes)
336 pub blob_versioned_hashes: Option<Vec<Hash>>,
337 /// The total amount of gas used in the block until this transaction was executed.
338 pub cumulative_gas_used: Option<Quantity>,
339 /// The sum of the base fee and tip paid per unit of gas.
340 pub effective_gas_price: Option<Quantity>,
341 /// Gas used by transaction
342 pub gas_used: Option<Quantity>,
343 /// Address of created contract if transaction was a contract creation
344 pub contract_address: Option<Address>,
345 /// Bloom filter for logs produced by this transaction
346 pub logs_bloom: Option<BloomFilter>,
347 /// Transaction type. For ethereum: Legacy, Eip2930, Eip1559, Eip4844
348 #[serde(rename = "type")]
349 pub type_: Option<TransactionType>,
350 /// The Keccak 256-bit hash of the root node of the trie structure populated with each
351 /// transaction in the transactions list portion of the block; formally Ht.
352 pub root: Option<Hash>,
353 /// If transaction is executed successfully.
354 ///
355 /// This is the `statusCode`
356 pub status: Option<TransactionStatus>,
357 /// The fee associated with a transaction on the Layer 1,
358 /// it is calculated as l1GasPrice multiplied by l1GasUsed
359 pub l1_fee: Option<Quantity>,
360 /// The gas price for transactions on the Layer 1
361 pub l1_gas_price: Option<Quantity>,
362 /// The amount of gas consumed by a transaction on the Layer 1
363 pub l1_gas_used: Option<Quantity>,
364 /// A multiplier applied to the actual gas usage on Layer 1 to calculate the dynamic costs.
365 /// If set to 1, it has no impact on the L1 gas usage
366 pub l1_fee_scalar: Option<f64>,
367 /// Amount of gas spent on L1 calldata in units of L2 gas.
368 pub gas_used_for_l1: Option<Quantity>,
369 /// Gas price for blob transactions
370 pub blob_gas_price: Option<Quantity>,
371 /// Amount of blob gas used by this transaction
372 pub blob_gas_used: Option<Quantity>,
373 /// Deposit transaction nonce for Optimism
374 pub deposit_nonce: Option<Quantity>,
375 /// Deposit receipt version for Optimism
376 pub deposit_receipt_version: Option<Quantity>,
377 /// Base fee scalar for L1 cost calculation
378 pub l1_base_fee_scalar: Option<Quantity>,
379 /// L1 blob base fee for cost calculation
380 pub l1_blob_base_fee: Option<Quantity>,
381 /// L1 blob base fee scalar for cost calculation
382 pub l1_blob_base_fee_scalar: Option<Quantity>,
383 /// L1 block number associated with transaction
384 pub l1_block_number: Option<Quantity>,
385 /// Amount of ETH minted in this transaction
386 pub mint: Option<Quantity>,
387 /// 4-byte function signature hash
388 pub sighash: Option<Data>,
389 /// Source hash for optimism transactions
390 pub source_hash: Option<Hash>,
391}
392
393/// Log object
394#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
395pub struct Log {
396 /// The boolean value indicating if the event was removed from the blockchain due
397 /// to a chain reorganization. True if the log was removed. False if it is a valid log.
398 pub removed: Option<bool>,
399 /// The integer identifying the index of the event within the block's list of events.
400 pub log_index: Option<LogIndex>,
401 /// The integer index of the transaction within the block's list of transactions.
402 pub transaction_index: Option<TransactionIndex>,
403 /// The hash of the transaction that triggered the event.
404 pub transaction_hash: Option<Hash>,
405 /// The hash of the block in which the event was included.
406 pub block_hash: Option<Hash>,
407 /// The block number in which the event was included.
408 pub block_number: Option<BlockNumber>,
409 /// The contract address from which the event originated.
410 pub address: Option<Address>,
411 /// The non-indexed data that was emitted along with the event.
412 pub data: Option<Data>,
413 /// An array of 32-byte data fields containing indexed event parameters.
414 pub topics: ArrayVec<Option<LogArgument>, 4>,
415}
416
417/// Trace object
418#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
419pub struct Trace {
420 /// The address of the sender who initiated the transaction.
421 pub from: Option<Address>,
422 /// The address of the recipient of the transaction if it was a transaction to an address.
423 /// For contract creation transactions, this field is None.
424 pub to: Option<Address>,
425 /// The type of trace, `call` or `delegatecall`, two ways to invoke a function in a smart contract.
426 ///
427 /// `call` creates a new environment for the function to work in, so changes made in that
428 /// function won't affect the environment where the function was called.
429 ///
430 /// `delegatecall` doesn't create a new environment. Instead, it runs the function within the
431 /// environment of the caller, so changes made in that function will affect the caller's environment.
432 pub call_type: Option<String>,
433 /// The units of gas included in the transaction by the sender.
434 pub gas: Option<Quantity>,
435 /// The optional input data sent with the transaction, usually used to interact with smart contracts.
436 pub input: Option<Data>,
437 /// The init code.
438 pub init: Option<Data>,
439 /// The value of the native token transferred along with the transaction, in Wei.
440 pub value: Option<Quantity>,
441 /// The address of the receiver for reward transaction.
442 pub author: Option<Address>,
443 /// Kind of reward. `Block` reward or `Uncle` reward.
444 pub reward_type: Option<String>,
445 /// The hash of the block in which the transaction was included.
446 pub block_hash: Option<Hash>,
447 /// The number of the block in which the transaction was included.
448 pub block_number: Option<u64>,
449 /// Destroyed address.
450 pub address: Option<Address>,
451 /// Contract code.
452 pub code: Option<Data>,
453 /// The total used gas by the call, encoded as hexadecimal.
454 pub gas_used: Option<Quantity>,
455 /// The return value of the call, encoded as a hexadecimal string.
456 pub output: Option<Data>,
457 /// The number of sub-traces created during execution. When a transaction is executed on the EVM,
458 /// it may trigger additional sub-executions, such as when a smart contract calls another smart
459 /// contract or when an external account is accessed.
460 pub subtraces: Option<u64>,
461 /// An array that indicates the position of the transaction in the trace.
462 pub trace_address: Option<Vec<u64>>,
463 /// The hash of the transaction.
464 pub transaction_hash: Option<Hash>,
465 /// The index of the transaction in the block.
466 pub transaction_position: Option<u64>,
467 /// The type of action taken by the transaction, `call`, `create`, `reward` and `suicide`.
468 ///
469 /// `call` is the most common type of trace and occurs when a smart contract invokes another contract's function.
470 ///
471 /// `create` represents the creation of a new smart contract. This type of trace occurs when a smart contract is deployed to the blockchain.
472 #[serde(rename = "type")]
473 pub type_: Option<String>,
474 /// A string that indicates whether the transaction was successful or not.
475 ///
476 /// None if successful, Reverted if not.
477 pub error: Option<String>,
478 /// 4-byte function signature hash for the trace
479 pub sighash: Option<Data>,
480 /// The action address for traces that create contracts
481 pub action_address: Option<Address>,
482 /// The balance associated with the trace operation
483 pub balance: Option<Quantity>,
484 /// The refund address for refund operations
485 pub refund_address: Option<Address>,
486}
487
488#[cfg(test)]
489mod tests {
490 use hypersync_net_types::TraceField;
491
492 use super::*;
493
494 fn has_tx_field(tx: &Transaction, field: TransactionField) -> bool {
495 match field {
496 TransactionField::BlockHash => tx.block_hash.is_none(),
497 TransactionField::BlockNumber => tx.block_number.is_none(),
498 TransactionField::From => tx.from.is_none(),
499 TransactionField::Gas => tx.gas.is_none(),
500 TransactionField::Hash => tx.hash.is_none(),
501 TransactionField::Input => tx.input.is_none(),
502 TransactionField::Nonce => tx.nonce.is_none(),
503 TransactionField::TransactionIndex => tx.transaction_index.is_none(),
504 TransactionField::Value => tx.value.is_none(),
505 TransactionField::CumulativeGasUsed => tx.cumulative_gas_used.is_none(),
506 TransactionField::EffectiveGasPrice => tx.effective_gas_price.is_none(),
507 TransactionField::GasUsed => tx.gas_used.is_none(),
508 TransactionField::LogsBloom => tx.logs_bloom.is_none(),
509 TransactionField::GasPrice => tx.gas_price.is_none(),
510 TransactionField::To => tx.to.is_none(),
511 TransactionField::V => tx.v.is_none(),
512 TransactionField::R => tx.r.is_none(),
513 TransactionField::S => tx.s.is_none(),
514 TransactionField::MaxPriorityFeePerGas => tx.max_priority_fee_per_gas.is_none(),
515 TransactionField::MaxFeePerGas => tx.max_fee_per_gas.is_none(),
516 TransactionField::ChainId => tx.chain_id.is_none(),
517 TransactionField::ContractAddress => tx.contract_address.is_none(),
518 TransactionField::Type => tx.type_.is_none(),
519 TransactionField::Root => tx.root.is_none(),
520 TransactionField::Status => tx.status.is_none(),
521 TransactionField::YParity => tx.y_parity.is_none(),
522 TransactionField::AccessList => tx.access_list.is_none(),
523 TransactionField::AuthorizationList => tx.authorization_list.is_none(),
524 TransactionField::L1Fee => tx.l1_fee.is_none(),
525 TransactionField::L1GasPrice => tx.l1_gas_price.is_none(),
526 TransactionField::L1GasUsed => tx.l1_gas_used.is_none(),
527 TransactionField::L1FeeScalar => tx.l1_fee_scalar.is_none(),
528 TransactionField::GasUsedForL1 => tx.gas_used_for_l1.is_none(),
529 TransactionField::MaxFeePerBlobGas => tx.max_fee_per_blob_gas.is_none(),
530 TransactionField::BlobVersionedHashes => tx.blob_versioned_hashes.is_none(),
531 TransactionField::BlobGasPrice => tx.blob_gas_price.is_none(),
532 TransactionField::BlobGasUsed => tx.blob_gas_used.is_none(),
533 TransactionField::DepositNonce => tx.deposit_nonce.is_none(),
534 TransactionField::DepositReceiptVersion => tx.deposit_receipt_version.is_none(),
535 TransactionField::L1BaseFeeScalar => tx.l1_base_fee_scalar.is_none(),
536 TransactionField::L1BlobBaseFee => tx.l1_blob_base_fee.is_none(),
537 TransactionField::L1BlobBaseFeeScalar => tx.l1_blob_base_fee_scalar.is_none(),
538 TransactionField::L1BlockNumber => tx.l1_block_number.is_none(),
539 TransactionField::Mint => tx.mint.is_none(),
540 TransactionField::Sighash => tx.sighash.is_none(),
541 TransactionField::SourceHash => tx.source_hash.is_none(),
542 }
543 }
544
545 fn has_block_field(block: &Block, field: BlockField) -> bool {
546 match field {
547 BlockField::Number => block.number.is_none(),
548 BlockField::Hash => block.hash.is_none(),
549 BlockField::ParentHash => block.parent_hash.is_none(),
550 BlockField::Nonce => block.nonce.is_none(),
551 BlockField::Sha3Uncles => block.sha3_uncles.is_none(),
552 BlockField::LogsBloom => block.logs_bloom.is_none(),
553 BlockField::TransactionsRoot => block.transactions_root.is_none(),
554 BlockField::StateRoot => block.state_root.is_none(),
555 BlockField::ReceiptsRoot => block.receipts_root.is_none(),
556 BlockField::Miner => block.miner.is_none(),
557 BlockField::Difficulty => block.difficulty.is_none(),
558 BlockField::TotalDifficulty => block.total_difficulty.is_none(),
559 BlockField::ExtraData => block.extra_data.is_none(),
560 BlockField::Size => block.size.is_none(),
561 BlockField::GasLimit => block.gas_limit.is_none(),
562 BlockField::GasUsed => block.gas_used.is_none(),
563 BlockField::Timestamp => block.timestamp.is_none(),
564 BlockField::Uncles => block.uncles.is_none(),
565 BlockField::BaseFeePerGas => block.base_fee_per_gas.is_none(),
566 BlockField::BlobGasUsed => block.blob_gas_used.is_none(),
567 BlockField::ExcessBlobGas => block.excess_blob_gas.is_none(),
568 BlockField::ParentBeaconBlockRoot => block.parent_beacon_block_root.is_none(),
569 BlockField::WithdrawalsRoot => block.withdrawals_root.is_none(),
570 BlockField::Withdrawals => block.withdrawals.is_none(),
571 BlockField::L1BlockNumber => block.l1_block_number.is_none(),
572 BlockField::SendCount => block.send_count.is_none(),
573 BlockField::SendRoot => block.send_root.is_none(),
574 BlockField::MixHash => block.mix_hash.is_none(),
575 }
576 }
577
578 fn has_log_field(log: &Log, field: LogField) -> bool {
579 match field {
580 LogField::Removed => log.removed.is_none(),
581 LogField::LogIndex => log.log_index.is_none(),
582 LogField::TransactionIndex => log.transaction_index.is_none(),
583 LogField::TransactionHash => log.transaction_hash.is_none(),
584 LogField::BlockHash => log.block_hash.is_none(),
585 LogField::BlockNumber => log.block_number.is_none(),
586 LogField::Address => log.address.is_none(),
587 LogField::Data => log.data.is_none(),
588 #[allow(clippy::get_first)] // annoying clippy
589 LogField::Topic0 => log.topics.get(0).is_none(),
590 LogField::Topic1 => log.topics.get(1).is_none(),
591 LogField::Topic2 => log.topics.get(2).is_none(),
592 LogField::Topic3 => log.topics.get(3).is_none(),
593 }
594 }
595
596 fn has_trace_field(trace: &Trace, field: TraceField) -> bool {
597 match field {
598 TraceField::From => trace.from.is_none(),
599 TraceField::To => trace.to.is_none(),
600 TraceField::CallType => trace.call_type.is_none(),
601 TraceField::Gas => trace.gas.is_none(),
602 TraceField::Input => trace.input.is_none(),
603 TraceField::Init => trace.init.is_none(),
604 TraceField::Value => trace.value.is_none(),
605 TraceField::Author => trace.author.is_none(),
606 TraceField::RewardType => trace.reward_type.is_none(),
607 TraceField::BlockHash => trace.block_hash.is_none(),
608 TraceField::BlockNumber => trace.block_number.is_none(),
609 TraceField::Address => trace.address.is_none(),
610 TraceField::Code => trace.code.is_none(),
611 TraceField::GasUsed => trace.gas_used.is_none(),
612 TraceField::Output => trace.output.is_none(),
613 TraceField::Subtraces => trace.subtraces.is_none(),
614 TraceField::TraceAddress => trace.trace_address.is_none(),
615 TraceField::TransactionHash => trace.transaction_hash.is_none(),
616 TraceField::TransactionPosition => trace.transaction_position.is_none(),
617 TraceField::Type => trace.type_.is_none(),
618 TraceField::Error => trace.error.is_none(),
619 TraceField::Sighash => trace.sighash.is_none(),
620 TraceField::ActionAddress => trace.action_address.is_none(),
621 TraceField::Balance => trace.balance.is_none(),
622 TraceField::RefundAddress => trace.refund_address.is_none(),
623 }
624 }
625
626 #[test]
627 fn has_all_tx_fields() {
628 let tx = Transaction::default();
629 for field in TransactionField::all() {
630 assert!(has_tx_field(&tx, field));
631 }
632 }
633
634 #[test]
635 fn has_all_block_fields() {
636 let block = Block::default();
637 for field in BlockField::all() {
638 assert!(has_block_field(&block, field));
639 }
640 }
641
642 #[test]
643 fn has_all_log_fields() {
644 let log = Log::default();
645 for field in LogField::all() {
646 assert!(has_log_field(&log, field));
647 }
648 }
649
650 #[test]
651 fn has_all_trace_fields() {
652 let trace = Trace::default();
653 for field in TraceField::all() {
654 assert!(has_trace_field(&trace, field));
655 }
656 }
657}