Skip to content

Commit

Permalink
feat(relayer): hardcode gas limit to determine if a message needs ext…
Browse files Browse the repository at this point in the history
…ra gas to deploy a contract (#13764)

Co-authored-by: Roger <50648015+RogerLamTd@users.noreply.github.com>
  • Loading branch information
cyberhorsey and RogerLamTd authored May 16, 2023
1 parent 894fba2 commit 0615bf6
Show file tree
Hide file tree
Showing 14 changed files with 221 additions and 125 deletions.
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

0 comments on commit 0615bf6

Please sign in to comment.