From 9e1b6fe859df277cc6b63523609f73f8b3bc6f76 Mon Sep 17 00:00:00 2001 From: clabby Date: Tue, 6 Dec 2022 19:40:49 -0500 Subject: [PATCH] Two step withdrawal indexer updates --- indexer/db/db.go | 36 +++++++++++++++++++++++++--- indexer/db/l1block.go | 1 + indexer/db/sql.go | 2 ++ indexer/db/withdrawal.go | 10 ++++++++ indexer/services/l1/bridge/bridge.go | 6 ++++- indexer/services/l1/bridge/portal.go | 34 ++++++++++++++++++++++++++ indexer/services/l1/service.go | 14 ++++++++++- 7 files changed, 98 insertions(+), 5 deletions(-) diff --git a/indexer/db/db.go b/indexer/db/db.go index 288d463834a6..cf49a77b119d 100644 --- a/indexer/db/db.go +++ b/indexer/db/db.go @@ -198,7 +198,12 @@ func (d *Database) AddIndexedL1Block(block *IndexedL1Block) error { ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) ` - const updateWithdrawalStatement = ` + const updateProvenWithdrawalStatement = ` + UPDATE withdrawals SET (br_withdrawal_proven_tx_hash, br_withdrawal_proven_log_index) = ($1, $2) + WHERE br_withdrawal_hash = $3 + ` + + const updateFinalizedWithdrawalStatement = ` UPDATE withdrawals SET (br_withdrawal_finalized_tx_hash, br_withdrawal_finalized_log_index, br_withdrawal_finalized_success) = ($1, $2, $3) WHERE br_withdrawal_hash = $4 ` @@ -236,10 +241,24 @@ func (d *Database) AddIndexedL1Block(block *IndexedL1Block) error { } } + if len(block.ProvenWithdrawals) > 0 { + for _, wd := range block.ProvenWithdrawals { + _, err = tx.Exec( + updateProvenWithdrawalStatement, + wd.TxHash.String(), + wd.LogIndex, + wd.WithdrawalHash.String(), + ) + if err != nil { + return err + } + } + } + if len(block.FinalizedWithdrawals) > 0 { for _, wd := range block.FinalizedWithdrawals { _, err = tx.Exec( - updateWithdrawalStatement, + updateFinalizedWithdrawalStatement, wd.TxHash.String(), wd.LogIndex, wd.Success, @@ -486,6 +505,7 @@ func (d *Database) GetWithdrawalsByAddress(address common.Address, page Paginati withdrawals.l1_token, withdrawals.l2_token, l2_tokens.name, l2_tokens.symbol, l2_tokens.decimals, l2_blocks.number, l2_blocks.timestamp, withdrawals.br_withdrawal_hash, + withdrawals.br_withdrawal_proven_tx_hash, withdrawals.br_withdrawal_proven_log_index, withdrawals.br_withdrawal_finalized_tx_hash, withdrawals.br_withdrawal_finalized_log_index, withdrawals.br_withdrawal_finalized_success FROM withdrawals @@ -506,6 +526,8 @@ func (d *Database) GetWithdrawalsByAddress(address common.Address, page Paginati var withdrawal WithdrawalJSON var l2Token Token var wdHash sql.NullString + var proveTxHash sql.NullString + var proveLogIndex sql.NullInt32 var finTxHash sql.NullString var finLogIndex sql.NullInt32 var finSuccess sql.NullBool @@ -515,7 +537,8 @@ func (d *Database) GetWithdrawalsByAddress(address common.Address, page Paginati &withdrawal.L1Token, &l2Token.Address, &l2Token.Name, &l2Token.Symbol, &l2Token.Decimals, &withdrawal.BlockNumber, &withdrawal.BlockTimestamp, - &wdHash, &finTxHash, &finLogIndex, &finSuccess, + &wdHash, &proveTxHash, &proveLogIndex, + &finTxHash, &finLogIndex, &finSuccess, ); err != nil { return err } @@ -523,6 +546,13 @@ func (d *Database) GetWithdrawalsByAddress(address common.Address, page Paginati if wdHash.Valid { withdrawal.BedrockWithdrawalHash = &wdHash.String } + if proveTxHash.Valid { + withdrawal.BedrockProvenTxHash = &proveTxHash.String + } + if proveLogIndex.Valid { + idx := int(proveLogIndex.Int32) + withdrawal.BedrockProvenLogIndex = &idx + } if finTxHash.Valid { withdrawal.BedrockFinalizedTxHash = &finTxHash.String } diff --git a/indexer/db/l1block.go b/indexer/db/l1block.go index 53b506d6ae00..f767b141f1af 100644 --- a/indexer/db/l1block.go +++ b/indexer/db/l1block.go @@ -11,6 +11,7 @@ type IndexedL1Block struct { Number uint64 Timestamp uint64 Deposits []Deposit + ProvenWithdrawals []ProvenWithdrawal FinalizedWithdrawals []FinalizedWithdrawal } diff --git a/indexer/db/sql.go b/indexer/db/sql.go index 21c16af255eb..d5180cd9c85c 100644 --- a/indexer/db/sql.go +++ b/indexer/db/sql.go @@ -124,6 +124,8 @@ CREATE TABLE IF NOT EXISTS airdrops ( const updateWithdrawalsTable = ` ALTER TABLE withdrawals ADD COLUMN IF NOT EXISTS br_withdrawal_hash VARCHAR NULL; +ALTER TABLE withdrawals ADD COLUMN IF NOT EXISTS br_withdrawal_proven_tx_hash VARCHAR NULL; +ALTER TABLE withdrawals ADD COLUMN IF NOT EXISTS br_withdrawal_proven_log_index INTEGER NULL; ALTER TABLE withdrawals ADD COLUMN IF NOT EXISTS br_withdrawal_finalized_tx_hash VARCHAR NULL; ALTER TABLE withdrawals ADD COLUMN IF NOT EXISTS br_withdrawal_finalized_log_index INTEGER NULL; ALTER TABLE withdrawals ADD COLUMN IF NOT EXISTS br_withdrawal_finalized_success BOOLEAN NULL; diff --git a/indexer/db/withdrawal.go b/indexer/db/withdrawal.go index 2cc31963ac68..92925588a7f0 100644 --- a/indexer/db/withdrawal.go +++ b/indexer/db/withdrawal.go @@ -40,6 +40,8 @@ type WithdrawalJSON struct { TxHash string `json:"transactionHash"` Batch *StateBatchJSON `json:"batch"` BedrockWithdrawalHash *string `json:"bedrockWithdrawalHash"` + BedrockProvenTxHash *string `json:"bedrockProvenTxHash"` + BedrockProvenLogIndex *int `json:"bedrockProvenLogIndex"` BedrockFinalizedTxHash *string `json:"bedrockFinalizedTxHash"` BedrockFinalizedLogIndex *int `json:"bedrockFinalizedLogIndex"` BedrockFinalizedSuccess *bool `json:"bedrockFinalizedSuccess"` @@ -75,6 +77,14 @@ func (f FinalizationState) SQL() string { return "" } +type ProvenWithdrawal struct { + From common.Address + To common.Address + WithdrawalHash common.Hash + TxHash common.Hash + LogIndex uint +} + type FinalizedWithdrawal struct { WithdrawalHash common.Hash TxHash common.Hash diff --git a/indexer/services/l1/bridge/bridge.go b/indexer/services/l1/bridge/bridge.go index 1ab8813bfcb0..fd97ed3829a8 100644 --- a/indexer/services/l1/bridge/bridge.go +++ b/indexer/services/l1/bridge/bridge.go @@ -21,8 +21,12 @@ type DepositsMap map[common.Hash][]db.Deposit // on block hashes. type InitiatedWithdrawalMap map[common.Hash][]db.Withdrawal +// ProvenWithdrawalsMap is a collection of proven withdrawal +// objects keyed on block hashses +type ProvenWithdrawalsMap map[common.Hash][]db.ProvenWithdrawal + // FinalizedWithdrawalsMap is a collection of finalized withdrawal -// objected keyed on block hashes. +// objects keyed on block hashes. type FinalizedWithdrawalsMap map[common.Hash][]db.FinalizedWithdrawal type Bridge interface { diff --git a/indexer/services/l1/bridge/portal.go b/indexer/services/l1/bridge/portal.go index 6a2c3efb08aa..7ea11a58d068 100644 --- a/indexer/services/l1/bridge/portal.go +++ b/indexer/services/l1/bridge/portal.go @@ -29,6 +29,40 @@ func (p *Portal) Address() common.Address { return p.address } +func (p *Portal) GetProvenWithdrawalsByBlockRange(ctx context.Context, start, end uint64) (ProvenWithdrawalsMap, error) { + wdsByBlockHash := make(ProvenWithdrawalsMap) + opts := &bind.FilterOpts{ + Context: ctx, + Start: start, + End: &end, + } + + var iter *bindings.OptimismPortalWithdrawalProvenIterator + err := backoff.Do(3, backoff.Exponential(), func() error { + var err error + iter, err = p.contract.FilterWithdrawalProven(opts, nil, nil, nil) + return err + }) + if err != nil { + return nil, err + } + + defer iter.Close() + for iter.Next() { + wdsByBlockHash[iter.Event.Raw.BlockHash] = append( + wdsByBlockHash[iter.Event.Raw.BlockHash], db.ProvenWithdrawal{ + WithdrawalHash: iter.Event.WithdrawalHash, + From: iter.Event.From, + To: iter.Event.To, + TxHash: iter.Event.Raw.TxHash, + LogIndex: iter.Event.Raw.Index, + }, + ) + } + + return wdsByBlockHash, iter.Error() +} + func (p *Portal) GetFinalizedWithdrawalsByBlockRange(ctx context.Context, start, end uint64) (FinalizedWithdrawalsMap, error) { wdsByBlockHash := make(FinalizedWithdrawalsMap) opts := &bind.FilterOpts{ diff --git a/indexer/services/l1/service.go b/indexer/services/l1/service.go index b660a80e73d7..cc93f5e5947b 100644 --- a/indexer/services/l1/service.go +++ b/indexer/services/l1/service.go @@ -246,6 +246,7 @@ func (s *Service) Update(newHeader *types.Header) error { }() bridgeDepositsCh := make(chan bridge.DepositsMap, len(s.bridges)) + provenWithdrawalsCh := make(chan bridge.ProvenWithdrawalsMap, 1) finalizedWithdrawalsCh := make(chan bridge.FinalizedWithdrawalsMap, 1) errCh := make(chan error, len(s.bridges)+1) @@ -259,6 +260,14 @@ func (s *Service) Update(newHeader *types.Header) error { bridgeDepositsCh <- deposits }(bridgeImpl) } + go func() { + provenWithdrawals, err := s.portal.GetProvenWithdrawalsByBlockRange(s.ctx, startHeight, endHeight) + if err != nil { + errCh <- err + return + } + provenWithdrawalsCh <- provenWithdrawals + }() go func() { finalizedWithdrawals, err := s.portal.GetFinalizedWithdrawalsByBlockRange(s.ctx, startHeight, endHeight) if err != nil { @@ -291,6 +300,7 @@ func (s *Service) Update(newHeader *types.Header) error { } } + provenWithdrawalsByBlockHash := <-provenWithdrawalsCh finalizedWithdrawalsByBlockHash := <-finalizedWithdrawalsCh var stateBatches map[common.Hash][]db.StateBatch @@ -307,11 +317,12 @@ func (s *Service) Update(newHeader *types.Header) error { number := header.Number.Uint64() deposits := depositsByBlockHash[blockHash] batches := stateBatches[blockHash] + provenWds := provenWithdrawalsByBlockHash[blockHash] finalizedWds := finalizedWithdrawalsByBlockHash[blockHash] // Always record block data in the last block // in the list of headers - if len(deposits) == 0 && len(batches) == 0 && len(finalizedWds) == 0 && i != len(headers)-1 { + if len(deposits) == 0 && len(batches) == 0 && len(provenWds) == 0 && len(finalizedWds) == 0 && i != len(headers)-1 { continue } @@ -321,6 +332,7 @@ func (s *Service) Update(newHeader *types.Header) error { Number: number, Timestamp: header.Time, Deposits: deposits, + ProvenWithdrawals: provenWds, FinalizedWithdrawals: finalizedWds, }