diff --git a/proposer/proposer.go b/proposer/proposer.go index 62161cd9c..dd38e1846 100644 --- a/proposer/proposer.go +++ b/proposer/proposer.go @@ -5,6 +5,7 @@ import ( "context" "fmt" "math/rand" + "strings" "sync" "time" @@ -363,7 +364,29 @@ func (p *Proposer) ProposeTxLists(ctx context.Context, txListsBytes [][]byte) [] txCandidates[i] = *candidate } - return p.txSender.SendAndWaitDetailed("proposeBlock", txCandidates...) + // Send the transactions to the TaikoL1 contract, and if any of them fails, try + // to parse the custom error. + errors := p.txSender.SendAndWaitDetailed("proposeBlock", txCandidates...) + for i, err := range errors { + if err == nil { + continue + } + + // If a transaction is reverted on chain, the error string returned by txSender will like this: + // fmt.Errorf("%w purpose: %v hash: %v", ErrTransactionReverted, txPurpose, rcpt.Receipt.TxHash) + // Then we try parsing the custom error for more details in log. + if strings.Contains("purpose: ", err.Error()) && strings.Contains("hash: ", err.Error()) { + txHash := strings.Split(err.Error(), "hash: ")[1] + receipt, err := p.rpc.L1.TransactionReceipt(ctx, common.HexToHash(txHash)) + if err != nil { + log.Error("Failed to fetch receipt", "txHash", txHash, "error", err) + continue + } + errors[i] = encoding.TryParsingCustomErrorFromReceipt(ctx, p.rpc.L1, p.proposerAddress, receipt) + } + } + + return errors } // updateProposingTicker updates the internal proposing timer.