Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(relayer): hardcode gas limit to determine if a message needs extra gas to deploy a contract #13764

Merged
merged 4 commits into from
May 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions packages/relayer/.default.env
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ MYSQL_MAX_OPEN_CONNS=3000
MYSQL_CONN_MAX_LIFETIME_IN_MS=100000
RELAYER_ECDSA_KEY=
L1_BRIDGE_ADDRESS=0x3612E284D763f42f5E4CB72B1602b23DAEC3cA60
L2_BRIDGE_ADDRESS=0x0000777700000000000000000000000000000004
L2_BRIDGE_ADDRESS=0x1000777700000000000000000000000000000004
L1_TOKEN_VAULT_ADDRESS=0x3612E284D763f42f5E4CB72B1602b23DAEC3cA60
L2_TOKEN_VAULT_ADDRESS=0x1000777700000000000000000000000000000002
L1_TAIKO_ADDRESS=0x7B3AF414448ba906f02a1CA307C56c4ADFF27ce7
L2_TAIKO_ADDRESS=0x0000777700000000000000000000000000000001
L2_TAIKO_ADDRESS=0x1000777700000000000000000000000000000001
L1_SIGNAL_SERVICE_ADDRESS=0x403cc7802725928652a3d116Bb1781005e2e76d3
L2_SIGNAL_SERVICE_ADDRESS=0x8BDa62dc6c0160Bce2C3a9360755dF030575985a
L2_SIGNAL_SERVICE_ADDRESS=0x1000777700000000000000000000000000000007
L1_RPC_URL=wss://l1ws.a1.taiko.xyz
L2_RPC_URL=wss://l2ws.a1.taiko.xyz
CONFIRMATIONS_BEFORE_PROCESSING=13
Expand Down
6 changes: 3 additions & 3 deletions packages/relayer/.golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ linters:

linters-settings:
funlen:
lines: 137
statements: 54
lines: 145
statements: 60
gocognit:
min-complexity: 43
min-complexity: 50

issues:
exclude-rules:
Expand Down
4 changes: 4 additions & 0 deletions packages/relayer/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ var (
"L1_BRIDGE_ADDRESS",
"L2_BRIDGE_ADDRESS",
"L2_TAIKO_ADDRESS",
"L1_TOKEN_VAULT_ADDRESS",
"L2_TOKEN_VAULT_ADDRESS",
"L1_RPC_URL",
"L2_RPC_URL",
"MYSQL_USER",
Expand Down Expand Up @@ -220,6 +222,7 @@ func makeIndexers(
DestTaikoAddress: common.HexToAddress(os.Getenv("L2_TAIKO_ADDRESS")),
SrcTaikoAddress: common.HexToAddress(os.Getenv("L1_TAIKO_ADDRESS")),
SrcSignalServiceAddress: common.HexToAddress(os.Getenv("L1_SIGNAL_SERVICE_ADDRESS")),
DestTokenVaultAddress: common.HexToAddress(os.Getenv("L2_TOKEN_VAULT_ADDRESS")),
BlockBatchSize: uint64(blockBatchSize),
NumGoroutines: numGoroutines,
SubscriptionBackoff: subscriptionBackoff,
Expand Down Expand Up @@ -249,6 +252,7 @@ func makeIndexers(
DestBridgeAddress: common.HexToAddress(os.Getenv("L1_BRIDGE_ADDRESS")),
DestTaikoAddress: common.HexToAddress(os.Getenv("L1_TAIKO_ADDRESS")),
SrcSignalServiceAddress: common.HexToAddress(os.Getenv("L2_SIGNAL_SERVICE_ADDRESS")),
DestTokenVaultAddress: common.HexToAddress(os.Getenv("L1_TOKEN_VAULT_ADDRESS")),
BlockBatchSize: uint64(blockBatchSize),
NumGoroutines: numGoroutines,
SubscriptionBackoff: subscriptionBackoff,
Expand Down
55 changes: 1 addition & 54 deletions packages/relayer/indexer/handle_event.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@ import (
"encoding/json"
"math/big"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"github.com/taikoxyz/taiko-mono/packages/relayer"
"github.com/taikoxyz/taiko-mono/packages/relayer/contracts/bridge"
"github.com/taikoxyz/taiko-mono/packages/relayer/contracts/tokenvault"
)

// handleEvent handles an individual MessageSent event
Expand Down Expand Up @@ -46,7 +44,7 @@ func (svc *Service) handleEvent(
return errors.Wrap(err, "json.Marshal(event)")
}

eventType, canonicalToken, amount, err := eventTypeAmountAndCanonicalTokenFromEvent(event)
eventType, canonicalToken, amount, err := relayer.DecodeMessageSentData(event)
if err != nil {
return errors.Wrap(err, "eventTypeAmountAndCanonicalTokenFromEvent(event)")
}
Expand Down Expand Up @@ -83,57 +81,6 @@ func (svc *Service) handleEvent(
return nil
}

func eventTypeAmountAndCanonicalTokenFromEvent(
event *bridge.BridgeMessageSent,
) (relayer.EventType, relayer.CanonicalToken, *big.Int, error) {
eventType := relayer.EventTypeSendETH

var canonicalToken relayer.CanonicalToken

var amount *big.Int

if event.Message.Data != nil && common.BytesToHash(event.Message.Data) != relayer.ZeroHash {
tokenVaultMD := bind.MetaData{
ABI: tokenvault.TokenVaultABI,
}

tokenVaultABI, err := tokenVaultMD.GetAbi()
if err != nil {
return eventType, relayer.CanonicalToken{}, big.NewInt(0), errors.Wrap(err, "tokenVaultMD.GetAbi()")
}

method, err := tokenVaultABI.MethodById(event.Message.Data[:4])
if err != nil {
return eventType, relayer.CanonicalToken{}, big.NewInt(0), errors.Wrap(err, "tokenVaultABI.MethodById")
}

inputsMap := make(map[string]interface{})

if err := method.Inputs.UnpackIntoMap(inputsMap, event.Message.Data[4:]); err != nil {
return eventType, relayer.CanonicalToken{}, big.NewInt(0), errors.Wrap(err, "method.Inputs.UnpackIntoMap")
}

if method.Name == "receiveERC20" {
eventType = relayer.EventTypeSendERC20

canonicalToken = inputsMap["canonicalToken"].(struct {
// nolint
ChainId *big.Int `json:"chainId"`
Addr common.Address `json:"addr"`
Decimals uint8 `json:"decimals"`
Symbol string `json:"symbol"`
Name string `json:"name"`
})

amount = inputsMap["amount"].(*big.Int)
}
} else {
amount = event.Message.DepositValue
}

return eventType, canonicalToken, amount, nil
}

func canProcessMessage(
ctx context.Context,
eventStatus relayer.EventStatus,
Expand Down
56 changes: 0 additions & 56 deletions packages/relayer/indexer/handle_event_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/taikoxyz/taiko-mono/packages/relayer"
"github.com/taikoxyz/taiko-mono/packages/relayer/contracts/bridge"
"github.com/taikoxyz/taiko-mono/packages/relayer/mock"
)

Expand Down Expand Up @@ -148,58 +147,3 @@ func Test_eventStatusFromMsgHash(t *testing.T) {
})
}
}

func Test_eventTypeAmountAndCanonicalTokenFromEvent(t *testing.T) {
tests := []struct {
name string
event *bridge.BridgeMessageSent
wantEventType relayer.EventType
wantCanonicalToken relayer.CanonicalToken
wantAmount *big.Int
wantError error
}{
{
"receiveERC20",
&bridge.BridgeMessageSent{
Message: bridge.IBridgeMessage{
// nolint lll
Data: common.Hex2Bytes("0c6fab8200000000000000000000000000000000000000000000000000000000000000800000000000000000000000004ec242468812b6ffc8be8ff423af7bd23108d9910000000000000000000000004ec242468812b6ffc8be8ff423af7bd23108d99100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000007a68000000000000000000000000e4337137828c93d0046212ebda8a82a24356b67b000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000004544553540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000095465737445524332300000000000000000000000000000000000000000000000"),
},
},
relayer.EventTypeSendERC20,
relayer.CanonicalToken{
ChainId: big.NewInt(31336),
Addr: common.HexToAddress("0xe4337137828c93D0046212ebDa8a82a24356b67B"),
Decimals: uint8(18),
Symbol: "TEST",
Name: "TestERC20",
},
big.NewInt(1),
nil,
},
{
"nilData",
&bridge.BridgeMessageSent{
Message: bridge.IBridgeMessage{
// nolint lll
DepositValue: big.NewInt(1),
Data: common.Hex2Bytes("00"),
},
},
relayer.EventTypeSendETH,
relayer.CanonicalToken{},
big.NewInt(1),
nil,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
eventType, canonicalToken, amount, err := eventTypeAmountAndCanonicalTokenFromEvent(tt.event)
assert.Equal(t, tt.wantEventType, eventType)
assert.Equal(t, tt.wantCanonicalToken, canonicalToken)
assert.Equal(t, tt.wantAmount, amount)
assert.Equal(t, tt.wantError, err)
})
}
}
16 changes: 12 additions & 4 deletions packages/relayer/indexer/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/taikoxyz/taiko-mono/packages/relayer/contracts/bridge"
"github.com/taikoxyz/taiko-mono/packages/relayer/contracts/icrosschainsync"
"github.com/taikoxyz/taiko-mono/packages/relayer/contracts/taikol1"
"github.com/taikoxyz/taiko-mono/packages/relayer/contracts/tokenvault"
"github.com/taikoxyz/taiko-mono/packages/relayer/message"
"github.com/taikoxyz/taiko-mono/packages/relayer/proof"
)
Expand Down Expand Up @@ -65,6 +66,7 @@ type NewServiceOpts struct {
DestBridgeAddress common.Address
SrcTaikoAddress common.Address
DestTaikoAddress common.Address
DestTokenVaultAddress common.Address
SrcSignalServiceAddress common.Address
BlockBatchSize uint64
NumGoroutines int
Expand Down Expand Up @@ -124,12 +126,12 @@ func NewService(opts NewServiceOpts) (*Service, error) {

srcBridge, err := bridge.NewBridge(opts.BridgeAddress, opts.EthClient)
if err != nil {
return nil, errors.Wrap(err, "contracts.NewBridge")
return nil, errors.Wrap(err, "bridge.NewBridge")
}

destBridge, err := bridge.NewBridge(opts.DestBridgeAddress, opts.DestEthClient)
if err != nil {
return nil, errors.Wrap(err, "contracts.NewBridge")
return nil, errors.Wrap(err, "bridge.NewBridge")
}

prover, err := proof.New(opts.EthClient)
Expand All @@ -139,17 +141,22 @@ func NewService(opts NewServiceOpts) (*Service, error) {

destHeaderSyncer, err := icrosschainsync.NewICrossChainSync(opts.DestTaikoAddress, opts.DestEthClient)
if err != nil {
return nil, errors.Wrap(err, "contracts.NewTaikoL2")
return nil, errors.Wrap(err, "icrosschainsync.NewTaikoL2")
}

var taikoL1 *taikol1.TaikoL1
if opts.SrcTaikoAddress != ZeroAddress {
taikoL1, err = taikol1.NewTaikoL1(opts.SrcTaikoAddress, opts.EthClient)
if err != nil {
return nil, errors.Wrap(err, "contracts.NewTaikoL1")
return nil, errors.Wrap(err, "taikol1.NewTaikoL1")
}
}

destTokenVault, err := tokenvault.NewTokenVault(opts.DestTokenVaultAddress, opts.DestEthClient)
if err != nil {
return nil, errors.Wrap(err, "tokenvault.NewTokenVault")
}

processor, err := message.NewProcessor(message.NewProcessorOpts{
Prover: prover,
ECDSAKey: privateKey,
Expand All @@ -165,6 +172,7 @@ func NewService(opts NewServiceOpts) (*Service, error) {
HeaderSyncIntervalSeconds: opts.HeaderSyncIntervalInSeconds,
SrcSignalServiceAddress: opts.SrcSignalServiceAddress,
ConfirmationsTimeoutInSeconds: opts.ConfirmationsTimeoutInSeconds,
DestTokenVault: destTokenVault,
})
if err != nil {
return nil, errors.Wrap(err, "message.NewProcessor")
Expand Down
1 change: 1 addition & 0 deletions packages/relayer/indexer/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func newTestService() (*Service, relayer.Bridge) {
DestBridge: &mock.Bridge{},
SrcETHClient: &mock.EthClient{},
DestETHClient: &mock.EthClient{},
DestTokenVault: &mock.TokenVault{},
ECDSAKey: privateKey,
DestHeaderSyncer: &mock.HeaderSyncer{},
Prover: prover,
Expand Down
47 changes: 43 additions & 4 deletions packages/relayer/message/process_message.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,9 @@ func (p *Processor) sendProcessMessageCall(

gas, cost, err := p.estimateGas(ctx, event.Message, proof)
if err != nil || gas == 0 {
// we can get unable to estimet gas for contract deployments within the contract code.
// if we get an error or the gas is 0, lets manual set high gas limit and ignore error,
// and try to actually send.
auth.GasLimit = 1500000
if err := p.hardcodeGasLimit(ctx, auth, event); err != nil {
return nil, errors.Wrap(err, "p.hardcodeGasLimit")
}
}

if bool(p.profitableOnly) {
Expand Down Expand Up @@ -189,6 +188,46 @@ func (p *Processor) sendProcessMessageCall(
return tx, nil
}

// hardcodeGasLimit determines a viable gas limit when we can get
// unable to estimate gas for contract deployments within the contract code.
// if we get an error or the gas is 0, lets manual set high gas limit and ignore error,
// and try to actually send.
// if contract has not been deployed, we need much higher gas limit, otherwise, we can
// send lower.
func (p *Processor) hardcodeGasLimit(
ctx context.Context,
auth *bind.TransactOpts,
event *bridge.BridgeMessageSent,
) error {
eventType, canonicalToken, _, err := relayer.DecodeMessageSentData(event)
if err != nil {
return errors.Wrap(err, "relayer.DecodeMessageSentData")
}

if eventType == relayer.EventTypeSendETH {
// eth bridges take much less gas, from 250k to 450k.
auth.GasLimit = 500000
} else {
// determine whether the canonical token is bridged or not on this chain
bridgedAddress, err := p.destTokenVault.CanonicalToBridged(nil, canonicalToken.ChainId, canonicalToken.Addr)
if err != nil {
return errors.Wrap(err, "p.destTokenVault.IsBridgedToken")
}

if bridgedAddress == relayer.ZeroAddress {
// needs large gas limit because it has to deploy an ERC20 contract on destination
// chain. deploying ERC20 can be 2 mil by itself.
auth.GasLimit = 3000000
} else {
// needs larger than ETH gas limit but not as much as deploying ERC20.
// takes 450-550k gas after signalRoot refactors.
auth.GasLimit = 600000
}
}

return nil
}

func (p *Processor) setLatestNonce(nonce uint64) {
p.destNonce = nonce
}
Expand Down
4 changes: 4 additions & 0 deletions packages/relayer/message/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type ethClient interface {
HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error)
SuggestGasPrice(ctx context.Context) (*big.Int, error)
}

type Processor struct {
eventRepo relayer.EventRepository
srcEthClient ethClient
Expand All @@ -29,6 +30,7 @@ type Processor struct {

destBridge relayer.Bridge
destHeaderSyncer relayer.HeaderSyncer
destTokenVault relayer.TokenVault

prover *proof.Prover

Expand All @@ -54,6 +56,7 @@ type NewProcessorOpts struct {
DestBridge relayer.Bridge
EventRepo relayer.EventRepository
DestHeaderSyncer relayer.HeaderSyncer
DestTokenVault relayer.TokenVault
RelayerAddress common.Address
SrcSignalServiceAddress common.Address
Confirmations uint64
Expand Down Expand Up @@ -114,6 +117,7 @@ func NewProcessor(opts NewProcessorOpts) (*Processor, error) {
destEthClient: opts.DestETHClient,
destBridge: opts.DestBridge,
destHeaderSyncer: opts.DestHeaderSyncer,
destTokenVault: opts.DestTokenVault,

mu: &sync.Mutex{},

Expand Down
1 change: 1 addition & 0 deletions packages/relayer/message/processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func newTestProcessor(profitableOnly relayer.ProfitableOnly) *Processor {
destBridge: &mock.Bridge{},
srcEthClient: &mock.EthClient{},
destEthClient: &mock.EthClient{},
destTokenVault: &mock.TokenVault{},
mu: &sync.Mutex{},
ecdsaKey: privateKey,
destHeaderSyncer: &mock.HeaderSyncer{},
Expand Down
20 changes: 20 additions & 0 deletions packages/relayer/mock/token_vault.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package mock

import (
"math/big"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/taikoxyz/taiko-mono/packages/relayer"
)

type TokenVault struct {
}

func (t *TokenVault) CanonicalToBridged(
opts *bind.CallOpts,
chainID *big.Int,
canonicalAddress common.Address,
) (common.Address, error) {
return relayer.ZeroAddress, nil
}
Loading