Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate RPC log/callTrace response #1152

Merged

Conversation

khaidarkairbek
Copy link
Contributor

Added a check to validate whether filtered logs and calltraces point to valid transactions in the block for realtime-sync engine. Relates to #1150 issue.

@khaidarkairbek
Copy link
Contributor Author

@kyscott18 Added a check after filtering transactions, was wondering if this would be sufficient for realtime-sync

Comment on lines 502 to 504
throw new Error(
`Received callTrace/log in the block referencing transaction that is not in current head block '${block.hash}'`,
);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not blocking, but I'd advocate for a more specific error message which includes the suspicious transaction hashes. That would make it much easier for us to submit bug reports to chains / RPC providers.

Also, what if the lengths are different because we have an extra required transaction? That scenario would suggest a Ponder bug rather than a faulty RPC.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. With regards to error message, do you think it would be better to include the list of suspicious tx hashes in the message?
  2. We would expect requiredTransactions size to be larger than transactions length only in the case if some logs or callTraces that is matched with filter are pointing to more transactions, than there are transactions filtered by those logs/traces.
    const transactions = block.transactions.filter(({ hash }) => requiredTransactions.has(hash), );

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. yes
  2. I think the transaction validation should be more precise. Something like:
const blockTransactionsHashes = new Set(
  block.transactions.map((t) => t.hash),
);
for (const hash of Array.from(requiredTransactions)) {
  if (blockTransactionsHashes.has(hash) === false) {
    // throw error, include `hash`
  }
}

I also think it would be nice to have something that compares blockHash in logs and callTraces to block.hash

@khaidarkairbek
Copy link
Contributor Author

khaidarkairbek commented Oct 10, 2024

@kyscott18 @0xOlias I have added the validation checks in sync-realtime for logs response:

  • log.transactionHash in block.transactions
  • log.blockHash === block.hash
    and for callTraces response:
  • trace.transactionHash in block.transactions
  • trace.blockHash === block.hash (already existed)

Similarly, for sync-historical I have added the following checks:

  • log.transactionHash in block.transactions
  • trace.transactionHash in block.transactions
  • log.blockHash === fetchedBlock.hash
  • trace.blockHash === fetchedBlock.hash

@khaidarkairbek khaidarkairbek marked this pull request as draft October 10, 2024 17:19
@khaidarkairbek khaidarkairbek marked this pull request as ready for review October 10, 2024 18:28
@kyscott18 kyscott18 linked an issue Oct 11, 2024 that may be closed by this pull request
Copy link
Collaborator

@kyscott18 kyscott18 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking great! Gonna do a commit or two and then I think we can get this out

);

// Validate that traces point to the valid transaction hash in the block and collect them
const transactionHashes = new Set(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to move this outside of the Set constructor, so it's not doing two things at once

@@ -393,6 +393,15 @@ export const createRealtimeSync = (
`Detected invalid '${args.network.name}' eth_getLogs response.`,
);
}

// Check that logs refer to the correct block
for (const log of logs) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great

(t) => t.hash === transactionHash,
);
if (!isTransactionValid) {
throw new Error(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add something to catch this error and make sure it is getting logged properly

Copy link
Collaborator

@0xOlias 0xOlias left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great. Unfortunately, I bet we're going to start getting bug reports including these error messages.

@@ -485,9 +485,18 @@ export const createRealtimeSync = (
// Protect against RPCs returning empty logs. Known to happen near chain tip.
if (block.logsBloom !== zeroLogsBloom && logs.length === 0) {
throw new Error(
`Detected invalid '${args.network.name}' eth_getLogs response.`,
"Detected invalid eth_getLogs response. `block.logsBloom` is not empty but zero logs were returned.",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great error message

@kyscott18 kyscott18 merged commit d436bdb into ponder-sh:main Oct 11, 2024
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Validate rpc response consistency
3 participants