Skip to content

Commit

Permalink
feat: add block timestamp to eth_getLogs (#2374)
Browse files Browse the repository at this point in the history
## What ❔

Add a new field `blockTimestamp` to the `eth_getLogs` endpoint. 

## Why ❔

That'd allow network indexers to avoid sending a second requests just to
get timestamp for each block. More
[info](https://ethereum-magicians.org/t/proposal-for-adding-blocktimestamp-to-logs-object-returned-by-eth-getlogs-and-related-requests/11183)
  • Loading branch information
ischasny authored Jul 8, 2024
1 parent e652e4d commit 50422b8
Show file tree
Hide file tree
Showing 15 changed files with 84 additions and 18 deletions.
3 changes: 3 additions & 0 deletions core/lib/basic_types/src/web3/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,9 @@ pub struct Log {
pub log_type: Option<String>,
/// Removed
pub removed: Option<bool>,
/// L2 block timestamp
#[serde(rename = "blockTimestamp")]
pub block_timestamp: Option<i64>,
}

impl Log {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion core/lib/dal/src/events_dal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,8 @@ impl EventsDal<'_, '_> {
tx_hash,
tx_index_in_block,
event_index_in_block,
event_index_in_tx
event_index_in_tx,
NULL::BIGINT AS "block_timestamp?"
FROM
events
WHERE
Expand Down
6 changes: 4 additions & 2 deletions core/lib/dal/src/events_web3_dal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ impl EventsWeb3Dal<'_, '_> {
ORDER BY miniblock_number ASC, event_index_in_block ASC
LIMIT ${}
)
SELECT miniblocks.hash as "block_hash", miniblocks.l1_batch_number as "l1_batch_number", events_select.*
SELECT miniblocks.hash as "block_hash", miniblocks.l1_batch_number as "l1_batch_number",
miniblocks.timestamp as block_timestamp, events_select.*
FROM events_select
INNER JOIN miniblocks ON events_select.miniblock_number = miniblocks.number
ORDER BY miniblock_number ASC, event_index_in_block ASC
Expand Down Expand Up @@ -222,7 +223,8 @@ impl EventsWeb3Dal<'_, '_> {
tx_hash AS "tx_hash!",
tx_index_in_block AS "tx_index_in_block!",
event_index_in_block AS "event_index_in_block!",
event_index_in_tx AS "event_index_in_tx!"
event_index_in_tx AS "event_index_in_tx!",
miniblocks.timestamp AS "block_timestamp"
FROM
events_select
INNER JOIN miniblocks ON events_select.miniblock_number = miniblocks.number
Expand Down
2 changes: 2 additions & 0 deletions core/lib/dal/src/models/storage_event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub struct StorageWeb3Log {
pub tx_index_in_block: i32,
pub event_index_in_block: i32,
pub event_index_in_tx: i32,
pub block_timestamp: Option<i64>,
}

impl From<StorageWeb3Log> for api::Log {
Expand Down Expand Up @@ -47,6 +48,7 @@ impl From<StorageWeb3Log> for api::Log {
transaction_log_index: Some(U256::from(log.event_index_in_tx as u32)),
log_type: None,
removed: Some(false),
block_timestamp: log.block_timestamp,
}
}
}
Expand Down
1 change: 1 addition & 0 deletions core/lib/dal/src/models/storage_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ pub(crate) struct StorageTransactionReceipt {
pub effective_gas_price: Option<BigDecimal>,
pub contract_address: Option<Vec<u8>>,
pub initiator_address: Vec<u8>,
pub block_timestamp: Option<i64>,
}

impl From<StorageTransactionReceipt> for TransactionReceipt {
Expand Down
19 changes: 12 additions & 7 deletions core/lib/dal/src/transactions_web3_dal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ impl TransactionsWeb3Dal<'_, '_> {
// Clarification for first part of the query(`WITH` clause):
// Looking for `ContractDeployed` event in the events table
// to find the address of deployed contract
let mut receipts: Vec<TransactionReceipt> = sqlx::query_as!(
let st_receipts: Vec<StorageTransactionReceipt> = sqlx::query_as!(
StorageTransactionReceipt,
r#"
WITH
Expand Down Expand Up @@ -75,7 +75,8 @@ impl TransactionsWeb3Dal<'_, '_> {
transactions.gas_limit AS gas_limit,
miniblocks.hash AS "block_hash",
miniblocks.l1_batch_number AS "l1_batch_number?",
events.topic4 AS "contract_address?"
events.topic4 AS "contract_address?",
miniblocks.timestamp AS "block_timestamp?"
FROM
transactions
JOIN miniblocks ON miniblocks.number = transactions.miniblock_number
Expand All @@ -93,10 +94,13 @@ impl TransactionsWeb3Dal<'_, '_> {
.instrument("get_transaction_receipts")
.with_arg("hashes.len", &hashes.len())
.fetch_all(self.storage)
.await?
.into_iter()
.map(Into::into)
.collect();
.await?;

let block_timestamps: Vec<Option<i64>> =
st_receipts.iter().map(|x| x.block_timestamp).collect();

let mut receipts: Vec<TransactionReceipt> =
st_receipts.into_iter().map(Into::into).collect();

let mut logs = self
.storage
Expand All @@ -110,7 +114,7 @@ impl TransactionsWeb3Dal<'_, '_> {
.get_l2_to_l1_logs_by_hashes(hashes)
.await?;

for receipt in &mut receipts {
for (receipt, block_timestamp) in receipts.iter_mut().zip(block_timestamps.into_iter()) {
let logs_for_tx = logs.remove(&receipt.transaction_hash);

if let Some(logs) = logs_for_tx {
Expand All @@ -119,6 +123,7 @@ impl TransactionsWeb3Dal<'_, '_> {
.map(|mut log| {
log.block_hash = Some(receipt.block_hash);
log.l1_batch_number = receipt.l1_batch_number;
log.block_timestamp = block_timestamp;
log
})
.collect();
Expand Down
3 changes: 3 additions & 0 deletions core/lib/types/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,9 @@ pub struct Log {
pub log_type: Option<String>,
/// Removed
pub removed: Option<bool>,
/// L2 block timestamp
#[serde(rename = "blockTimestamp")]
pub block_timestamp: Option<i64>,
}

impl Log {
Expand Down
1 change: 1 addition & 0 deletions core/lib/types/src/event/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ impl From<&VmEvent> for Log {
transaction_log_index: None,
log_type: None,
removed: Some(false),
block_timestamp: None,
}
}
}
Expand Down
1 change: 1 addition & 0 deletions core/lib/types/src/protocol_upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,7 @@ mod tests {
transaction_log_index: Default::default(),
log_type: Default::default(),
removed: Default::default(),
block_timestamp: Default::default(),
};
let decoded_op: GovernanceOperation = correct_log.clone().try_into().unwrap();
assert_eq!(decoded_op.calls.len(), 1);
Expand Down
1 change: 1 addition & 0 deletions core/node/consistency_checker/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ fn l1_batch_commit_log(l1_batch: &L1BatchWithMetadata) -> Log {
transaction_log_index: None,
log_type: Some("mined".into()),
removed: None,
block_timestamp: None,
}
}

Expand Down
2 changes: 2 additions & 0 deletions core/node/eth_watch/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,7 @@ fn tx_into_log(tx: L1Tx) -> Log {
transaction_log_index: Some(0u64.into()),
log_type: None,
removed: None,
block_timestamp: None,
}
}

Expand Down Expand Up @@ -549,6 +550,7 @@ fn upgrade_into_governor_log(upgrade: ProtocolUpgrade, eth_block: u64) -> Log {
transaction_log_index: Some(0u64.into()),
log_type: None,
removed: None,
block_timestamp: None,
}
}

Expand Down
26 changes: 26 additions & 0 deletions core/tests/ts-integration/tests/api/web3.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,32 @@ describe('web3 API compatibility tests', () => {
expect(logs[0].transactionHash).toEqual(tx.hash);
});

test('Should check getLogs returns block_timestamp', async () => {
// We're sending a transfer from the wallet, so we'll use a new account to make event unique.
let uniqueRecipient = testMaster.newEmptyAccount().address;
const tx = await alice.transfer({
to: uniqueRecipient,
amount: 1,
token: l2Token
});
const receipt = await tx.wait();
const response = await alice.provider.send('eth_getLogs', [
{
fromBlock: ethers.toBeHex(receipt.blockNumber),
toBlock: ethers.toBeHex(receipt.blockNumber),
address: l2Token,
topics: [
'0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
ethers.zeroPadValue(alice.address, 32),
ethers.zeroPadValue(uniqueRecipient, 32)
]
}
]);
expect(response).toHaveLength(1);
// TODO: switch to provider.getLogs once blockTimestamp is added to zksync ethers.js
expect(response[0].blockTimestamp).toBeDefined();
});

test('Should check getLogs endpoint works properly with block tags', async () => {
const earliestLogs = alice.provider.send('eth_getLogs', [
{
Expand Down

0 comments on commit 50422b8

Please sign in to comment.