Skip to content

Commit 3d9814f

Browse files
remove bridges and leafs from exit tree, and then restore only the subset of bridges that were not removed by reorg
1 parent b093169 commit 3d9814f

File tree

2 files changed

+136
-85
lines changed

2 files changed

+136
-85
lines changed

bridgesync/processor.go

Lines changed: 108 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ var (
125125
type BridgeSource string
126126

127127
const (
128-
BridgeSourceBackwardLET BridgeSource = "backward_let"
129-
BridgeSourceForwardLET BridgeSource = "forward_let"
128+
BridgeSourceRestoredBackwardLET BridgeSource = "restored_backward_let"
129+
BridgeSourceForwardLET BridgeSource = "forward_let"
130130
)
131131

132132
// Bridge is the representation of a bridge event
@@ -1249,8 +1249,14 @@ func (p *processor) Reorg(ctx context.Context, firstReorgedBlock uint64) error {
12491249
}()
12501250

12511251
// ---------------------------------------------------------------------
1252-
// 1. Load affected BackwardLETs BEFORE deleting blocks, bridges and BackwardLET entries
1252+
// 1. Load affected deposit counts and BackwardLETs BEFORE deleting blocks, bridges and BackwardLET entries
12531253
// ---------------------------------------------------------------------
1254+
depositCountsToRemove, err := loadReorgedDepositCounts(tx, firstReorgedBlock)
1255+
if err != nil {
1256+
p.log.Errorf("failed to retrieve reorged bridges: %v", err)
1257+
return err
1258+
}
1259+
12541260
backwardLETsQuery := `
12551261
SELECT previous_deposit_count, new_deposit_count
12561262
FROM backward_let
@@ -1260,84 +1266,10 @@ func (p *processor) Reorg(ctx context.Context, firstReorgedBlock uint64) error {
12601266
return fmt.Errorf("failed to retrieve the affected backward LETs: %w", err)
12611267
}
12621268

1263-
// ---------------------------------------------------------------------
1264-
// 2. Restore bridge rows from archive for each interval
1265-
// ---------------------------------------------------------------------
1266-
restoredBridgesQuery := `SELECT * FROM bridge
1267-
WHERE deposit_count > $1 AND deposit_count <= $2
1268-
ORDER BY deposit_count ASC;`
1269-
bridgeRestorationSQL := `
1270-
INSERT INTO bridge (
1271-
block_num, block_pos, leaf_type, origin_network, origin_address,
1272-
destination_network, destination_address, amount, metadata,
1273-
tx_hash, block_timestamp, txn_sender, deposit_count, from_address, source, to_address
1274-
)
1275-
SELECT
1276-
block_num, block_pos, leaf_type, origin_network, origin_address,
1277-
destination_network, destination_address, amount, metadata,
1278-
tx_hash, block_timestamp, txn_sender, deposit_count, from_address, $1, to_address
1279-
FROM bridge_archive
1280-
WHERE deposit_count > $2 AND deposit_count <= $3
1281-
ORDER BY deposit_count ASC;
1282-
`
1283-
for _, backwardLET := range backwardLETs {
1284-
prevDepositCount, err := aggkitcommon.SafeUint64(backwardLET.PreviousDepositCount)
1285-
if err != nil {
1286-
return fmt.Errorf("invalid previous deposit count %s: %w", backwardLET.PreviousDepositCount, err)
1287-
}
1288-
1289-
newDepositCount, err := aggkitcommon.SafeUint64(backwardLET.NewDepositCount)
1290-
if err != nil {
1291-
return fmt.Errorf("invalid new deposit count %s: %w", backwardLET.NewDepositCount, err)
1292-
}
1293-
1294-
if _, err := tx.Exec(bridgeRestorationSQL, BridgeSourceBackwardLET, newDepositCount, prevDepositCount); err != nil {
1295-
return fmt.Errorf("failed to restore bridges from bridge archive (deposit counts range: %d..%d): %w",
1296-
newDepositCount, prevDepositCount, err)
1297-
}
1298-
1299-
// ---------------------------------------------------------------------
1300-
// 3. Restore bridges in the exit tree
1301-
// ---------------------------------------------------------------------
1302-
var restoredBridges []*Bridge
1303-
err = meddler.QueryAll(tx, &restoredBridges, restoredBridgesQuery, newDepositCount, prevDepositCount)
1304-
if err != nil {
1305-
return fmt.Errorf("failed to retrieve the restored bridges (deposit counts range: %d..%d): %w",
1306-
newDepositCount, prevDepositCount, err)
1307-
}
1308-
1309-
restoredDepositCounts := make([]uint32, 0, len(restoredBridges))
1310-
for _, restoredBridge := range restoredBridges {
1311-
if p.log.IsEnabledLogLevel(zapcore.DebugLevel) {
1312-
restoredDepositCounts = append(restoredDepositCounts, restoredBridge.DepositCount)
1313-
}
1314-
1315-
if _, err = p.exitTree.PutLeaf(tx, restoredBridge.BlockNum, restoredBridge.BlockPos,
1316-
types.Leaf{
1317-
Index: restoredBridge.DepositCount,
1318-
Hash: restoredBridge.Hash(),
1319-
}); err != nil {
1320-
if errors.Is(err, tree.ErrInvalidIndex) {
1321-
p.halt(fmt.Sprintf("error adding leaf to the exit tree: %v", err))
1322-
}
1323-
return sync.ErrInconsistentState
1324-
}
1325-
}
1326-
1327-
p.log.Debugf("restored bridges with deposit counts: %v", restoredDepositCounts)
1328-
1329-
// ---------------------------------------------------------------------
1330-
// 4. Remove restored bridges from the bridge_archive table
1331-
// ---------------------------------------------------------------------
1332-
_, err = tx.Exec(`DELETE FROM bridge_archive WHERE deposit_count > $1 AND deposit_count <= $2`,
1333-
newDepositCount, prevDepositCount)
1334-
if err != nil {
1335-
return fmt.Errorf("failed to delete restored rows from archive (range %d..%d): %w",
1336-
newDepositCount, prevDepositCount, err)
1337-
}
1338-
}
1339-
1340-
blocksRes, err := tx.Exec(`DELETE FROM block WHERE num >= $1;`, firstReorgedBlock)
1269+
// ---------------------------------------------------------
1270+
// 2. Delete blocks (cascade delete everything else)
1271+
// ---------------------------------------------------------
1272+
blocksRes, err := tx.Exec(`DELETE FROM block WHERE num >= $1`, firstReorgedBlock)
13411273
if err != nil {
13421274
p.log.Errorf("failed to delete blocks during reorg: %v", err)
13431275
return err
@@ -1349,11 +1281,22 @@ func (p *processor) Reorg(ctx context.Context, firstReorgedBlock uint64) error {
13491281
return err
13501282
}
13511283

1352-
if err = p.exitTree.Reorg(tx, firstReorgedBlock); err != nil {
1284+
// ---------------------------------------------------------
1285+
// 3. Reorg exit tree to clean state
1286+
// ---------------------------------------------------------
1287+
if err := p.exitTree.Reorg(tx, firstReorgedBlock); err != nil {
13531288
p.log.Errorf("failed to reorg exit tree: %v", err)
13541289
return err
13551290
}
13561291

1292+
// ---------------------------------------------------------
1293+
// 4. Restore bridges removed by BackwardLET
1294+
// ---------------------------------------------------------
1295+
err = p.restoreBackwardLETBridges(tx, backwardLETs, depositCountsToRemove)
1296+
if err != nil {
1297+
return err
1298+
}
1299+
13571300
if err = tx.Commit(); err != nil {
13581301
p.log.Errorf("failed to commit reorg transaction: %v", err)
13591302
return err
@@ -1370,6 +1313,89 @@ func (p *processor) Reorg(ctx context.Context, firstReorgedBlock uint64) error {
13701313
return nil
13711314
}
13721315

1316+
// restoreBackwardLETBridges restores bridges that were previously removed by BackwardLET events
1317+
func (p *processor) restoreBackwardLETBridges(tx dbtypes.Txer, backwardLETs []*BackwardLET,
1318+
reorgedDepositCounts map[uint32]struct{}) error {
1319+
restoreQuery := `
1320+
SELECT *
1321+
FROM bridge_archive
1322+
WHERE deposit_count > $1 AND deposit_count <= $2
1323+
ORDER BY deposit_count ASC
1324+
`
1325+
1326+
for _, backwardLET := range backwardLETs {
1327+
prev, err := aggkitcommon.SafeUint64(backwardLET.PreviousDepositCount)
1328+
if err != nil {
1329+
return fmt.Errorf("invalid previous deposit count: %w", err)
1330+
}
1331+
1332+
next, err := aggkitcommon.SafeUint64(backwardLET.NewDepositCount)
1333+
if err != nil {
1334+
return fmt.Errorf("invalid new deposit count: %w", err)
1335+
}
1336+
1337+
var bridges []*Bridge
1338+
if err := meddler.QueryAll(tx, &bridges, restoreQuery, next, prev); err != nil {
1339+
return err
1340+
}
1341+
1342+
for _, b := range bridges {
1343+
if _, ok := reorgedDepositCounts[b.DepositCount]; ok {
1344+
// skip cascade-deleted bridges (prevent from restoring them)
1345+
continue
1346+
}
1347+
1348+
// tag the bridge as restored by reorged BackwardLET event
1349+
b.Source = BridgeSourceRestoredBackwardLET
1350+
if err := meddler.Insert(tx, bridgeTableName, b); err != nil {
1351+
return err
1352+
}
1353+
1354+
leaf := types.Leaf{
1355+
Index: b.DepositCount,
1356+
Hash: b.Hash(),
1357+
}
1358+
if _, err := p.exitTree.PutLeaf(tx, b.BlockNum, b.BlockPos, leaf); err != nil {
1359+
return err
1360+
}
1361+
}
1362+
1363+
// cleanup bridge_archive
1364+
if _, err := tx.Exec(`
1365+
DELETE FROM bridge_archive
1366+
WHERE deposit_count > $1 AND deposit_count <= $2
1367+
`, next, prev); err != nil {
1368+
return err
1369+
}
1370+
}
1371+
1372+
return nil
1373+
}
1374+
1375+
// loadReorgedDepositCounts retrieves the bridges that are going to be deleted by the reorg,
1376+
// and returns its deposit counts
1377+
func loadReorgedDepositCounts(tx dbtypes.Txer, fromBlock uint64) (map[uint32]struct{}, error) {
1378+
rows, err := tx.Query(`
1379+
SELECT deposit_count
1380+
FROM bridge_archive
1381+
WHERE block_num >= $1
1382+
`, fromBlock)
1383+
if err != nil {
1384+
return nil, err
1385+
}
1386+
defer rows.Close()
1387+
1388+
result := make(map[uint32]struct{})
1389+
for rows.Next() {
1390+
var dc uint32
1391+
if err := rows.Scan(&dc); err != nil {
1392+
return nil, err
1393+
}
1394+
result[dc] = struct{}{}
1395+
}
1396+
return result, nil
1397+
}
1398+
13731399
// ProcessBlock process the events of the block to build the exit tree
13741400
// and updates the last processed block (can be called without events for that purpose)
13751401
func (p *processor) ProcessBlock(ctx context.Context, block sync.Block) error {

bridgesync/processor_test.go

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5597,7 +5597,7 @@ func TestProcessor_BackwardLET(t *testing.T) {
55975597
Event{BackwardLET: &BackwardLET{
55985598
BlockNum: 4,
55995599
BlockPos: 0,
5600-
PreviousDepositCount: big.NewInt(6),
5600+
PreviousDepositCount: big.NewInt(5),
56015601
NewDepositCount: big.NewInt(2),
56025602
}},
56035603
},
@@ -5610,13 +5610,38 @@ func TestProcessor_BackwardLET(t *testing.T) {
56105610
targetDepositCount: 3,
56115611
restoredBridgeDepositCounts: []uint32{3},
56125612
},
5613+
{
5614+
name: "backward let event in the middle of bridges + reorg backward let",
5615+
setupBlocks: func() []sync.Block {
5616+
blocks := buildBlocksWithSequentialBridges(2, 3, 0, 0)
5617+
backwardLETBlock := sync.Block{
5618+
Num: uint64(len(blocks) + 1),
5619+
Hash: common.HexToHash(fmt.Sprintf("0x%x", len(blocks)+1)),
5620+
Events: []any{
5621+
Event{BackwardLET: &BackwardLET{
5622+
BlockNum: uint64(len(blocks) + 1),
5623+
BlockPos: 0,
5624+
PreviousDepositCount: big.NewInt(5),
5625+
NewDepositCount: big.NewInt(2),
5626+
}},
5627+
},
5628+
}
5629+
blocks = append(blocks, backwardLETBlock)
5630+
blocks = append(blocks, buildBlocksWithSequentialBridges(3, 2, uint64(len(blocks)), 3)...)
5631+
5632+
return blocks
5633+
},
5634+
firstReorgedBlock: uint64Ptr(3),
5635+
targetDepositCount: 5,
5636+
restoredBridgeDepositCounts: []uint32{3, 4, 5},
5637+
},
56135638
}
56145639

56155640
for _, c := range testCases {
56165641
t.Run(c.name, func(t *testing.T) {
56175642
dbPath := filepath.Join(t.TempDir(), "backward_let_cases.sqlite")
56185643
require.NoError(t, migrations.RunMigrations(dbPath))
5619-
p, err := newProcessor(dbPath, "bridge-syncer", log.GetDefaultLogger(), dbQueryTimeout)
5644+
p, err := newProcessor(dbPath, "bridge-syncer", log.GetDefaultLogger(), 2*time.Minute)
56205645
require.NoError(t, err)
56215646

56225647
blocks := c.setupBlocks()
@@ -5640,7 +5665,7 @@ func TestProcessor_BackwardLET(t *testing.T) {
56405665
for i := range expectedBridges {
56415666
for _, restored := range c.restoredBridgeDepositCounts {
56425667
if expectedBridges[i].DepositCount == restored {
5643-
expectedBridges[i].Source = BridgeSourceBackwardLET
5668+
expectedBridges[i].Source = BridgeSourceRestoredBackwardLET
56445669
}
56455670
}
56465671
}

0 commit comments

Comments
 (0)