@@ -125,8 +125,8 @@ var (
125125type BridgeSource string
126126
127127const (
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)
13751401func (p * processor ) ProcessBlock (ctx context.Context , block sync.Block ) error {
0 commit comments