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: allows reorg detectors configure the what kind of block is a finalized block #180

Merged
2 changes: 1 addition & 1 deletion aggsender/block_notifier_polling_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ func TestNewBlockNotifierPolling(t *testing.T) {
testData := newBlockNotifierPollingTestData(t, nil)
require.NotNil(t, testData.sut)
_, err := NewBlockNotifierPolling(testData.ethClientMock, ConfigBlockNotifierPolling{
BlockFinalityType: etherman.BlockNumberFinality("invalid"),
BlockFinalityType: etherman.NewBlockNumberFinality("invalid"),
}, log.WithFields("test", "test"), nil)
require.Error(t, err)
}
Expand Down
23 changes: 10 additions & 13 deletions bridgesync/bridgesync.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ type ReorgDetector interface {

// BridgeSync manages the state of the exit tree for the bridge contract by processing Ethereum blockchain events.
type BridgeSync struct {
processor *processor
driver *sync.EVMDriver
processor *processor
driver *sync.EVMDriver
downloader *sync.EVMDownloader

originNetwork uint32
blockFinality etherman.BlockNumberFinality
reorgDetector ReorgDetector
}

// NewL1 creates a bridge syncer that synchronizes the mainnet exit tree
Expand All @@ -45,7 +46,6 @@ func NewL1(
maxRetryAttemptsAfterError int,
originNetwork uint32,
syncFullClaims bool,
finalizedBlockType etherman.BlockNumberFinality,
) (*BridgeSync, error) {
return newBridgeSync(
ctx,
Expand All @@ -62,7 +62,6 @@ func NewL1(
maxRetryAttemptsAfterError,
originNetwork,
syncFullClaims,
finalizedBlockType,
)
}

Expand All @@ -81,7 +80,6 @@ func NewL2(
maxRetryAttemptsAfterError int,
originNetwork uint32,
syncFullClaims bool,
finalizedBlockType etherman.BlockNumberFinality,
) (*BridgeSync, error) {
return newBridgeSync(
ctx,
Expand All @@ -98,7 +96,6 @@ func NewL2(
maxRetryAttemptsAfterError,
originNetwork,
syncFullClaims,
finalizedBlockType,
)
}

Expand All @@ -117,7 +114,6 @@ func newBridgeSync(
maxRetryAttemptsAfterError int,
originNetwork uint32,
syncFullClaims bool,
finalizedBlockType etherman.BlockNumberFinality,
) (*BridgeSync, error) {
logger := log.WithFields("module", syncerID)
processor, err := newProcessor(dbPath, logger)
Expand Down Expand Up @@ -156,7 +152,7 @@ func newBridgeSync(
appender,
[]common.Address{bridge},
rh,
finalizedBlockType,
rd.GetFinalizedBlock(),
)
if err != nil {
return nil, err
Expand All @@ -176,7 +172,7 @@ func newBridgeSync(
" maxRetryAttemptsAfterError: %d\n"+
" retryAfterErrorPeriod: %s\n"+
" syncBlockChunkSize: %d\n"+
" blockFinalityType: %s\n"+
" ReorgDetector: %s\n"+
" waitForNewBlocksPeriod: %s",
syncerID,
dbPath,
Expand All @@ -186,15 +182,16 @@ func newBridgeSync(
maxRetryAttemptsAfterError,
retryAfterErrorPeriod.String(),
syncBlockChunkSize,
blockFinalityType,
rd.String(),
waitForNewBlocksPeriod.String(),
)

return &BridgeSync{
processor: processor,
driver: driver,
downloader: downloader,
originNetwork: originNetwork,
blockFinality: blockFinalityType,
reorgDetector: rd,
}, nil
}

Expand Down Expand Up @@ -282,5 +279,5 @@ func (s *BridgeSync) OriginNetwork() uint32 {

// BlockFinality returns the block finality type
func (s *BridgeSync) BlockFinality() etherman.BlockNumberFinality {
return s.blockFinality
return s.reorgDetector.GetFinalizedBlock()
}
7 changes: 3 additions & 4 deletions bridgesync/bridgesync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,20 @@ func TestNewLx(t *testing.T) {
bridge := common.HexToAddress("0x1234567890abcdef1234567890abcdef12345678")
const (
syncBlockChunkSize = uint64(100)
blockFinalityType = etherman.SafeBlock
initialBlock = uint64(0)
waitForNewBlocksPeriod = time.Second * 10
retryAfterErrorPeriod = time.Second * 5
maxRetryAttemptsAfterError = 3
originNetwork = uint32(1)
)
var blockFinalityType = etherman.SafeBlock

mockEthClient := mocksbridgesync.NewEthClienter(t)
mockReorgDetector := mocksbridgesync.NewReorgDetector(t)

mockReorgDetector.EXPECT().Subscribe(mock.Anything).Return(nil, nil)

mockReorgDetector.EXPECT().GetFinalizedBlock().Return(blockFinalityType)
mockReorgDetector.EXPECT().String().Return("mockReorgDetector")
l1BridgeSync, err := NewL1(
ctx,
dbPath,
Expand All @@ -58,7 +59,6 @@ func TestNewLx(t *testing.T) {
maxRetryAttemptsAfterError,
originNetwork,
false,
blockFinalityType,
)

assert.NoError(t, err)
Expand All @@ -80,7 +80,6 @@ func TestNewLx(t *testing.T) {
maxRetryAttemptsAfterError,
originNetwork,
false,
blockFinalityType,
)

assert.NoError(t, err)
Expand Down
45 changes: 35 additions & 10 deletions bridgesync/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import (
"time"

"github.com/agglayer/aggkit/bridgesync"
"github.com/agglayer/aggkit/etherman"
"github.com/agglayer/aggkit/log"
"github.com/agglayer/aggkit/test/helpers"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient/simulated"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -56,13 +58,19 @@ func TestBridgeEventE2E(t *testing.T) {
require.NoError(t, err)
require.Equal(t, receipt.Status, types.ReceiptStatusSuccessful)
expectedBridges = append(expectedBridges, bridge)
expectedRoot, err := setup.L1Environment.BridgeContract.GetRoot(nil)
require.NoError(t, err)
finalizedBlock := GetFinalizedBlockNumber(t, ctx, setup.L1Environment.SimBackend.Client())
log.Infof("*** iteration: %d, Bridge Root: %s latestBlock:%d finalizedBlock:%d", i, common.Hash(expectedRoot).Hex(), bn, finalizedBlock)
bridgesSent++

// Trigger reorg
if i%reorgEveryXIterations == 0 {
blocksToReorg := 1 + i%maxReorgDepth
bn, err := setup.L1Environment.SimBackend.Client().BlockNumber(ctx)
require.NoError(t, err)
bn, err = setup.L1Environment.SimBackend.Client().BlockNumber(ctx)
require.NoError(t, err)
finalizedBlockNumber := GetFinalizedBlockNumber(t, ctx, setup.L1Environment.SimBackend.Client())
blocksToReorg := 1 + i%maxReorgDepth
// Trigger reorg but prevent to reorg a finalized block
if i%reorgEveryXIterations == 0 && bn-uint64(blocksToReorg) > finalizedBlockNumber {
log.Infof("*** Reorg iteration: %d, Reorging %d blocks. From block: %d to %d. finalizedBlockNumber: %d",
i, blocksToReorg, bn, bn-uint64(blocksToReorg), finalizedBlockNumber)
helpers.Reorg(t, setup.L1Environment.SimBackend, uint64(blocksToReorg))
// Clean expected bridges
lastValidBlock := bn - uint64(blocksToReorg)
Expand Down Expand Up @@ -92,21 +100,38 @@ func TestBridgeEventE2E(t *testing.T) {

// Wait for syncer to catch up
time.Sleep(time.Second * 2) // sleeping since the processor could be up to date, but have pending reorgs
lb, err := setup.L1Environment.SimBackend.Client().BlockNumber(ctx)
require.NoError(t, err)

lb := GetFinalizedBlockNumber(t, ctx, setup.L1Environment.SimBackend.Client())
helpers.RequireProcessorUpdated(t, setup.L1Environment.BridgeSync, lb)

// Get bridges
lastBlock, err := setup.L1Environment.SimBackend.Client().BlockNumber(ctx)
require.NoError(t, err)
actualBridges, err := setup.L1Environment.BridgeSync.GetBridges(ctx, 0, lastBlock)
lastProcessedBlock, err := setup.L1Environment.BridgeSync.GetLastProcessedBlock(ctx)
require.NoError(t, err)

actualBridges, err := setup.L1Environment.BridgeSync.GetBridges(ctx, 0, lastProcessedBlock)
require.NoError(t, err)
log.Infof("lastBlockOnChain:%d lastProcessedBlock: %d, len(actualBridges): %d", lb, lastProcessedBlock, len(actualBridges))
// Assert bridges
expectedRoot, err := setup.L1Environment.BridgeContract.GetRoot(nil)
require.NoError(t, err)
root, err := setup.L1Environment.BridgeSync.GetExitRootByIndex(ctx, expectedBridges[len(expectedBridges)-1].DepositCount)
require.NoError(t, err)
log.Infof("expectedRoot: %s lastBlock: %d lastFinalized:%d DepositCount:%d ", common.Hash(expectedRoot).Hex(), lastBlock, lb, expectedBridges[len(expectedBridges)-1].DepositCount)
for i := 119; i >= 00; i-- {
root, err := setup.L1Environment.BridgeSync.GetExitRootByIndex(ctx, uint32(i))
require.NoError(t, err)
log.Infof("DepositCount:%d root: %s", i, root.Hash.Hex())
}
require.Equal(t, common.Hash(expectedRoot).Hex(), root.Hash.Hex())
require.Equal(t, expectedBridges, actualBridges)
}

func GetFinalizedBlockNumber(t *testing.T, ctx context.Context, client simulated.Client) uint64 {
joanestebanr marked this conversation as resolved.
Show resolved Hide resolved
t.Helper()
lastBlockFinalityType, err := etherman.FinalizedBlock.ToBlockNum()
require.NoError(t, err)
lastBlockHeader, err := client.HeaderByNumber(ctx, lastBlockFinalityType)
require.NoError(t, err)
return lastBlockHeader.Number.Uint64()
}
92 changes: 92 additions & 0 deletions bridgesync/mocks/mock_reorg_detector.go

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

Loading
Loading