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

feat: update tryFinalize() to check finality on each L2 block #23

Merged
merged 19 commits into from
Jul 26, 2024

Conversation

lesterli
Copy link
Collaborator

@lesterli lesterli commented Jul 12, 2024

Summary

This PR updates finalizer.go to check finality on each L2 block, tryFinalize() doesn't call on each L2 block b/c onPendingSafeUpdate only triggered upon a new L1 block.

  • add an FinalizerL2Interface interface which has the function L2BlockRefByNumber(ctx context.Context, num uint64) (eth.L2BlockRef, error)
  • update the function NewFinalizer to add this interface as its input parameter
  • update all the codes that call the function NewFinalizer and pass an instance of the FinalizerL2Interface interface

Test Plan

make lint-go
make build-go
cd op-node && make test

connect w FP e2e tests locally and see it passed

    op_test_manager.go:354: [17:55:15.448] Registered Finality Provider cceb4691002c79802720f1adb9573d66e44c18edcad2b26e59b80750eb14e2e8 for op-stack-l2-901
    base_test_manager.go:174: successfully submitted a BTC delegation
    base_test_manager.go:207: delegations are pending
    base_test_manager.go:227: delegations are active
    op_test_manager.go:430: [17:55:36.294] The test manager is running with 1 finality-provider(s)
    utils.go:100: Public randomness for fp cceb4691002c79802720f1adb9573d66e44c18edcad2b26e59b80750eb14e2e8 is successfully committed at height 64
    op_e2e_test.go:172: [17:56:31.538] Stopped the FP instance
    op_e2e_test.go:176: [17:56:31.538] last processed height 56
    op_e2e_test.go:189: [17:56:43.065] Test case 1: OP chain block finalized stuck at height 56
    op_e2e_test.go:198: [17:57:12.090] Restarted the FP instance
    op_e2e_test.go:202: [17:57:22.093] Test case 2: OP chain finality is recover, the latest finalized block height 95
    op_test_manager.go:480: Stopping test manager
--- PASS: TestFinalityStuckAndRecover (193.73s)
PASS
ok  	github.com/babylonchain/finality-provider/itest/opstackl2	201.464s

@lesterli lesterli marked this pull request as draft July 12, 2024 01:54
@lesterli lesterli marked this pull request as ready for review July 16, 2024 15:08
@lesterli lesterli marked this pull request as draft July 16, 2024 15:10
op-node/rollup/finality/finalizer.go Outdated Show resolved Hide resolved
op-node/rollup/finality/finalizer.go Outdated Show resolved Hide resolved
op-node/rollup/finality/finalizer.go Outdated Show resolved Hide resolved
op-node/rollup/finality/finalizer.go Outdated Show resolved Hide resolved
op-node/rollup/finality/finalizer.go Outdated Show resolved Hide resolved
@bap2pecs bap2pecs marked this pull request as ready for review July 16, 2024 18:42
@bap2pecs
Copy link
Collaborator

updated to fix all comments ^

@bap2pecs
Copy link
Collaborator

@lesterli let's make sure we run all the commands in test plan since we have disabled CI for now.

I just found that cd op-node && make test fails

go.mod Outdated Show resolved Hide resolved
op-node/rollup/finality/finalizer_test.go Outdated Show resolved Hide resolved
op-node/rollup/finality/finalizer.go Outdated Show resolved Hide resolved
op-node/rollup/finality/finalizer.go Outdated Show resolved Hide resolved
op-node/rollup/finality/finalizer.go Outdated Show resolved Hide resolved
@lesterli lesterli requested a review from bap2pecs July 26, 2024 11:30
Comment on lines 248 to 249
lastFinalizedBlock, err := fi.findFinalizedL2Block(fd.L2Block.Number, finalizedL2.Number)
if err != nil {
Copy link
Collaborator

@bap2pecs bap2pecs Jul 26, 2024

Choose a reason for hiding this comment

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

this confused me a bit b/c when there is err but we don't log it here. only after digging into the code, I see that it's already emitted inside findFinalizedL2Block

so given that we only need to check "where there is error", a better API design is to return a bool hasErr. wdyt?

Copy link
Collaborator

@bap2pecs bap2pecs Jul 26, 2024

Choose a reason for hiding this comment

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

also findFinalizedL2Block should be renamed to sth like findLastFinalizedL2BlockWithConsecutiveQuorom

Copy link
Collaborator

Choose a reason for hiding this comment

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

fixed in 38f6625

if err != nil {
if lastFinalizedBlock != (eth.L2BlockRef{}) {
// set finalized block(s)
finalizedL2, finalizedDerivedFrom = fi.updateFinalized(lastFinalizedBlock, fd.L1Block)
Copy link
Collaborator

Choose a reason for hiding this comment

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

should we use lastFinalizedBlock.L1Origin here instead of fd.L1Block?

b/c lastFinalizedBlock might not be the same as fd.L2Block.Number

Copy link
Collaborator

@bap2pecs bap2pecs Jul 26, 2024

Choose a reason for hiding this comment

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

this is probably another edge case that test coverage failed. we should have a test case for this where fd.L1Block is different from lastFinalizedBlock.L1Origin

Copy link
Collaborator

Choose a reason for hiding this comment

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

fixed in 38f6625

break
}
// set finalized block(s)
finalizedL2, finalizedDerivedFrom = fi.updateFinalized(lastFinalizedBlock, fd.L1Block)
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 the same call as in L252. i think the overall logic from line 249-264 is not very clean

Copy link
Collaborator

Choose a reason for hiding this comment

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

same for the if lastFinalizedBlock == (eth.L2BlockRef{}) { check. we checked it twice

Copy link
Collaborator

Choose a reason for hiding this comment

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

we can do sth like this:

image

so we only need to call updateFinalized once; and check lastFinalizedBlock != (eth.L2BlockRef{}) once

Copy link
Collaborator

Choose a reason for hiding this comment

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

fixed in 38f6625

if err != nil && !errors.Is(err, sdk.ErrNoFpHasVotingPower) {
fi.emitter.Emit(rollup.CriticalErrorEvent{Err: fmt.Errorf("failed to check if block %d is finalized on Babylon: %w", fd.L2Block.Number, err)})

if hasErr {
return
Copy link
Collaborator

Choose a reason for hiding this comment

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

thinking deeper on it. "return on err" is inappropriate now. if you see the below logic where if finalizedDerivedFrom != (eth.BlockID{}) { is checked, whenever finalizedDerivedFrom is set, we have to do some sanity checks.

so we need to:

  • remove the "return on error" logic
  • findLastFinalizedL2BlockWithConsecutiveQuorom doesn't need to return hasErr now

Copy link
Collaborator

Choose a reason for hiding this comment

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

fixed in b28870d

@@ -300,6 +292,80 @@ func (fi *Finalizer) tryFinalize() {
}
}

/*
* findLastFinalizedL2BlockWithConsecutiveQuorom tries to find the finalized L2 block.
Copy link
Collaborator

Choose a reason for hiding this comment

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

tries to find the last finalized L2 block with consecutive quorom

Copy link
Collaborator

Choose a reason for hiding this comment

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

fixed in c89dd55

Comment on lines 303 to 307
* for any other error types, emit an critical error event.
*/
func (fi *Finalizer) findLastFinalizedL2BlockWithConsecutiveQuorom(
fdL2BlockNumber uint64,
finalizedL2Number uint64,
Copy link
Collaborator

Choose a reason for hiding this comment

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

let's add some comments to explain the return value and those arguments

Copy link
Collaborator

Choose a reason for hiding this comment

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

fixed in c89dd55

return eth.L2BlockRef{}
}

return l2Blocks[*lastFinalizedBlockNumber]
Copy link
Collaborator

Choose a reason for hiding this comment

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

what if lastFinalizedBlockNumber is nil?

Copy link
Collaborator

Choose a reason for hiding this comment

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

fixed in c89dd55

func (fi *Finalizer) findLastFinalizedL2BlockWithConsecutiveQuorom(
fdL2BlockNumber uint64,
finalizedL2Number uint64,
) eth.L2BlockRef {
Copy link
Collaborator

Choose a reason for hiding this comment

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

why not return a pointer?

i think using a pointer type will be cleaner so the check above

if lastFinalizedBlock.Number != fd.L2Block.Number {

will be changed to

if lastFinalizedBlock == nil || lastFinalizedBlock.Number != fd.L2Block.Number {

so it's more explicit

Copy link
Collaborator

Choose a reason for hiding this comment

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

fixed in c89dd55

// https://github.com/babylonchain/babylon-finality-gadget/issues/59
if err != nil && !errors.Is(err, sdkclient.ErrNoFpHasVotingPower) {
if lastFinalizedBlockNumber != nil {
fi.log.Warn("Received error but also had the finalized block", "error", err, "blockNumber", *lastFinalizedBlockNumber)
Copy link
Collaborator

Choose a reason for hiding this comment

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

the logic here is not clean for the same reason that we have too many unnecessary nesting and condition checks

it can be simplified to be:

  • if there is error, emit
  • if last finalized block is not nil, return the block
  • else return nil

Copy link
Collaborator

Choose a reason for hiding this comment

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

fixed in c89dd55

Copy link
Collaborator

@bap2pecs bap2pecs left a comment

Choose a reason for hiding this comment

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

given that this PR is already way too big. let's move all the changes in finalizer_test.go to another PR so we can start new discussion threads there

also the tests seem still failing

Copy link
Collaborator

@bap2pecs bap2pecs left a comment

Choose a reason for hiding this comment

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

ok I fixed all the comments above. @lesterli you can create a new PR to fix test. it's currently failing. I copied the code of finalizer_test.go to https://gist.github.com/bap2pecs/65e97276d3253e3973f138ab84878e74

I am gonna merge this PR now. I tested against FP e2e tests and all passed

let's keep the branch for now since I don't know if FP or SDK repo depends on some commits in this branch

@bap2pecs bap2pecs merged commit 8d9427b into feat/babylon-rfc Jul 26, 2024
1 check failed
@bap2pecs bap2pecs deleted the feat/check-each-l2-block branch July 26, 2024 23:56
@bap2pecs bap2pecs restored the feat/check-each-l2-block branch July 26, 2024 23:57
@bap2pecs bap2pecs mentioned this pull request Jul 27, 2024
5 tasks
@lesterli lesterli mentioned this pull request Jul 29, 2024
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.

3 participants