-
Notifications
You must be signed in to change notification settings - Fork 11
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
refactor(execution_deposits_exporter): export deposits up to head and… #939
Conversation
guybrush
commented
Oct 10, 2024
•
edited
Loading
edited
ab6ecb3
to
0575c81
Compare
var nearestELBlock sql.NullInt64 | ||
err = db.ReaderDb.Get(&nearestELBlock, "select exec_block_number from blocks where slot <= $1 and exec_block_number > 0 order by slot desc limit 1", res.Data.Finalized.Epoch*utils.Config.Chain.ClConfig.SlotsPerEpoch) | ||
err = db.ReaderDb.Get(&nearestELBlock, "select exec_block_number from blocks where exec_block_number > 0 order by slot desc limit 1") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is really meh. it made a bit more sense when we were following the finalized checkpoints (we had to resolve the slot to a exec block somehow) but even that wasnt that clean (you can resolve slot => exec block num using /eth/v2/beacon/blocks/{block_id}
data.message.body.execution_payload.block_number
)
i would rather
- listen to block events from erigon by adding a new
OnExecutionHead
listener to the modular exporter system - resolve the slot to a exec block num using the beacon api as described above
- do this query in the actual exporting loop below (makes no difference doing it here or there, besides having to store it variable when doing the former), though I'm not a big fan of having exporters depend on other exporters because this makes locating issues hard and can cause compounding delays.
e33d9ac
to
cab4d83
Compare
Deploying beaconchain with Cloudflare Pages
|
7af102c
to
99acbd5
Compare
* export deposits up to head * handle reorgs by reexporting blocks since lastExportedFinalizedBlock * persist lastExportedFinalizedBlock in redis * refactor export-logic from multiple event-based goroutines with canceling to single loop * aggregated deposits and cached view are only updated when export is on head * avoid fetching old blocks if no deposits are on the chain * avoid duplicate work by caching exported tx-hashes BEDS-585
99acbd5
to
b5099bf
Compare
if d.exportedTxsCache.Contains(fmt.Sprintf("%x", depositLog.Raw.TxHash.Bytes())) { | ||
log.Debugf("skipping already exported deposit-tx: block: %d, tx: %x", depositLog.Raw.BlockNumber, depositLog.Raw.TxHash.Bytes()) | ||
continue | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is wrong and very dangerous. i meant only caching the validity of the signature, not skipping seen txns
the current solution can result in the following issue:
- there are 3 deposit txns on chain, each with one deposit:
txnA:0
,txnB:1
,txnC:2
(:n
is the merkle tree index)txnA:0
,txnB:1
,txnC:2
gets pushed to the db
- the chain gets reorged and a new txn (
txnD
) with 1 deposit get inserted aftertxnA
- there are now 4 deposits on chain:
txnA:0
,txnD:1
,txnB:2
,txnC:3
- the lru cache skips the re-processing of txnB & txnC
txnD:1
gets pushed to the db
- there are now 4 deposits on chain:
- a new txn with a single deposit gets added (
txnE
)txnE:4
gets pushed to the db
the result db state would be
txnA:0
,txnD:1
,txnC:2
,txnE:4
instead of
txnA:0
,txnD:1
,txnB:2
,txnC:3
,txnE:4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed cache
g.Go(func() error { | ||
headSlot, err := d.CL.GetSlot("head") | ||
if err != nil { | ||
return fmt.Errorf("error getting head-slot: %w", err) | ||
} | ||
headBlock = headSlot.Data.Message.Body.ExecutionPayload.BlockNumber | ||
return nil | ||
}) | ||
g.Go(func() error { | ||
finSlot, err := d.CL.GetSlot("finalized") | ||
if err != nil { | ||
return fmt.Errorf("error getting finalized-slot: %w", err) | ||
} | ||
finBlock = finSlot.Data.Message.Body.ExecutionPayload.BlockNumber | ||
return nil | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this could be done in onHead
& onFinalizedCheckpoint
to follow the event driven approach
but since export()
is in a fixed loop i would not bother with it rn since it would yield no benefit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm