forked from OffchainLabs/nitro
-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathwait_for_l1.go
119 lines (111 loc) · 3.7 KB
/
wait_for_l1.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Copyright 2021-2024, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
package arbutil
import (
"context"
"errors"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/rpc"
)
type L1Interface interface {
bind.ContractBackend
bind.BlockHashContractCaller
ethereum.ChainReader
ethereum.ChainStateReader
ethereum.TransactionReader
TransactionSender(ctx context.Context, tx *types.Transaction, block common.Hash, index uint) (common.Address, error)
BlockNumber(ctx context.Context) (uint64, error)
PendingCallContract(ctx context.Context, msg ethereum.CallMsg) ([]byte, error)
ChainID(ctx context.Context) (*big.Int, error)
Client() rpc.ClientInterface
}
func SendTxAsCall(ctx context.Context, client L1Interface, tx *types.Transaction, from common.Address, blockNum *big.Int, unlimitedGas bool) ([]byte, error) {
var gas uint64
if unlimitedGas {
gas = 0
} else {
gas = tx.Gas()
}
callMsg := ethereum.CallMsg{
From: from,
To: tx.To(),
Gas: gas,
GasFeeCap: tx.GasFeeCap(),
GasTipCap: tx.GasTipCap(),
Value: tx.Value(),
Data: tx.Data(),
AccessList: tx.AccessList(),
}
return client.CallContract(ctx, callMsg, blockNum)
}
func GetPendingCallBlockNumber(ctx context.Context, client L1Interface) (*big.Int, error) {
msg := ethereum.CallMsg{
// Pretend to be a contract deployment to execute EVM code without calling a contract.
To: nil,
// Contains the following EVM code, which returns the current block number:
// NUMBER
// PUSH1 0
// MSTORE
// PUSH1 32
// PUSH1 0
// RETURN
Data: []byte{0x43, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0xF3},
}
callRes, err := client.PendingCallContract(ctx, msg)
if err != nil {
return nil, err
}
return new(big.Int).SetBytes(callRes), nil
}
func DetailTxError(ctx context.Context, client L1Interface, tx *types.Transaction, txRes *types.Receipt) error {
// Re-execute the transaction as a call to get a better error
if ctx.Err() != nil {
return ctx.Err()
}
if txRes == nil {
return errors.New("expected receipt")
}
if txRes.Status == types.ReceiptStatusSuccessful {
return nil
}
from, err := client.TransactionSender(ctx, tx, txRes.BlockHash, txRes.TransactionIndex)
if err != nil {
return fmt.Errorf("TransactionSender got: %w for tx %v", err, tx.Hash())
}
_, err = SendTxAsCall(ctx, client, tx, from, txRes.BlockNumber, false)
if err == nil {
return fmt.Errorf("tx failed but call succeeded for tx hash %v", tx.Hash())
}
_, err = SendTxAsCall(ctx, client, tx, from, txRes.BlockNumber, true)
if err == nil {
return fmt.Errorf("%w for tx hash %v", vm.ErrOutOfGas, tx.Hash())
}
return fmt.Errorf("SendTxAsCall got: %w for tx hash %v", err, tx.Hash())
}
func DetailTxErrorUsingCallMsg(ctx context.Context, client L1Interface, txHash common.Hash, txRes *types.Receipt, callMsg ethereum.CallMsg) error {
// Re-execute the transaction as a call to get a better error
if ctx.Err() != nil {
return ctx.Err()
}
if txRes == nil {
return errors.New("expected receipt")
}
if txRes.Status == types.ReceiptStatusSuccessful {
return nil
}
var err error
if _, err = client.CallContract(ctx, callMsg, txRes.BlockNumber); err == nil {
return fmt.Errorf("tx failed but call succeeded for tx hash %v", txHash)
}
callMsg.Gas = 0
if _, err = client.CallContract(ctx, callMsg, txRes.BlockNumber); err == nil {
return fmt.Errorf("%w for tx hash %v", vm.ErrOutOfGas, txHash)
}
return fmt.Errorf("SendTxAsCall got: %w for tx hash %v", err, txHash)
}