From 2fa81d98954af104f2e3309979a6216d04813e6b Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Thu, 17 Aug 2023 18:47:13 -0700 Subject: [PATCH 01/82] fix the history page --- .../src/components/Events/History.svelte | 53 +++++++++++-------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/packages/pos-dashboard/src/components/Events/History.svelte b/packages/pos-dashboard/src/components/Events/History.svelte index 8a2f2fe0fd5..a9a4d22aabb 100644 --- a/packages/pos-dashboard/src/components/Events/History.svelte +++ b/packages/pos-dashboard/src/components/Events/History.svelte @@ -25,11 +25,16 @@ pageSize: number, allEvents: APIResponseEvent[], ) { - if (!allEvents) return []; - const start = (page - 1) * pageSize; - const end = start + pageSize; - const ret = allEvents.slice(start, end); - return ret; + loading = true; + try { + if (!allEvents) return []; + const start = (page - 1) * pageSize; + const end = start + pageSize; + const ret = allEvents.slice(start, end); + return ret; + } finally { + loading = false; + } } const tabs = [ @@ -42,6 +47,7 @@ ]; async function getEvents(signer: ethers.Signer, activeTab: string) { + loading = true; let items = []; if (!signer) return []; @@ -82,21 +88,24 @@
{#each tabs as tab} (activeTab = tab.name)}>{tab.name} + on:click={() => { + eventsToShow = []; + activeTab = tab.name; + }}>{tab.name} {/each} {#each tabs as tab} @@ -108,7 +117,9 @@ Event {#if tab.name === tabs[0].name} Amount - {:else if tab.name === tabs[1].name}{:else if tab.name === tabs[2].name} + {:else if tab.name === tabs[1].name} + Block ID + {:else if tab.name === tabs[2].name} Amount {:else if tab.name === tabs[3].name}{:else if tab.name === tabs[4].name} Block ID @@ -130,13 +141,13 @@ class="cursor-pointer ml-2 hidden md:inline-block" >{event.event} - {#if tab.name === tabs[0].name} + {#if activeTab === tabs[0].name} {ethers.utils.formatUnits(event.amount, 8)} TTKOe - {:else if tab.name === tabs[1].name}{:else if tab.name === tabs[2].name} - {ethers.utils.formatUnits(event.amount, 8)} TTKOe - {:else if tab.name === tabs[3].name}{:else if tab.name === tabs[4].name} + {:else if activeTab === tabs[1].name} + {event.blockID.Int64} + {:else if activeTab === tabs[2].name}{:else if activeTab === tabs[3].name}{:else if activeTab === tabs[4].name} {event.blockID.Int64} - {:else if tab.name === tabs[5].name} + {:else if activeTab === tabs[5].name} {ethers.utils.formatUnits(event.amount, 8)} TTKOe{/if} From 01b6922735a7616e558d47951506421dbcc69b70 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Tue, 29 Aug 2023 20:24:42 -0700 Subject: [PATCH 02/82] wip --- codecov.yml | 2 +- go.mod | 1 + go.sum | 6 + .../{contracts => bindings}/bridge/Bridge.go | 0 .../erc1155vault/ERC1155Vault.go | 0 .../erc20vault/ERC20Vault.go | 0 .../erc721vault/ERC721Vault.go | 0 .../icrosschainsync/ICrossChainSync.go | 0 .../taikol1/TaikoL1.go | 0 .../taikol2/TaikoL2.go | 0 packages/relayer/bridge.go | 2 +- packages/relayer/cli/cli.go | 409 ++++++++++++------ packages/relayer/cmd/main.go | 18 + packages/relayer/flags.go | 4 + .../indexer/detect_and_handle_reorg.go | 6 +- packages/relayer/indexer/handle_event.go | 53 +-- packages/relayer/indexer/handle_event_test.go | 70 --- .../indexer/handle_no_events_in_batch.go | 8 +- packages/relayer/indexer/indexer.go | 135 ++++++ .../save_message_status_changed_events.go | 22 +- packages/relayer/indexer/service.go | 221 ---------- packages/relayer/indexer/service_test.go | 214 +-------- .../set_initial_processing_block_by_mode.go | 12 +- .../{filter_then_subscribe.go => start.go} | 72 +-- ...r_then_subscribe_test.go => start_test.go} | 12 +- packages/relayer/indexer/subscribe.go | 40 +- .../relayer/message/process_message_test.go | 97 ----- packages/relayer/message/processor.go | 140 ------ packages/relayer/message/processor_test.go | 226 ---------- packages/relayer/mock/bridge.go | 2 +- packages/relayer/mock/queue.go | 30 ++ .../relayer/processor/can_process_message.go | 32 ++ .../processor/can_process_message_test.go | 80 ++++ .../relayer/{message => processor}/errors.go | 2 +- .../{message => processor}/estimate_gas.go | 4 +- .../get_latest_nonce.go | 2 +- .../get_latest_nonce_test.go | 2 +- .../{message => processor}/is_profitable.go | 4 +- .../is_profitable_test.go | 4 +- .../{message => processor}/process_message.go | 61 +-- .../relayer/processor/process_message_test.go | 187 ++++++++ packages/relayer/processor/processor.go | 252 +++++++++++ packages/relayer/processor/processor_test.go | 71 +++ .../wait_for_confirmations.go | 2 +- .../wait_for_confirmations_test.go | 2 +- .../wait_header_synced.go | 4 +- .../wait_header_synced_test.go | 4 +- packages/relayer/queue/queue.go | 32 ++ packages/relayer/queue/rabbitmq/queue.go | 130 ++++++ packages/relayer/{ => scripts}/abigen.sh | 2 +- packages/relayer/scripts/install-rabbit-mq.sh | 44 ++ packages/relayer/types.go | 8 +- packages/relayer/types_test.go | 2 +- 53 files changed, 1460 insertions(+), 1273 deletions(-) rename packages/relayer/{contracts => bindings}/bridge/Bridge.go (100%) rename packages/relayer/{contracts => bindings}/erc1155vault/ERC1155Vault.go (100%) rename packages/relayer/{contracts => bindings}/erc20vault/ERC20Vault.go (100%) rename packages/relayer/{contracts => bindings}/erc721vault/ERC721Vault.go (100%) rename packages/relayer/{contracts => bindings}/icrosschainsync/ICrossChainSync.go (100%) rename packages/relayer/{contracts => bindings}/taikol1/TaikoL1.go (100%) rename packages/relayer/{contracts => bindings}/taikol2/TaikoL2.go (100%) create mode 100644 packages/relayer/indexer/indexer.go delete mode 100644 packages/relayer/indexer/service.go rename packages/relayer/indexer/{filter_then_subscribe.go => start.go} (60%) rename packages/relayer/indexer/{filter_then_subscribe_test.go => start_test.go} (82%) delete mode 100644 packages/relayer/message/process_message_test.go delete mode 100644 packages/relayer/message/processor.go delete mode 100644 packages/relayer/message/processor_test.go create mode 100644 packages/relayer/mock/queue.go create mode 100644 packages/relayer/processor/can_process_message.go create mode 100644 packages/relayer/processor/can_process_message_test.go rename packages/relayer/{message => processor}/errors.go (97%) rename packages/relayer/{message => processor}/estimate_gas.go (89%) rename packages/relayer/{message => processor}/get_latest_nonce.go (95%) rename packages/relayer/{message => processor}/get_latest_nonce_test.go (95%) rename packages/relayer/{message => processor}/is_profitable.go (86%) rename packages/relayer/{message => processor}/is_profitable_test.go (93%) rename packages/relayer/{message => processor}/process_message.go (86%) create mode 100644 packages/relayer/processor/process_message_test.go create mode 100644 packages/relayer/processor/processor.go create mode 100644 packages/relayer/processor/processor_test.go rename packages/relayer/{message => processor}/wait_for_confirmations.go (96%) rename packages/relayer/{message => processor}/wait_for_confirmations_test.go (94%) rename packages/relayer/{message => processor}/wait_header_synced.go (95%) rename packages/relayer/{message => processor}/wait_header_synced_test.go (79%) create mode 100644 packages/relayer/queue/queue.go create mode 100644 packages/relayer/queue/rabbitmq/queue.go rename packages/relayer/{ => scripts}/abigen.sh (94%) create mode 100755 packages/relayer/scripts/install-rabbit-mq.sh diff --git a/codecov.yml b/codecov.yml index 537ea5dda77..20dc6ea3357 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,6 +1,6 @@ coverage: ignore: - - "packages/relayer/contracts/**/*" + - "packages/relayer/bindings/**/*" - "packages/relayer/mock/**/*" - "packages/relayer/cmd/**/*" status: diff --git a/go.mod b/go.mod index 6b88e30583f..d887bc5342f 100644 --- a/go.mod +++ b/go.mod @@ -100,6 +100,7 @@ require ( github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.39.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect + github.com/rabbitmq/amqp091-go v1.8.1 // indirect github.com/sergi/go-diff v1.1.0 // indirect github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect github.com/skeema/knownhosts v1.1.1 // indirect diff --git a/go.sum b/go.sum index 8efaa6b12e1..815f2ff6261 100644 --- a/go.sum +++ b/go.sum @@ -404,6 +404,8 @@ github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8u github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/rabbitmq/amqp091-go v1.8.1 h1:RejT1SBUim5doqcL6s7iN6SBmsQqyTgXb1xMlH0h1hA= +github.com/rabbitmq/amqp091-go v1.8.1/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -443,12 +445,15 @@ github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= @@ -492,6 +497,7 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= diff --git a/packages/relayer/contracts/bridge/Bridge.go b/packages/relayer/bindings/bridge/Bridge.go similarity index 100% rename from packages/relayer/contracts/bridge/Bridge.go rename to packages/relayer/bindings/bridge/Bridge.go diff --git a/packages/relayer/contracts/erc1155vault/ERC1155Vault.go b/packages/relayer/bindings/erc1155vault/ERC1155Vault.go similarity index 100% rename from packages/relayer/contracts/erc1155vault/ERC1155Vault.go rename to packages/relayer/bindings/erc1155vault/ERC1155Vault.go diff --git a/packages/relayer/contracts/erc20vault/ERC20Vault.go b/packages/relayer/bindings/erc20vault/ERC20Vault.go similarity index 100% rename from packages/relayer/contracts/erc20vault/ERC20Vault.go rename to packages/relayer/bindings/erc20vault/ERC20Vault.go diff --git a/packages/relayer/contracts/erc721vault/ERC721Vault.go b/packages/relayer/bindings/erc721vault/ERC721Vault.go similarity index 100% rename from packages/relayer/contracts/erc721vault/ERC721Vault.go rename to packages/relayer/bindings/erc721vault/ERC721Vault.go diff --git a/packages/relayer/contracts/icrosschainsync/ICrossChainSync.go b/packages/relayer/bindings/icrosschainsync/ICrossChainSync.go similarity index 100% rename from packages/relayer/contracts/icrosschainsync/ICrossChainSync.go rename to packages/relayer/bindings/icrosschainsync/ICrossChainSync.go diff --git a/packages/relayer/contracts/taikol1/TaikoL1.go b/packages/relayer/bindings/taikol1/TaikoL1.go similarity index 100% rename from packages/relayer/contracts/taikol1/TaikoL1.go rename to packages/relayer/bindings/taikol1/TaikoL1.go diff --git a/packages/relayer/contracts/taikol2/TaikoL2.go b/packages/relayer/bindings/taikol2/TaikoL2.go similarity index 100% rename from packages/relayer/contracts/taikol2/TaikoL2.go rename to packages/relayer/bindings/taikol2/TaikoL2.go diff --git a/packages/relayer/bridge.go b/packages/relayer/bridge.go index 506a6eb282c..7f2b40da95b 100644 --- a/packages/relayer/bridge.go +++ b/packages/relayer/bridge.go @@ -6,7 +6,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/event" - "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/bridge" + "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/bridge" ) type Bridge interface { diff --git a/packages/relayer/cli/cli.go b/packages/relayer/cli/cli.go index 80dbd0e4185..c62a87893ca 100644 --- a/packages/relayer/cli/cli.go +++ b/packages/relayer/cli/cli.go @@ -20,6 +20,10 @@ import ( "github.com/taikoxyz/taiko-mono/packages/relayer/db" "github.com/taikoxyz/taiko-mono/packages/relayer/http" "github.com/taikoxyz/taiko-mono/packages/relayer/indexer" + "github.com/taikoxyz/taiko-mono/packages/relayer/processor" + "github.com/taikoxyz/taiko-mono/packages/relayer/proof" + "github.com/taikoxyz/taiko-mono/packages/relayer/queue" + "github.com/taikoxyz/taiko-mono/packages/relayer/queue/rabbitmq" "github.com/taikoxyz/taiko-mono/packages/relayer/repo" "gorm.io/driver/mysql" "gorm.io/gorm" @@ -58,6 +62,8 @@ func Run( layer relayer.Layer, httpOnly relayer.HTTPOnly, profitableOnly relayer.ProfitableOnly, + index relayer.Indexer, + process relayer.Processor, ) { if err := loadAndValidateEnv(); err != nil { log.Fatal(err) @@ -112,10 +118,9 @@ func Run( } }() - if !httpOnly { + if bool(index) && !bool(httpOnly) { indexers, closeFunc, err := makeIndexers(layer, db, profitableOnly) if err != nil { - sqlDB.Close() log.Fatal(err) } @@ -123,161 +128,44 @@ func Run( defer closeFunc() for _, i := range indexers { - go func(i *indexer.Service) { - if err := i.FilterThenSubscribe(context.Background(), mode, watchMode); err != nil { + go func(i *indexer.Indexer) { + if err := i.Start(context.Background(), mode, watchMode); err != nil { log.Fatal(err) } }(i) } - } - - <-forever -} - -func makeIndexers( - layer relayer.Layer, - db relayer.DB, - profitableOnly relayer.ProfitableOnly, -) ([]*indexer.Service, func(), error) { - eventRepository, err := repo.NewEventRepository(db) - if err != nil { - return nil, nil, err - } - - blockRepository, err := repo.NewBlockRepository(db) - if err != nil { - return nil, nil, err - } - - blockBatchSize, err := strconv.Atoi(os.Getenv("BLOCK_BATCH_SIZE")) - if err != nil || blockBatchSize <= 0 { - blockBatchSize = defaultBlockBatchSize - } - - numGoroutines, err := strconv.Atoi(os.Getenv("NUM_GOROUTINES")) - if err != nil || numGoroutines <= 0 { - numGoroutines = defaultNumGoroutines - } + } else if bool(process) && !bool(httpOnly) { + processors, closeFunc := makeProcessors(layer, db, profitableOnly) - var subscriptionBackoff time.Duration - - subscriptionBackoffInSeconds, err := strconv.Atoi(os.Getenv("SUBSCRIPTION_BACKOFF_IN_SECONDS")) - if err != nil || subscriptionBackoffInSeconds <= 0 { - subscriptionBackoff = defaultSubscriptionBackoff - } else { - subscriptionBackoff = time.Duration(subscriptionBackoffInSeconds) * time.Second - } - - headerSyncIntervalInSeconds, err := strconv.Atoi(os.Getenv("HEADER_SYNC_INTERVAL_IN_SECONDS")) - if err != nil || headerSyncIntervalInSeconds <= 0 { - headerSyncIntervalInSeconds = defaultHeaderSyncIntervalSeconds - } + defer sqlDB.Close() + defer closeFunc() - confirmations, err := strconv.Atoi(os.Getenv("CONFIRMATIONS_BEFORE_PROCESSING")) - if err != nil || confirmations <= 0 { - confirmations = defaultConfirmations + for _, p := range processors { + go func(p *processor.Processor) { + if err := p.Start(context.Background()); err != nil { + log.Fatal(err) + } + }(p) + } } - confirmationsTimeoutInSeconds, err := strconv.Atoi(os.Getenv("CONFIRMATIONS_TIMEOUT_IN_SECONDS")) - if err != nil || confirmationsTimeoutInSeconds <= 0 { - confirmationsTimeoutInSeconds = defaultConfirmationsTimeoutInSeconds - } + <-forever +} - l1EthClient, err := ethclient.Dial(os.Getenv("L1_RPC_URL")) - if err != nil { - log.Fatal(err) +func openQueue() (queue.Queue, error) { + opts := queue.NewQueueOpts{ + Username: os.Getenv("QUEUE_USERNAME"), + Password: os.Getenv("QUEUE_PASSWORD"), + Host: os.Getenv("QUEUE_HOST"), + Port: os.Getenv("QUEUE_PORT"), } - l2EthClient, err := ethclient.Dial(os.Getenv("L2_RPC_URL")) + q, err := rabbitmq.NewQueue(opts) if err != nil { log.Fatal(err) } - l1RpcClient, err := rpc.DialContext(context.Background(), os.Getenv("L1_RPC_URL")) - if err != nil { - return nil, nil, err - } - - l2RpcClient, err := rpc.DialContext(context.Background(), os.Getenv("L2_RPC_URL")) - if err != nil { - return nil, nil, err - } - - indexers := make([]*indexer.Service, 0) - - if layer == relayer.L1 || layer == relayer.Both { - l1Indexer, err := indexer.NewService(indexer.NewServiceOpts{ - EventRepo: eventRepository, - BlockRepo: blockRepository, - DestEthClient: l2EthClient, - EthClient: l1EthClient, - RPCClient: l1RpcClient, - DestRPCClient: l2RpcClient, - - ECDSAKey: os.Getenv("RELAYER_ECDSA_KEY"), - BridgeAddress: common.HexToAddress(os.Getenv("L1_BRIDGE_ADDRESS")), - DestBridgeAddress: common.HexToAddress(os.Getenv("L2_BRIDGE_ADDRESS")), - 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")), - DestERC20VaultAddress: common.HexToAddress(os.Getenv("L2_ERC20_VAULT_ADDRESS")), - DestERC721VaultAddress: common.HexToAddress(os.Getenv("L2_ERC721_VAULT_ADDRESS")), - DestERC1155VaultAddress: common.HexToAddress(os.Getenv("L2_ERC1155_VAULT_ADDRESS")), - BlockBatchSize: uint64(blockBatchSize), - NumGoroutines: numGoroutines, - SubscriptionBackoff: subscriptionBackoff, - Confirmations: uint64(confirmations), - ProfitableOnly: profitableOnly, - HeaderSyncIntervalInSeconds: int64(headerSyncIntervalInSeconds), - ConfirmationsTimeoutInSeconds: int64(confirmationsTimeoutInSeconds), - }) - if err != nil { - log.Fatal(err) - } - - indexers = append(indexers, l1Indexer) - } - - if layer == relayer.L2 || layer == relayer.Both { - l2Indexer, err := indexer.NewService(indexer.NewServiceOpts{ - EventRepo: eventRepository, - BlockRepo: blockRepository, - DestEthClient: l1EthClient, - EthClient: l2EthClient, - RPCClient: l2RpcClient, - DestRPCClient: l1RpcClient, - - ECDSAKey: os.Getenv("RELAYER_ECDSA_KEY"), - BridgeAddress: common.HexToAddress(os.Getenv("L2_BRIDGE_ADDRESS")), - 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")), - DestERC20VaultAddress: common.HexToAddress(os.Getenv("L1_ERC20_VAULT_ADDRESS")), - DestERC721VaultAddress: common.HexToAddress(os.Getenv("L1_ERC721_VAULT_ADDRESS")), - DestERC1155VaultAddress: common.HexToAddress(os.Getenv("L1_ERC1155_VAULT_ADDRESS")), - BlockBatchSize: uint64(blockBatchSize), - NumGoroutines: numGoroutines, - SubscriptionBackoff: subscriptionBackoff, - Confirmations: uint64(confirmations), - ProfitableOnly: profitableOnly, - HeaderSyncIntervalInSeconds: int64(headerSyncIntervalInSeconds), - ConfirmationsTimeoutInSeconds: int64(confirmationsTimeoutInSeconds), - }) - if err != nil { - log.Fatal(err) - } - - indexers = append(indexers, l2Indexer) - } - - closeFunc := func() { - l1EthClient.Close() - l2EthClient.Close() - l1RpcClient.Close() - l2RpcClient.Close() - } - - return indexers, closeFunc, nil + return q, nil } func openDBConnection(opts relayer.DBConnectionOpts) (relayer.DB, error) { @@ -390,3 +278,240 @@ func newHTTPServer(db relayer.DB, l1EthClient relayer.EthClient, l2EthClient rel return srv, nil } + +func makeIndexers( + layer relayer.Layer, + db relayer.DB, + profitableOnly relayer.ProfitableOnly, +) ([]*indexer.Indexer, func(), error) { + eventRepository, err := repo.NewEventRepository(db) + if err != nil { + return nil, nil, err + } + + blockRepository, err := repo.NewBlockRepository(db) + if err != nil { + return nil, nil, err + } + + blockBatchSize, err := strconv.Atoi(os.Getenv("BLOCK_BATCH_SIZE")) + if err != nil || blockBatchSize <= 0 { + blockBatchSize = defaultBlockBatchSize + } + + numGoroutines, err := strconv.Atoi(os.Getenv("NUM_GOROUTINES")) + if err != nil || numGoroutines <= 0 { + numGoroutines = defaultNumGoroutines + } + + var subscriptionBackoff time.Duration + + subscriptionBackoffInSeconds, err := strconv.Atoi(os.Getenv("SUBSCRIPTION_BACKOFF_IN_SECONDS")) + if err != nil || subscriptionBackoffInSeconds <= 0 { + subscriptionBackoff = defaultSubscriptionBackoff + } else { + subscriptionBackoff = time.Duration(subscriptionBackoffInSeconds) * time.Second + } + + l1EthClient, err := ethclient.Dial(os.Getenv("L1_RPC_URL")) + if err != nil { + log.Fatal(err) + } + + l2EthClient, err := ethclient.Dial(os.Getenv("L2_RPC_URL")) + if err != nil { + log.Fatal(err) + } + + l1RpcClient, err := rpc.DialContext(context.Background(), os.Getenv("L1_RPC_URL")) + if err != nil { + return nil, nil, err + } + + l2RpcClient, err := rpc.DialContext(context.Background(), os.Getenv("L2_RPC_URL")) + if err != nil { + return nil, nil, err + } + + indexers := make([]*indexer.Indexer, 0) + + q, err := openQueue() + if err != nil { + return nil, nil, err + } + + if layer == relayer.L1 || layer == relayer.Both { + l1Indexer, err := indexer.NewIndexer(indexer.NewIndexerOpts{ + EventRepo: eventRepository, + BlockRepo: blockRepository, + DestEthClient: l2EthClient, + EthClient: l1EthClient, + RPCClient: l1RpcClient, + BridgeAddress: common.HexToAddress(os.Getenv("L1_BRIDGE_ADDRESS")), + DestBridgeAddress: common.HexToAddress(os.Getenv("L2_BRIDGE_ADDRESS")), + SrcTaikoAddress: common.HexToAddress(os.Getenv("L1_TAIKO_ADDRESS")), + BlockBatchSize: uint64(blockBatchSize), + NumGoroutines: numGoroutines, + SubscriptionBackoff: subscriptionBackoff, + Queue: q, + }) + if err != nil { + log.Fatal(err) + } + + indexers = append(indexers, l1Indexer) + } + + if layer == relayer.L2 || layer == relayer.Both { + l2Indexer, err := indexer.NewIndexer(indexer.NewIndexerOpts{ + EventRepo: eventRepository, + BlockRepo: blockRepository, + DestEthClient: l1EthClient, + EthClient: l2EthClient, + RPCClient: l2RpcClient, + BridgeAddress: common.HexToAddress(os.Getenv("L2_BRIDGE_ADDRESS")), + DestBridgeAddress: common.HexToAddress(os.Getenv("L1_BRIDGE_ADDRESS")), + BlockBatchSize: uint64(blockBatchSize), + NumGoroutines: numGoroutines, + SubscriptionBackoff: subscriptionBackoff, + Queue: q, + }) + if err != nil { + log.Fatal(err) + } + + indexers = append(indexers, l2Indexer) + } + + closeFunc := func() { + l1EthClient.Close() + l2EthClient.Close() + l1RpcClient.Close() + l2RpcClient.Close() + } + + return indexers, closeFunc, nil +} + +func makeProcessors(layer relayer.Layer, + db relayer.DB, + profitableOnly relayer.ProfitableOnly, +) ([]*processor.Processor, func()) { + l1EthClient, err := ethclient.Dial(os.Getenv("L1_RPC_URL")) + if err != nil { + log.Fatal(err) + } + + l2EthClient, err := ethclient.Dial(os.Getenv("L2_RPC_URL")) + if err != nil { + log.Fatal(err) + } + + l1RpcClient, err := rpc.DialContext(context.Background(), os.Getenv("L1_RPC_URL")) + if err != nil { + log.Fatal(err) + } + + l2RpcClient, err := rpc.DialContext(context.Background(), os.Getenv("L2_RPC_URL")) + if err != nil { + log.Fatal(err) + } + + headerSyncIntervalInSeconds, err := strconv.Atoi(os.Getenv("HEADER_SYNC_INTERVAL_IN_SECONDS")) + if err != nil || headerSyncIntervalInSeconds <= 0 { + headerSyncIntervalInSeconds = defaultHeaderSyncIntervalSeconds + } + + confirmations, err := strconv.Atoi(os.Getenv("CONFIRMATIONS_BEFORE_PROCESSING")) + if err != nil || confirmations <= 0 { + confirmations = defaultConfirmations + } + + confirmationsTimeoutInSeconds, err := strconv.Atoi(os.Getenv("CONFIRMATIONS_TIMEOUT_IN_SECONDS")) + if err != nil || confirmationsTimeoutInSeconds <= 0 { + confirmationsTimeoutInSeconds = defaultConfirmationsTimeoutInSeconds + } + + eventRepository, err := repo.NewEventRepository(db) + if err != nil { + log.Fatal(err) + } + + q, err := openQueue() + if err != nil { + log.Fatal(err) + } + + processors := make([]*processor.Processor, 0) + + if layer == relayer.L1 || layer == relayer.Both { + prover, err := proof.New(l1EthClient) + if err != nil { + log.Fatal(err) + } + + processor, err := processor.NewProcessor(processor.NewProcessorOpts{ + Prover: prover, + ECDSAKey: os.Getenv("RELAYER_ECDSA_KEY"), + RPCClient: l1RpcClient, + SrcETHClient: l1EthClient, + DestETHClient: l2EthClient, + EventRepo: eventRepository, + Queue: q, + Confirmations: uint64(confirmations), + ProfitableOnly: profitableOnly, + HeaderSyncIntervalInSeconds: int64(headerSyncIntervalInSeconds), + ConfirmationsTimeoutInSeconds: int64(confirmationsTimeoutInSeconds), + DestERC20VaultAddress: common.HexToAddress(os.Getenv("L2_ERC20_VAULT_ADDRESS")), + DestERC721VaultAddress: common.HexToAddress(os.Getenv("L2_ERC721_VAULT_ADDRESS")), + DestERC1155VaultAddress: common.HexToAddress(os.Getenv("L2_ERC1155_VAULT_ADDRESS")), + DestTaikoAddress: common.HexToAddress(os.Getenv("L2_TAIKO_ADDRESS")), + SrcSignalServiceAddress: common.HexToAddress(os.Getenv("L1_SIGNAL_Service_ADDRESS")), + }) + if err != nil { + log.Fatal(err) + } + + processors = append(processors, processor) + } + + if layer == relayer.L2 || layer == relayer.Both { + prover, err := proof.New(l2EthClient) + if err != nil { + log.Fatal(err) + } + + processor, err := processor.NewProcessor(processor.NewProcessorOpts{ + Prover: prover, + ECDSAKey: os.Getenv("RELAYER_ECDSA_KEY"), + RPCClient: l2RpcClient, + SrcETHClient: l2EthClient, + DestETHClient: l1EthClient, + EventRepo: eventRepository, + Queue: q, + Confirmations: uint64(confirmations), + ProfitableOnly: profitableOnly, + HeaderSyncIntervalInSeconds: int64(headerSyncIntervalInSeconds), + ConfirmationsTimeoutInSeconds: int64(confirmationsTimeoutInSeconds), + DestERC20VaultAddress: common.HexToAddress(os.Getenv("L1_ERC20_VAULT_ADDRESS")), + DestERC721VaultAddress: common.HexToAddress(os.Getenv("L1_ERC721_VAULT_ADDRESS")), + DestERC1155VaultAddress: common.HexToAddress(os.Getenv("L1_ERC1155_VAULT_ADDRESS")), + DestTaikoAddress: common.HexToAddress(os.Getenv("L1_TAIKO_ADDRESS")), + SrcSignalServiceAddress: common.HexToAddress(os.Getenv("L2_SIGNAL_Service_ADDRESS")), + }) + if err != nil { + log.Fatal(err) + } + + processors = append(processors, processor) + } + + closeFunc := func() { + l1EthClient.Close() + l2EthClient.Close() + l1RpcClient.Close() + l2RpcClient.Close() + } + + return processors, closeFunc +} diff --git a/packages/relayer/cmd/main.go b/packages/relayer/cmd/main.go index e83c3888da3..e739894d504 100644 --- a/packages/relayer/cmd/main.go +++ b/packages/relayer/cmd/main.go @@ -42,8 +42,24 @@ func main() { false: `) + indexerPtr := flag.Bool("indexer", false, `whether to index transactions + options: + true: + false: + `) + + processorPtr := flag.Bool("processor", false, `whether to process transactions + options: + true: + false: + `) + flag.Parse() + if *indexerPtr && *processorPtr { + log.Fatal("can not index and process") + } + if !relayer.IsInSlice(relayer.Mode(*modePtr), relayer.Modes) { log.Fatal("mode not valid") } @@ -58,5 +74,7 @@ func main() { relayer.Layer(*layersPtr), relayer.HTTPOnly(*httpOnlyPtr), relayer.ProfitableOnly(*profitableOnlyPtr), + relayer.Indexer(*indexerPtr), + relayer.Processor(*processorPtr), ) } diff --git a/packages/relayer/flags.go b/packages/relayer/flags.go index 59cebcb1117..f7aa32b4120 100644 --- a/packages/relayer/flags.go +++ b/packages/relayer/flags.go @@ -29,3 +29,7 @@ var ( type HTTPOnly bool type ProfitableOnly bool + +type Indexer bool + +type Processor bool diff --git a/packages/relayer/indexer/detect_and_handle_reorg.go b/packages/relayer/indexer/detect_and_handle_reorg.go index 6ad827c3030..c82c75f1d99 100644 --- a/packages/relayer/indexer/detect_and_handle_reorg.go +++ b/packages/relayer/indexer/detect_and_handle_reorg.go @@ -8,8 +8,8 @@ import ( "log/slog" ) -func (svc *Service) detectAndHandleReorg(ctx context.Context, eventType string, msgHash string) error { - e, err := svc.eventRepo.FirstByEventAndMsgHash(ctx, eventType, msgHash) +func (i *Indexer) detectAndHandleReorg(ctx context.Context, eventType string, msgHash string) error { + e, err := i.eventRepo.FirstByEventAndMsgHash(ctx, eventType, msgHash) if err != nil { return errors.Wrap(err, "svc.eventRepo.FirstByMsgHash") } @@ -21,7 +21,7 @@ func (svc *Service) detectAndHandleReorg(ctx context.Context, eventType string, // reorg detected slog.Info("reorg detected", "msgHash", msgHash, "eventType", eventType) - err = svc.eventRepo.Delete(ctx, e.ID) + err = i.eventRepo.Delete(ctx, e.ID) if err != nil { return errors.Wrap(err, "svc.eventRepo.Delete") } diff --git a/packages/relayer/indexer/handle_event.go b/packages/relayer/indexer/handle_event.go index 8704dca06cb..d55bc695966 100644 --- a/packages/relayer/indexer/handle_event.go +++ b/packages/relayer/indexer/handle_event.go @@ -10,18 +10,19 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" "github.com/taikoxyz/taiko-mono/packages/relayer" - "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/bridge" + "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/bridge" + "github.com/taikoxyz/taiko-mono/packages/relayer/queue" ) // handleEvent handles an individual MessageSent event -func (svc *Service) handleEvent( +func (i *Indexer) handleEvent( ctx context.Context, chainID *big.Int, event *bridge.BridgeMessageSent, ) error { slog.Info("event found for msgHash", "msgHash", common.Hash(event.MsgHash).Hex(), "txHash", event.Raw.TxHash.Hex()) - if err := svc.detectAndHandleReorg(ctx, relayer.EventNameMessageSent, common.Hash(event.MsgHash).Hex()); err != nil { + if err := i.detectAndHandleReorg(ctx, relayer.EventNameMessageSent, common.Hash(event.MsgHash).Hex()); err != nil { return errors.Wrap(err, "svc.detectAndHandleReorg") } @@ -30,7 +31,7 @@ func (svc *Service) handleEvent( return nil } - eventStatus, err := svc.eventStatusFromMsgHash(ctx, event.Message.GasLimit, event.MsgHash) + eventStatus, err := i.eventStatusFromMsgHash(ctx, event.Message.GasLimit, event.MsgHash) if err != nil { return errors.Wrap(err, "svc.eventStatusFromMsgHash") } @@ -45,7 +46,7 @@ func (svc *Service) handleEvent( return errors.Wrap(err, "eventTypeAmountAndCanonicalTokenFromEvent(event)") } - e, err := svc.eventRepo.Save(ctx, relayer.SaveEventOpts{ + e, err := i.eventRepo.Save(ctx, relayer.SaveEventOpts{ Name: relayer.EventNameMessageSent, Data: string(marshaled), ChainID: chainID, @@ -64,50 +65,32 @@ func (svc *Service) handleEvent( return errors.Wrap(err, "svc.eventRepo.Save") } - if !canProcessMessage(ctx, eventStatus, event.Message.User, svc.relayerAddr) { - slog.Warn("cant process message", "msgHash", common.Hash(event.MsgHash).Hex(), "eventStatus", eventStatus) - return nil - } - - // process the message - if err := svc.processor.ProcessMessage(ctx, event, e); err != nil { - return errors.Wrap(err, "svc.processMessage") + // TODO: add to queue + msg := queue.QueueMessageBody{ + ID: e.ID, + Event: event, } - return nil -} - -func canProcessMessage( - ctx context.Context, - eventStatus relayer.EventStatus, - messageOwner common.Address, - relayerAddress common.Address, -) bool { - // we can not process, exit early - if eventStatus == relayer.EventStatusNewOnlyOwner { - if messageOwner != relayerAddress { - slog.Info("gasLimit == 0 and owner is not the current relayer key, can not process. continuing loop") - return false - } - - return true + marshalledMsg, err := json.Marshal(msg) + if err != nil { + return errors.Wrap(err, "json.Marshal") } - if eventStatus == relayer.EventStatusNew { - return true + if err := i.queue.Publish(ctx, marshalledMsg); err != nil { + return errors.Wrap(err, "i.queue.Publish") } - return false + return nil } -func (svc *Service) eventStatusFromMsgHash( +func (i *Indexer) eventStatusFromMsgHash( ctx context.Context, gasLimit *big.Int, signal [32]byte, ) (relayer.EventStatus, error) { var eventStatus relayer.EventStatus - messageStatus, err := svc.destBridge.GetMessageStatus(nil, signal) + messageStatus, err := i.destBridge.GetMessageStatus(nil, signal) if err != nil { return 0, errors.Wrap(err, "svc.destBridge.GetMessageStatus") } diff --git a/packages/relayer/indexer/handle_event_test.go b/packages/relayer/indexer/handle_event_test.go index a09ff9db718..b1c308ade21 100644 --- a/packages/relayer/indexer/handle_event_test.go +++ b/packages/relayer/indexer/handle_event_test.go @@ -11,76 +11,6 @@ import ( "github.com/taikoxyz/taiko-mono/packages/relayer/mock" ) -var ( - relayerAddr = common.HexToAddress("0x71C7656EC7ab88b098defB751B7401B5f6d8976F") -) - -func Test_canProcessMessage(t *testing.T) { - tests := []struct { - name string - eventStatus relayer.EventStatus - messageOwner common.Address - relayerAddress common.Address - want bool - }{ - { - "canProcess, eventStatusNew", - relayer.EventStatusNew, - relayerAddr, - relayerAddr, - true, - }, - { - "cantProcess, eventStatusDone", - relayer.EventStatusDone, - relayerAddr, - relayerAddr, - false, - }, - { - "cantProcess, eventStatusRetriable", - relayer.EventStatusRetriable, - relayerAddr, - relayerAddr, - false, - }, - { - "cantProcess, eventStatusNewOnlyOwner and relayer is not owner", - relayer.EventStatusNewOnlyOwner, - common.HexToAddress("0x"), - relayerAddr, - false, - }, - { - "cantProcess, eventStatusFailed", - relayer.EventStatusFailed, - common.HexToAddress("0x"), - relayerAddr, - false, - }, - { - "canProcess, eventStatusOnlyOwner and relayer address is owner", - relayer.EventStatusNewOnlyOwner, - relayerAddr, - relayerAddr, - true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - canProcess := canProcessMessage( - context.Background(), - tt.eventStatus, - tt.messageOwner, - tt.relayerAddress, - ) - - assert.Equal(t, tt.want, canProcess) - }) - } -} - func Test_eventStatusFromMsgHash(t *testing.T) { tests := []struct { name string diff --git a/packages/relayer/indexer/handle_no_events_in_batch.go b/packages/relayer/indexer/handle_no_events_in_batch.go index 71ef151c203..06edf8a89a0 100644 --- a/packages/relayer/indexer/handle_no_events_in_batch.go +++ b/packages/relayer/indexer/handle_no_events_in_batch.go @@ -12,19 +12,19 @@ import ( // handleNoEventsInBatch is used when an entire batch call has no events in the entire response, // and we need to update the latest block processed -func (svc *Service) handleNoEventsInBatch( +func (i *Indexer) handleNoEventsInBatch( ctx context.Context, chainID *big.Int, blockNumber int64, ) error { - header, err := svc.ethClient.HeaderByNumber(ctx, big.NewInt(blockNumber)) + header, err := i.ethClient.HeaderByNumber(ctx, big.NewInt(blockNumber)) if err != nil { return errors.Wrap(err, "svc.ethClient.HeaderByNumber") } slog.Info("setting last processed block", "blockNum", blockNumber, "headerHash", header.Hash().Hex()) - if err := svc.blockRepo.Save(relayer.SaveBlockOpts{ + if err := i.blockRepo.Save(relayer.SaveBlockOpts{ Height: uint64(blockNumber), Hash: header.Hash(), ChainID: chainID, @@ -35,7 +35,7 @@ func (svc *Service) handleNoEventsInBatch( relayer.BlocksProcessed.Inc() - svc.processingBlockHeight = uint64(blockNumber) + i.processingBlockHeight = uint64(blockNumber) return nil } diff --git a/packages/relayer/indexer/indexer.go b/packages/relayer/indexer/indexer.go new file mode 100644 index 00000000000..715eb88a981 --- /dev/null +++ b/packages/relayer/indexer/indexer.go @@ -0,0 +1,135 @@ +package indexer + +import ( + "context" + "math/big" + "time" + + "github.com/cyberhorsey/errors" + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/rpc" + "github.com/taikoxyz/taiko-mono/packages/relayer" + "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/bridge" + "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/taikol1" + "github.com/taikoxyz/taiko-mono/packages/relayer/queue" +) + +var ( + ZeroAddress = common.HexToAddress("0x0000000000000000000000000000000000000000") +) + +type ethClient interface { + ChainID(ctx context.Context) (*big.Int, error) + HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) + SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (ethereum.Subscription, error) +} + +type Indexer struct { + eventRepo relayer.EventRepository + blockRepo relayer.BlockRepository + ethClient ethClient + + processingBlockHeight uint64 + + bridge relayer.Bridge + destBridge relayer.Bridge + + blockBatchSize uint64 + numGoroutines int + subscriptionBackoff time.Duration + + taikol1 *taikol1.TaikoL1 + + queue queue.Queue + + srcChainId *big.Int +} + +type NewIndexerOpts struct { + EventRepo relayer.EventRepository + BlockRepo relayer.BlockRepository + Queue queue.Queue + EthClient ethClient + DestEthClient ethClient + RPCClient *rpc.Client + BridgeAddress common.Address + DestBridgeAddress common.Address + SrcTaikoAddress common.Address + BlockBatchSize uint64 + NumGoroutines int + SubscriptionBackoff time.Duration +} + +func NewIndexer(opts NewIndexerOpts) (*Indexer, error) { + if opts.EventRepo == nil { + return nil, relayer.ErrNoEventRepository + } + + if opts.BlockRepo == nil { + return nil, relayer.ErrNoBlockRepository + } + + if opts.EthClient == nil { + return nil, relayer.ErrNoEthClient + } + + if opts.DestEthClient == nil { + return nil, relayer.ErrNoEthClient + } + + if opts.BridgeAddress == ZeroAddress { + return nil, relayer.ErrNoBridgeAddress + } + + if opts.DestBridgeAddress == ZeroAddress { + return nil, relayer.ErrNoBridgeAddress + } + + if opts.RPCClient == nil { + return nil, relayer.ErrNoRPCClient + } + + srcBridge, err := bridge.NewBridge(opts.BridgeAddress, opts.EthClient.(*ethclient.Client)) + if err != nil { + return nil, errors.Wrap(err, "bridge.NewBridge") + } + + destBridge, err := bridge.NewBridge(opts.DestBridgeAddress, opts.DestEthClient.(*ethclient.Client)) + if err != nil { + return nil, errors.Wrap(err, "bridge.NewBridge") + } + + var taikoL1 *taikol1.TaikoL1 + if opts.SrcTaikoAddress != ZeroAddress { + taikoL1, err = taikol1.NewTaikoL1(opts.SrcTaikoAddress, opts.EthClient.(*ethclient.Client)) + if err != nil { + return nil, errors.Wrap(err, "taikol1.NewTaikoL1") + } + } + + chainID, err := opts.EthClient.ChainID(context.Background()) + if err != nil { + return nil, errors.Wrap(err, "opts.EthClient.ChainID") + } + + return &Indexer{ + blockRepo: opts.BlockRepo, + eventRepo: opts.EventRepo, + ethClient: opts.EthClient, + + bridge: srcBridge, + destBridge: destBridge, + taikol1: taikoL1, + + blockBatchSize: opts.BlockBatchSize, + numGoroutines: opts.NumGoroutines, + subscriptionBackoff: opts.SubscriptionBackoff, + + queue: opts.Queue, + + srcChainId: chainID, + }, nil +} diff --git a/packages/relayer/indexer/save_message_status_changed_events.go b/packages/relayer/indexer/save_message_status_changed_events.go index 9d9aa3843b1..ef8914b31e6 100644 --- a/packages/relayer/indexer/save_message_status_changed_events.go +++ b/packages/relayer/indexer/save_message_status_changed_events.go @@ -10,10 +10,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" "github.com/taikoxyz/taiko-mono/packages/relayer" - "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/bridge" + "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/bridge" ) -func (svc *Service) saveMessageStatusChangedEvents( +func (i *Indexer) saveMessageStatusChangedEvents( ctx context.Context, chainID *big.Int, events *bridge.BridgeMessageStatusChangedIterator, @@ -28,16 +28,16 @@ func (svc *Service) saveMessageStatusChangedEvents( slog.Info("messageStatusChanged", "msgHash", common.Hash(event.MsgHash).Hex()) - if err := svc.detectAndHandleReorg( + if err := i.detectAndHandleReorg( ctx, relayer.EventNameMessageStatusChanged, common.Hash(event.MsgHash).Hex(), ); err != nil { - return errors.Wrap(err, "svc.detectAndHandleReorg") + return errors.Wrap(err, "i.detectAndHandleReorg") } - if err := svc.saveMessageStatusChangedEvent(ctx, chainID, event); err != nil { - return errors.Wrap(err, "svc.saveMessageStatusChangedEvent") + if err := i.saveMessageStatusChangedEvent(ctx, chainID, event); err != nil { + return errors.Wrap(err, "i.saveMessageStatusChangedEvent") } if !events.Next() { @@ -46,7 +46,7 @@ func (svc *Service) saveMessageStatusChangedEvents( } } -func (svc *Service) saveMessageStatusChangedEvent( +func (i *Indexer) saveMessageStatusChangedEvent( ctx context.Context, chainID *big.Int, event *bridge.BridgeMessageStatusChanged, @@ -59,16 +59,16 @@ func (svc *Service) saveMessageStatusChangedEvent( // get the previous MessageSent event or other message status changed events, // so we can find out the previous owner of this msg hash, // to save to the db. - e, err := svc.eventRepo.FirstByMsgHash(ctx, common.Hash(event.MsgHash).Hex()) + e, err := i.eventRepo.FirstByMsgHash(ctx, common.Hash(event.MsgHash).Hex()) if err != nil { - return errors.Wrap(err, "svc.eventRepo.FirstByMsgHash") + return errors.Wrap(err, "i.eventRepo.FirstByMsgHash") } if e == nil || e.MsgHash == "" { return nil } - _, err = svc.eventRepo.Save(ctx, relayer.SaveEventOpts{ + _, err = i.eventRepo.Save(ctx, relayer.SaveEventOpts{ Name: relayer.EventNameMessageStatusChanged, Data: string(marshaled), ChainID: chainID, @@ -78,7 +78,7 @@ func (svc *Service) saveMessageStatusChangedEvent( Event: relayer.EventNameMessageStatusChanged, }) if err != nil { - return errors.Wrap(err, "svc.eventRepo.Save") + return errors.Wrap(err, "i.eventRepo.Save") } return nil diff --git a/packages/relayer/indexer/service.go b/packages/relayer/indexer/service.go deleted file mode 100644 index 92bad858ef2..00000000000 --- a/packages/relayer/indexer/service.go +++ /dev/null @@ -1,221 +0,0 @@ -package indexer - -import ( - "context" - "crypto/ecdsa" - "math/big" - "time" - - "github.com/cyberhorsey/errors" - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/rpc" - "github.com/taikoxyz/taiko-mono/packages/relayer" - "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/bridge" - "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/erc1155vault" - "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/erc20vault" - "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/erc721vault" - "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/message" - "github.com/taikoxyz/taiko-mono/packages/relayer/proof" -) - -var ( - ZeroAddress = common.HexToAddress("0x0000000000000000000000000000000000000000") -) - -type ethClient interface { - ChainID(ctx context.Context) (*big.Int, error) - HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) - SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (ethereum.Subscription, error) -} - -type Service struct { - eventRepo relayer.EventRepository - blockRepo relayer.BlockRepository - ethClient ethClient - destRPC *rpc.Client - - processingBlockHeight uint64 - - bridge relayer.Bridge - destBridge relayer.Bridge - - processor *message.Processor - - relayerAddr common.Address - - blockBatchSize uint64 - numGoroutines int - subscriptionBackoff time.Duration - - taikol1 *taikol1.TaikoL1 -} - -type NewServiceOpts struct { - EventRepo relayer.EventRepository - BlockRepo relayer.BlockRepository - EthClient *ethclient.Client - DestEthClient *ethclient.Client - RPCClient *rpc.Client - DestRPCClient *rpc.Client - ECDSAKey string - BridgeAddress common.Address - DestBridgeAddress common.Address - SrcTaikoAddress common.Address - DestTaikoAddress common.Address - DestERC20VaultAddress common.Address - DestERC721VaultAddress common.Address - DestERC1155VaultAddress common.Address - SrcSignalServiceAddress common.Address - BlockBatchSize uint64 - NumGoroutines int - SubscriptionBackoff time.Duration - Confirmations uint64 - ProfitableOnly relayer.ProfitableOnly - HeaderSyncIntervalInSeconds int64 - ConfirmationsTimeoutInSeconds int64 -} - -func NewService(opts NewServiceOpts) (*Service, error) { - if opts.EventRepo == nil { - return nil, relayer.ErrNoEventRepository - } - - if opts.BlockRepo == nil { - return nil, relayer.ErrNoBlockRepository - } - - if opts.EthClient == nil { - return nil, relayer.ErrNoEthClient - } - - if opts.ECDSAKey == "" { - return nil, relayer.ErrNoECDSAKey - } - - if opts.DestEthClient == nil { - return nil, relayer.ErrNoEthClient - } - - if opts.BridgeAddress == ZeroAddress { - return nil, relayer.ErrNoBridgeAddress - } - - if opts.DestBridgeAddress == ZeroAddress { - return nil, relayer.ErrNoBridgeAddress - } - - if opts.RPCClient == nil { - return nil, relayer.ErrNoRPCClient - } - - privateKey, err := crypto.HexToECDSA(opts.ECDSAKey) - if err != nil { - return nil, errors.Wrap(err, "crypto.HexToECDSA") - } - - publicKey := privateKey.Public() - - publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) - if !ok { - return nil, errors.Wrap(err, "publicKey.(*ecdsa.PublicKey)") - } - - relayerAddr := crypto.PubkeyToAddress(*publicKeyECDSA) - - srcBridge, err := bridge.NewBridge(opts.BridgeAddress, opts.EthClient) - if err != nil { - return nil, errors.Wrap(err, "bridge.NewBridge") - } - - destBridge, err := bridge.NewBridge(opts.DestBridgeAddress, opts.DestEthClient) - if err != nil { - return nil, errors.Wrap(err, "bridge.NewBridge") - } - - prover, err := proof.New(opts.EthClient) - if err != nil { - return nil, errors.Wrap(err, "proof.New") - } - - destHeaderSyncer, err := icrosschainsync.NewICrossChainSync(opts.DestTaikoAddress, opts.DestEthClient) - if err != nil { - 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, "taikol1.NewTaikoL1") - } - } - - destERC20Vault, err := erc20vault.NewERC20Vault(opts.DestERC20VaultAddress, opts.DestEthClient) - if err != nil { - return nil, errors.Wrap(err, "erc20vault.NewERC20Vault") - } - - var destERC721Vault *erc721vault.ERC721Vault - if opts.DestERC721VaultAddress.Hex() != relayer.ZeroAddress.Hex() { - destERC721Vault, err = erc721vault.NewERC721Vault(opts.DestERC721VaultAddress, opts.DestEthClient) - if err != nil { - return nil, errors.Wrap(err, "erc721vault.NewERC721Vault") - } - } - - var destERC1155Vault *erc1155vault.ERC1155Vault - if opts.DestERC1155VaultAddress.Hex() != relayer.ZeroAddress.Hex() { - destERC1155Vault, err = erc1155vault.NewERC1155Vault(opts.DestERC1155VaultAddress, opts.DestEthClient) - if err != nil { - return nil, errors.Wrap(err, "erc1155vault.NewERC1155Vault") - } - } - - processor, err := message.NewProcessor(message.NewProcessorOpts{ - Prover: prover, - ECDSAKey: privateKey, - RPCClient: opts.RPCClient, - DestETHClient: opts.DestEthClient, - DestBridge: destBridge, - EventRepo: opts.EventRepo, - DestHeaderSyncer: destHeaderSyncer, - RelayerAddress: relayerAddr, - Confirmations: opts.Confirmations, - SrcETHClient: opts.EthClient, - ProfitableOnly: opts.ProfitableOnly, - HeaderSyncIntervalSeconds: opts.HeaderSyncIntervalInSeconds, - SrcSignalServiceAddress: opts.SrcSignalServiceAddress, - ConfirmationsTimeoutInSeconds: opts.ConfirmationsTimeoutInSeconds, - DestERC20Vault: destERC20Vault, - DestERC721Vault: destERC721Vault, - DestERC1155Vault: destERC1155Vault, - }) - if err != nil { - return nil, errors.Wrap(err, "message.NewProcessor") - } - - return &Service{ - blockRepo: opts.BlockRepo, - eventRepo: opts.EventRepo, - ethClient: opts.EthClient, - destRPC: opts.DestRPCClient, - - bridge: srcBridge, - destBridge: destBridge, - taikol1: taikoL1, - - processor: processor, - - relayerAddr: relayerAddr, - - blockBatchSize: opts.BlockBatchSize, - numGoroutines: opts.NumGoroutines, - subscriptionBackoff: opts.SubscriptionBackoff, - }, nil -} diff --git a/packages/relayer/indexer/service_test.go b/packages/relayer/indexer/service_test.go index c7b6830a7c6..f4f72d61151 100644 --- a/packages/relayer/indexer/service_test.go +++ b/packages/relayer/indexer/service_test.go @@ -1,49 +1,14 @@ package indexer import ( - "errors" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/rpc" - "github.com/stretchr/testify/assert" "github.com/taikoxyz/taiko-mono/packages/relayer" - "github.com/taikoxyz/taiko-mono/packages/relayer/message" "github.com/taikoxyz/taiko-mono/packages/relayer/mock" - "github.com/taikoxyz/taiko-mono/packages/relayer/proof" - "github.com/taikoxyz/taiko-mono/packages/relayer/repo" ) -var dummyEcdsaKey = "8da4ef21b864d2cc526dbdb2a120bd2874c36c9d0a1fb7f8c63d7f7a8b41de8f" -var dummyAddress = "0x63FaC9201494f0bd17B9892B9fae4d52fe3BD377" - -func newTestService() (*Service, relayer.Bridge) { +func newTestService() (*Indexer, relayer.Bridge) { b := &mock.Bridge{} - privateKey, _ := crypto.HexToECDSA(dummyEcdsaKey) - - prover, _ := proof.New( - &mock.Blocker{}, - ) - - processor, _ := message.NewProcessor(message.NewProcessorOpts{ - EventRepo: &mock.EventRepository{}, - DestBridge: &mock.Bridge{}, - SrcETHClient: &mock.EthClient{}, - DestETHClient: &mock.EthClient{}, - DestERC20Vault: &mock.TokenVault{}, - DestERC721Vault: &mock.TokenVault{}, - DestERC1155Vault: &mock.TokenVault{}, - ECDSAKey: privateKey, - DestHeaderSyncer: &mock.HeaderSyncer{}, - Prover: prover, - RPCClient: &mock.Caller{}, - ConfirmationsTimeoutInSeconds: 900, - }) - - return &Service{ + return &Indexer{ blockRepo: &mock.BlockRepository{}, eventRepo: &mock.EventRepository{}, bridge: b, @@ -52,179 +17,8 @@ func newTestService() (*Service, relayer.Bridge) { numGoroutines: 10, processingBlockHeight: 0, - processor: processor, blockBatchSize: 100, - }, b -} -func Test_NewService(t *testing.T) { - tests := []struct { - name string - opts NewServiceOpts - wantErr error - }{ - { - "success", - NewServiceOpts{ - EventRepo: &repo.EventRepository{}, - BlockRepo: &repo.BlockRepository{}, - RPCClient: &rpc.Client{}, - EthClient: ðclient.Client{}, - DestEthClient: ðclient.Client{}, - ECDSAKey: dummyEcdsaKey, - BridgeAddress: common.HexToAddress(dummyAddress), - DestBridgeAddress: common.HexToAddress(dummyAddress), - Confirmations: 1, - ConfirmationsTimeoutInSeconds: 900, - }, - nil, - }, - { - "invalidECDSAKey", - NewServiceOpts{ - EventRepo: &repo.EventRepository{}, - BlockRepo: &repo.BlockRepository{}, - RPCClient: &rpc.Client{}, - EthClient: ðclient.Client{}, - DestEthClient: ðclient.Client{}, - ECDSAKey: ">>>", - BridgeAddress: common.HexToAddress(dummyAddress), - DestBridgeAddress: common.HexToAddress(dummyAddress), - Confirmations: 1, - ConfirmationsTimeoutInSeconds: 900, - }, - errors.New("crypto.HexToECDSA: invalid hex character '>' in private key"), - }, - { - "noRpcClient", - NewServiceOpts{ - EventRepo: &repo.EventRepository{}, - BlockRepo: &repo.BlockRepository{}, - EthClient: ðclient.Client{}, - DestEthClient: ðclient.Client{}, - ECDSAKey: dummyEcdsaKey, - BridgeAddress: common.HexToAddress(dummyAddress), - DestBridgeAddress: common.HexToAddress(dummyAddress), - Confirmations: 1, - ConfirmationsTimeoutInSeconds: 900, - }, - relayer.ErrNoRPCClient, - }, - { - "noBridgeAddress", - NewServiceOpts{ - EventRepo: &repo.EventRepository{}, - BlockRepo: &repo.BlockRepository{}, - EthClient: ðclient.Client{}, - DestEthClient: ðclient.Client{}, - ECDSAKey: dummyEcdsaKey, - RPCClient: &rpc.Client{}, - DestBridgeAddress: common.HexToAddress(dummyAddress), - Confirmations: 1, - ConfirmationsTimeoutInSeconds: 900, - }, - relayer.ErrNoBridgeAddress, - }, - { - "noDestBridgeAddress", - NewServiceOpts{ - EventRepo: &repo.EventRepository{}, - BlockRepo: &repo.BlockRepository{}, - EthClient: ðclient.Client{}, - DestEthClient: ðclient.Client{}, - ECDSAKey: dummyEcdsaKey, - RPCClient: &rpc.Client{}, - BridgeAddress: common.HexToAddress(dummyAddress), - Confirmations: 1, - ConfirmationsTimeoutInSeconds: 900, - }, - relayer.ErrNoBridgeAddress, - }, - { - "noECDSAKey", - NewServiceOpts{ - EventRepo: &repo.EventRepository{}, - BlockRepo: &repo.BlockRepository{}, - RPCClient: &rpc.Client{}, - EthClient: ðclient.Client{}, - DestEthClient: ðclient.Client{}, - BridgeAddress: common.HexToAddress(dummyAddress), - DestBridgeAddress: common.HexToAddress(dummyAddress), - Confirmations: 1, - ConfirmationsTimeoutInSeconds: 900, - }, - relayer.ErrNoECDSAKey, - }, - { - "noEventRepo", - NewServiceOpts{ - BlockRepo: &repo.BlockRepository{}, - EthClient: ðclient.Client{}, - ECDSAKey: dummyEcdsaKey, - DestEthClient: ðclient.Client{}, - BridgeAddress: common.HexToAddress(dummyAddress), - RPCClient: &rpc.Client{}, - DestBridgeAddress: common.HexToAddress(dummyAddress), - Confirmations: 1, - ConfirmationsTimeoutInSeconds: 900, - }, - relayer.ErrNoEventRepository, - }, - { - "noBlockRepo", - NewServiceOpts{ - EventRepo: &repo.EventRepository{}, - EthClient: ðclient.Client{}, - ECDSAKey: dummyEcdsaKey, - RPCClient: &rpc.Client{}, - DestEthClient: ðclient.Client{}, - BridgeAddress: common.HexToAddress(dummyAddress), - DestBridgeAddress: common.HexToAddress(dummyAddress), - Confirmations: 1, - ConfirmationsTimeoutInSeconds: 900, - }, - relayer.ErrNoBlockRepository, - }, - { - "noEthClient", - NewServiceOpts{ - EventRepo: &repo.EventRepository{}, - BlockRepo: &repo.BlockRepository{}, - ECDSAKey: dummyEcdsaKey, - RPCClient: &rpc.Client{}, - DestEthClient: ðclient.Client{}, - BridgeAddress: common.HexToAddress(dummyAddress), - DestBridgeAddress: common.HexToAddress(dummyAddress), - Confirmations: 1, - ConfirmationsTimeoutInSeconds: 900, - }, - relayer.ErrNoEthClient, - }, - { - "noDestEthClient", - NewServiceOpts{ - EventRepo: &repo.EventRepository{}, - BlockRepo: &repo.BlockRepository{}, - ECDSAKey: dummyEcdsaKey, - EthClient: ðclient.Client{}, - RPCClient: &rpc.Client{}, - BridgeAddress: common.HexToAddress(dummyAddress), - DestBridgeAddress: common.HexToAddress(dummyAddress), - Confirmations: 1, - ConfirmationsTimeoutInSeconds: 900, - }, - relayer.ErrNoEthClient, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - _, err := NewService(tt.opts) - if tt.wantErr != nil { - assert.EqualError(t, tt.wantErr, err.Error()) - } else { - assert.Nil(t, err) - } - }) - } + queue: &mock.Queue{}, + }, b } diff --git a/packages/relayer/indexer/set_initial_processing_block_by_mode.go b/packages/relayer/indexer/set_initial_processing_block_by_mode.go index b76e1d469ae..ca9e1b4c4e4 100644 --- a/packages/relayer/indexer/set_initial_processing_block_by_mode.go +++ b/packages/relayer/indexer/set_initial_processing_block_by_mode.go @@ -8,15 +8,15 @@ import ( "github.com/taikoxyz/taiko-mono/packages/relayer" ) -func (svc *Service) setInitialProcessingBlockByMode( +func (i *Indexer) setInitialProcessingBlockByMode( ctx context.Context, mode relayer.Mode, chainID *big.Int, ) error { var startingBlock uint64 = 0 - if svc.taikol1 != nil { - stateVars, err := svc.taikol1.GetStateVariables(nil) + if i.taikol1 != nil { + stateVars, err := i.taikol1.GetStateVariables(nil) if err != nil { return errors.Wrap(err, "svc.taikoL1.GetStateVariables") } @@ -27,7 +27,7 @@ func (svc *Service) setInitialProcessingBlockByMode( switch mode { case relayer.SyncMode: // get most recently processed block height from the DB - latestProcessedBlock, err := svc.blockRepo.GetLatestBlockProcessedForEvent( + latestProcessedBlock, err := i.blockRepo.GetLatestBlockProcessedForEvent( eventName, chainID, ) @@ -39,11 +39,11 @@ func (svc *Service) setInitialProcessingBlockByMode( startingBlock = latestProcessedBlock.Height } - svc.processingBlockHeight = startingBlock + i.processingBlockHeight = startingBlock return nil case relayer.ResyncMode: - svc.processingBlockHeight = startingBlock + i.processingBlockHeight = startingBlock return nil default: return relayer.ErrInvalidMode diff --git a/packages/relayer/indexer/filter_then_subscribe.go b/packages/relayer/indexer/start.go similarity index 60% rename from packages/relayer/indexer/filter_then_subscribe.go rename to packages/relayer/indexer/start.go index 2292bfc75d6..08548e91296 100644 --- a/packages/relayer/indexer/filter_then_subscribe.go +++ b/packages/relayer/indexer/start.go @@ -17,49 +17,57 @@ var ( eventName = relayer.EventNameMessageSent ) -// FilterThenSubscribe gets the most recent block height that has been indexed, and works it's way +func (i *Indexer) queueName() string { + return fmt.Sprintf("%v-queue", i.srcChainId.String()) +} + +// Start gets the most recent block height that has been indexed, and works it's way // up to the latest block. As it goes, it tries to process messages. // When it catches up, it then starts to Subscribe to latest events as they come in. -func (svc *Service) FilterThenSubscribe( +func (i *Indexer) Start( ctx context.Context, mode relayer.Mode, watchMode relayer.WatchMode, ) error { - chainID, err := svc.ethClient.ChainID(ctx) + if err := i.queue.Start(ctx, i.queueName()); err != nil { + return err + } + + chainID, err := i.ethClient.ChainID(ctx) if err != nil { - return errors.Wrap(err, "svc.ethClient.ChainID()") + return errors.Wrap(err, "i.ethClient.ChainID()") } - go scanBlocks(ctx, svc.ethClient, chainID) + go scanBlocks(ctx, i.ethClient, chainID) // if subscribing to new events, skip filtering and subscribe if watchMode == relayer.SubscribeWatchMode { - return svc.subscribe(ctx, chainID) + return i.subscribe(ctx, chainID) } - if err := svc.setInitialProcessingBlockByMode(ctx, mode, chainID); err != nil { - return errors.Wrap(err, "svc.setInitialProcessingBlockByMode") + if err := i.setInitialProcessingBlockByMode(ctx, mode, chainID); err != nil { + return errors.Wrap(err, "i.setInitialProcessingBlockByMode") } - header, err := svc.ethClient.HeaderByNumber(ctx, nil) + header, err := i.ethClient.HeaderByNumber(ctx, nil) if err != nil { - return errors.Wrap(err, "svc.ethClient.HeaderByNumber") + return errors.Wrap(err, "i.ethClient.HeaderByNumber") } - if svc.processingBlockHeight == header.Number.Uint64() { + if i.processingBlockHeight == header.Number.Uint64() { slog.Info("indexing caught up, subscribing to new incoming events", "chainID", chainID.Uint64()) - return svc.subscribe(ctx, chainID) + return i.subscribe(ctx, chainID) } slog.Info("fetching batch block events", "chainID", chainID.Uint64(), - "startblock", svc.processingBlockHeight, + "startblock", i.processingBlockHeight, "endblock", header.Number.Int64(), - "batchsize", svc.blockBatchSize, + "batchsize", i.blockBatchSize, ) - for i := svc.processingBlockHeight; i < header.Number.Uint64(); i += svc.blockBatchSize { - end := svc.processingBlockHeight + svc.blockBatchSize + for j := i.processingBlockHeight; j < header.Number.Uint64(); j += i.blockBatchSize { + end := i.processingBlockHeight + i.blockBatchSize // if the end of the batch is greater than the latest block number, set end // to the latest block number if end > header.Number.Uint64() { @@ -71,16 +79,16 @@ func (svc *Service) FilterThenSubscribe( // process up to end - 1 for this batch. filterEnd := end - 1 - fmt.Printf("block batch from %v to %v", i, filterEnd) + fmt.Printf("block batch from %v to %v", j, filterEnd) fmt.Println() filterOpts := &bind.FilterOpts{ - Start: svc.processingBlockHeight, + Start: i.processingBlockHeight, End: &filterEnd, Context: ctx, } - messageStatusChangedEvents, err := svc.bridge.FilterMessageStatusChanged(filterOpts, nil) + messageStatusChangedEvents, err := i.bridge.FilterMessageStatusChanged(filterOpts, nil) if err != nil { return errors.Wrap(err, "bridge.FilterMessageStatusChanged") } @@ -88,12 +96,12 @@ func (svc *Service) FilterThenSubscribe( // we dont need to do anything with msgStatus events except save them to the DB. // we dont need to process them. they are for exposing via the API. - err = svc.saveMessageStatusChangedEvents(ctx, chainID, messageStatusChangedEvents) + err = i.saveMessageStatusChangedEvents(ctx, chainID, messageStatusChangedEvents) if err != nil { return errors.Wrap(err, "bridge.saveMessageStatusChangedEvents") } - messageSentEvents, err := svc.bridge.FilterMessageSent(filterOpts, nil) + messageSentEvents, err := i.bridge.FilterMessageSent(filterOpts, nil) if err != nil { return errors.Wrap(err, "bridge.FilterMessageSent") } @@ -101,8 +109,8 @@ func (svc *Service) FilterThenSubscribe( if !messageSentEvents.Next() || messageSentEvents.Event == nil { // use "end" not "filterEnd" here, because it will be used as the start // of the next batch. - if err := svc.handleNoEventsInBatch(ctx, chainID, int64(end)); err != nil { - return errors.Wrap(err, "svc.handleNoEventsInBatch") + if err := i.handleNoEventsInBatch(ctx, chainID, int64(end)); err != nil { + return errors.Wrap(err, "i.handleNoEventsInBatch") } continue @@ -110,13 +118,13 @@ func (svc *Service) FilterThenSubscribe( group, groupCtx := errgroup.WithContext(ctx) - group.SetLimit(svc.numGoroutines) + group.SetLimit(i.numGoroutines) for { event := messageSentEvents.Event group.Go(func() error { - err := svc.handleEvent(groupCtx, chainID, event) + err := i.handleEvent(groupCtx, chainID, event) if err != nil { relayer.ErrorEvents.Inc() // log error but always return nil to keep other goroutines active @@ -134,8 +142,8 @@ func (svc *Service) FilterThenSubscribe( } // handle no events remaining, saving the processing block and restarting the for // loop - if err := svc.handleNoEventsInBatch(ctx, chainID, int64(end)); err != nil { - return errors.Wrap(err, "svc.handleNoEventsInBatch") + if err := i.handleNoEventsInBatch(ctx, chainID, int64(end)); err != nil { + return errors.Wrap(err, "i.handleNoEventsInBatch") } break @@ -148,13 +156,13 @@ func (svc *Service) FilterThenSubscribe( chainID.Uint64(), ) - latestBlock, err := svc.ethClient.HeaderByNumber(ctx, nil) + latestBlock, err := i.ethClient.HeaderByNumber(ctx, nil) if err != nil { - return errors.Wrap(err, "svc.ethclient.HeaderByNumber") + return errors.Wrap(err, "i.ethclient.HeaderByNumber") } - if svc.processingBlockHeight < latestBlock.Number.Uint64() { - return svc.FilterThenSubscribe(ctx, relayer.SyncMode, watchMode) + if i.processingBlockHeight < latestBlock.Number.Uint64() { + return i.Start(ctx, relayer.SyncMode, watchMode) } // we are caught up and specified not to subscribe, we can return now @@ -162,5 +170,5 @@ func (svc *Service) FilterThenSubscribe( return nil } - return svc.subscribe(ctx, chainID) + return i.subscribe(ctx, chainID) } diff --git a/packages/relayer/indexer/filter_then_subscribe_test.go b/packages/relayer/indexer/start_test.go similarity index 82% rename from packages/relayer/indexer/filter_then_subscribe_test.go rename to packages/relayer/indexer/start_test.go index 3d6841d2723..6efac142ceb 100644 --- a/packages/relayer/indexer/filter_then_subscribe_test.go +++ b/packages/relayer/indexer/start_test.go @@ -10,14 +10,14 @@ import ( "github.com/taikoxyz/taiko-mono/packages/relayer/mock" ) -func Test_FilterThenSubscribe(t *testing.T) { +func Test_Start(t *testing.T) { svc, bridge := newTestService() b := bridge.(*mock.Bridge) svc.processingBlockHeight = 0 go func() { - _ = svc.FilterThenSubscribe( + _ = svc.Start( context.Background(), relayer.Mode(relayer.SyncMode), relayer.FilterAndSubscribeWatchMode, @@ -31,12 +31,12 @@ func Test_FilterThenSubscribe(t *testing.T) { assert.Equal(t, b.ErrorsSent, 2) } -func Test_FilterThenSubscribe_subscribeWatchMode(t *testing.T) { +func Test_Start_subscribeWatchMode(t *testing.T) { svc, bridge := newTestService() b := bridge.(*mock.Bridge) go func() { - _ = svc.FilterThenSubscribe( + _ = svc.Start( context.Background(), relayer.Mode(relayer.SyncMode), relayer.SubscribeWatchMode, @@ -50,14 +50,14 @@ func Test_FilterThenSubscribe_subscribeWatchMode(t *testing.T) { assert.Equal(t, b.ErrorsSent, 2) } -func Test_FilterThenSubscribe_alreadyCaughtUp(t *testing.T) { +func Test_Start_alreadyCaughtUp(t *testing.T) { svc, bridge := newTestService() b := bridge.(*mock.Bridge) svc.processingBlockHeight = mock.LatestBlockNumber.Uint64() go func() { - _ = svc.FilterThenSubscribe( + _ = svc.Start( context.Background(), relayer.Mode(relayer.SyncMode), relayer.FilterAndSubscribeWatchMode, diff --git a/packages/relayer/indexer/subscribe.go b/packages/relayer/indexer/subscribe.go index decd325d7dd..c396915ae81 100644 --- a/packages/relayer/indexer/subscribe.go +++ b/packages/relayer/indexer/subscribe.go @@ -11,18 +11,18 @@ import ( "github.com/ethereum/go-ethereum/event" "github.com/pkg/errors" "github.com/taikoxyz/taiko-mono/packages/relayer" - "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/bridge" + "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/bridge" ) // subscribe subscribes to latest events -func (svc *Service) subscribe(ctx context.Context, chainID *big.Int) error { +func (i *Indexer) subscribe(ctx context.Context, chainID *big.Int) error { slog.Info("subscribing to new events") errChan := make(chan error) - go svc.subscribeMessageSent(ctx, chainID, errChan) + go i.subscribeMessageSent(ctx, chainID, errChan) - go svc.subscribeMessageStatusChanged(ctx, chainID, errChan) + go i.subscribeMessageStatusChanged(ctx, chainID, errChan) // nolint: gosimple for { @@ -38,17 +38,17 @@ func (svc *Service) subscribe(ctx context.Context, chainID *big.Int) error { } } -func (svc *Service) subscribeMessageSent(ctx context.Context, chainID *big.Int, errChan chan error) { +func (i *Indexer) subscribeMessageSent(ctx context.Context, chainID *big.Int, errChan chan error) { sink := make(chan *bridge.BridgeMessageSent) - sub := event.ResubscribeErr(svc.subscriptionBackoff, func(ctx context.Context, err error) (event.Subscription, error) { + sub := event.ResubscribeErr(i.subscriptionBackoff, func(ctx context.Context, err error) (event.Subscription, error) { if err != nil { - slog.Error("svc.bridge.WatchMessageSent", "error", err) + slog.Error("i.bridge.WatchMessageSent", "error", err) } slog.Info("resubscribing to WatchMessageSent events") - return svc.bridge.WatchMessageSent(&bind.WatchOpts{ + return i.bridge.WatchMessageSent(&bind.WatchOpts{ Context: ctx, }, sink, nil) }) @@ -65,28 +65,28 @@ func (svc *Service) subscribeMessageSent(ctx context.Context, chainID *big.Int, case event := <-sink: go func() { slog.Info("new message sent event", "msgHash", common.Hash(event.MsgHash).Hex(), "chainID", chainID.String()) - err := svc.handleEvent(ctx, chainID, event) + err := i.handleEvent(ctx, chainID, event) if err != nil { - slog.Error("svc.subscribe, svc.handleEvent", "error", err) + slog.Error("i.subscribe, i.handleEvent", "error", err) return } - block, err := svc.blockRepo.GetLatestBlockProcessedForEvent(relayer.EventNameMessageSent, chainID) + block, err := i.blockRepo.GetLatestBlockProcessedForEvent(relayer.EventNameMessageSent, chainID) if err != nil { - slog.Error("svc.subscribe, blockRepo.GetLatestBlockProcessedForEvent", "error", err) + slog.Error("i.subscribe, blockRepo.GetLatestBlockProcessedForEvent", "error", err) return } if block.Height < event.Raw.BlockNumber { - err = svc.blockRepo.Save(relayer.SaveBlockOpts{ + err = i.blockRepo.Save(relayer.SaveBlockOpts{ Height: event.Raw.BlockNumber, Hash: event.Raw.BlockHash, ChainID: chainID, EventName: relayer.EventNameMessageSent, }) if err != nil { - slog.Error("svc.subscribe, svc.blockRepo.Save", "error", err) + slog.Error("i.subscribe, i.blockRepo.Save", "error", err) return } @@ -97,16 +97,16 @@ func (svc *Service) subscribeMessageSent(ctx context.Context, chainID *big.Int, } } -func (svc *Service) subscribeMessageStatusChanged(ctx context.Context, chainID *big.Int, errChan chan error) { +func (i *Indexer) subscribeMessageStatusChanged(ctx context.Context, chainID *big.Int, errChan chan error) { sink := make(chan *bridge.BridgeMessageStatusChanged) - sub := event.ResubscribeErr(svc.subscriptionBackoff, func(ctx context.Context, err error) (event.Subscription, error) { + sub := event.ResubscribeErr(i.subscriptionBackoff, func(ctx context.Context, err error) (event.Subscription, error) { if err != nil { - slog.Error("svc.bridge.WatchMessageStatusChanged", "error", err) + slog.Error("i.bridge.WatchMessageStatusChanged", "error", err) } slog.Info("resubscribing to WatchMessageStatusChanged events") - return svc.bridge.WatchMessageStatusChanged(&bind.WatchOpts{ + return i.bridge.WatchMessageStatusChanged(&bind.WatchOpts{ Context: ctx, }, sink, nil) }) @@ -126,8 +126,8 @@ func (svc *Service) subscribeMessageStatusChanged(ctx context.Context, chainID * "chainID", chainID.String(), ) - if err := svc.saveMessageStatusChangedEvent(ctx, chainID, event); err != nil { - slog.Error("svc.subscribe, svc.saveMessageStatusChangedEvent", "error", err) + if err := i.saveMessageStatusChangedEvent(ctx, chainID, event); err != nil { + slog.Error("i.subscribe, i.saveMessageStatusChangedEvent", "error", err) } } } diff --git a/packages/relayer/message/process_message_test.go b/packages/relayer/message/process_message_test.go deleted file mode 100644 index d855f051900..00000000000 --- a/packages/relayer/message/process_message_test.go +++ /dev/null @@ -1,97 +0,0 @@ -package message - -import ( - "context" - "math/big" - "testing" - - "github.com/pkg/errors" - "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" -) - -func Test_sendProcessMessageCall(t *testing.T) { - p := newTestProcessor(true) - - _, err := p.sendProcessMessageCall( - context.Background(), - &bridge.BridgeMessageSent{ - Message: bridge.IBridgeMessage{ - DestChainId: mock.MockChainID, - Fee: new(big.Int).Add(mock.ProcessMessageTx.Cost(), big.NewInt(1)), - }, - }, []byte{}) - - assert.Nil(t, err) - - assert.Equal(t, p.destNonce, mock.PendingNonce) -} - -func Test_ProcessMessage_messageNotReceived(t *testing.T) { - p := newTestProcessor(true) - - err := p.ProcessMessage(context.Background(), &bridge.BridgeMessageSent{ - Message: bridge.IBridgeMessage{ - GasLimit: big.NewInt(1), - }, - }, &relayer.Event{}) - assert.EqualError(t, err, "message not received") -} - -func Test_ProcessMessage_gasLimit0(t *testing.T) { - p := newTestProcessor(true) - - err := p.ProcessMessage(context.Background(), &bridge.BridgeMessageSent{}, &relayer.Event{}) - assert.EqualError(t, errors.New("only user can process this, gasLimit set to 0"), err.Error()) -} - -func Test_ProcessMessage_noChainId(t *testing.T) { - p := newTestProcessor(true) - - err := p.ProcessMessage(context.Background(), &bridge.BridgeMessageSent{ - Message: bridge.IBridgeMessage{ - GasLimit: big.NewInt(1), - }, - MsgHash: mock.SuccessMsgHash, - }, &relayer.Event{}) - assert.EqualError(t, err, "p.sendProcessMessageCall: bind.NewKeyedTransactorWithChainID: no chain id specified") -} - -func Test_ProcessMessage(t *testing.T) { - p := newTestProcessor(true) - - err := p.ProcessMessage(context.Background(), &bridge.BridgeMessageSent{ - Message: bridge.IBridgeMessage{ - GasLimit: big.NewInt(1), - DestChainId: mock.MockChainID, - Fee: big.NewInt(1000000000), - SrcChainId: mock.MockChainID, - }, - MsgHash: mock.SuccessMsgHash, - }, &relayer.Event{}) - - assert.Nil( - t, - err, - ) -} - -// func Test_ProcessMessage_unprofitable(t *testing.T) { -// p := newTestProcessor(true) - -// err := p.ProcessMessage(context.Background(), &bridge.BridgeMessageSent{ -// Message: bridge.IBridgeMessage{ -// GasLimit: big.NewInt(1), -// DestChainId: mock.MockChainID, -// }, -// Signal: mock.SuccessMsgHash, -// }, &relayer.Event{}) - -// assert.EqualError( -// t, -// err, -// "p.sendProcessMessageCall: "+relayer.ErrUnprofitable.Error(), -// ) -// } diff --git a/packages/relayer/message/processor.go b/packages/relayer/message/processor.go deleted file mode 100644 index 4fe00c26f8a..00000000000 --- a/packages/relayer/message/processor.go +++ /dev/null @@ -1,140 +0,0 @@ -package message - -import ( - "context" - "crypto/ecdsa" - "math/big" - "sync" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - - "github.com/taikoxyz/taiko-mono/packages/relayer" - "github.com/taikoxyz/taiko-mono/packages/relayer/proof" -) - -type ethClient interface { - PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) - TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) - BlockNumber(ctx context.Context) (uint64, error) - HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) - SuggestGasPrice(ctx context.Context) (*big.Int, error) - SuggestGasTipCap(ctx context.Context) (*big.Int, error) -} - -type Processor struct { - eventRepo relayer.EventRepository - srcEthClient ethClient - destEthClient ethClient - rpc relayer.Caller - ecdsaKey *ecdsa.PrivateKey - - destBridge relayer.Bridge - destHeaderSyncer relayer.HeaderSyncer - destERC20Vault relayer.TokenVault - destERC1155Vault relayer.TokenVault - destERC721Vault relayer.TokenVault - - prover *proof.Prover - - mu *sync.Mutex - - destNonce uint64 - relayerAddr common.Address - srcSignalServiceAddress common.Address - confirmations uint64 - - profitableOnly relayer.ProfitableOnly - headerSyncIntervalSeconds int64 - - confTimeoutInSeconds int64 -} - -type NewProcessorOpts struct { - Prover *proof.Prover - ECDSAKey *ecdsa.PrivateKey - RPCClient relayer.Caller - SrcETHClient ethClient - DestETHClient ethClient - DestBridge relayer.Bridge - EventRepo relayer.EventRepository - DestHeaderSyncer relayer.HeaderSyncer - DestERC20Vault relayer.TokenVault - DestERC721Vault relayer.TokenVault - DestERC1155Vault relayer.TokenVault - RelayerAddress common.Address - SrcSignalServiceAddress common.Address - Confirmations uint64 - ProfitableOnly relayer.ProfitableOnly - HeaderSyncIntervalSeconds int64 - ConfirmationsTimeoutInSeconds int64 -} - -func NewProcessor(opts NewProcessorOpts) (*Processor, error) { - if opts.Prover == nil { - return nil, relayer.ErrNoProver - } - - if opts.ECDSAKey == nil { - return nil, relayer.ErrNoECDSAKey - } - - if opts.RPCClient == nil { - return nil, relayer.ErrNoRPCClient - } - - if opts.DestETHClient == nil { - return nil, relayer.ErrNoEthClient - } - - if opts.SrcETHClient == nil { - return nil, relayer.ErrNoEthClient - } - - if opts.DestBridge == nil { - return nil, relayer.ErrNoBridge - } - - if opts.EventRepo == nil { - return nil, relayer.ErrNoEventRepository - } - - if opts.DestHeaderSyncer == nil { - return nil, relayer.ErrNoTaikoL2 - } - - if opts.Confirmations == 0 { - return nil, relayer.ErrInvalidConfirmations - } - - if opts.ConfirmationsTimeoutInSeconds == 0 { - return nil, relayer.ErrInvalidConfirmationsTimeoutInSeconds - } - - return &Processor{ - eventRepo: opts.EventRepo, - prover: opts.Prover, - ecdsaKey: opts.ECDSAKey, - rpc: opts.RPCClient, - - srcEthClient: opts.SrcETHClient, - - destEthClient: opts.DestETHClient, - destBridge: opts.DestBridge, - destHeaderSyncer: opts.DestHeaderSyncer, - destERC20Vault: opts.DestERC20Vault, - destERC721Vault: opts.DestERC1155Vault, - destERC1155Vault: opts.DestERC721Vault, - - mu: &sync.Mutex{}, - - destNonce: 0, - relayerAddr: opts.RelayerAddress, - srcSignalServiceAddress: opts.SrcSignalServiceAddress, - confirmations: opts.Confirmations, - - profitableOnly: opts.ProfitableOnly, - headerSyncIntervalSeconds: opts.HeaderSyncIntervalSeconds, - confTimeoutInSeconds: opts.ConfirmationsTimeoutInSeconds, - }, nil -} diff --git a/packages/relayer/message/processor_test.go b/packages/relayer/message/processor_test.go deleted file mode 100644 index 6709ef6ab4c..00000000000 --- a/packages/relayer/message/processor_test.go +++ /dev/null @@ -1,226 +0,0 @@ -package message - -import ( - "crypto/ecdsa" - "sync" - "testing" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/rpc" - "github.com/taikoxyz/taiko-mono/packages/relayer" - "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/mock" - "github.com/taikoxyz/taiko-mono/packages/relayer/proof" - "github.com/taikoxyz/taiko-mono/packages/relayer/repo" - "gopkg.in/go-playground/assert.v1" -) - -var dummyEcdsaKey = "8da4ef21b864d2cc526dbdb2a120bd2874c36c9d0a1fb7f8c63d7f7a8b41de8f" - -func newTestProcessor(profitableOnly relayer.ProfitableOnly) *Processor { - privateKey, _ := crypto.HexToECDSA(dummyEcdsaKey) - - prover, _ := proof.New( - &mock.Blocker{}, - ) - - return &Processor{ - eventRepo: &mock.EventRepository{}, - destBridge: &mock.Bridge{}, - srcEthClient: &mock.EthClient{}, - destEthClient: &mock.EthClient{}, - destERC20Vault: &mock.TokenVault{}, - mu: &sync.Mutex{}, - ecdsaKey: privateKey, - destHeaderSyncer: &mock.HeaderSyncer{}, - prover: prover, - rpc: &mock.Caller{}, - profitableOnly: profitableOnly, - headerSyncIntervalSeconds: 1, - confTimeoutInSeconds: 900, - } -} -func Test_NewProcessor(t *testing.T) { - tests := []struct { - name string - opts NewProcessorOpts - wantErr error - }{ - { - "success", - NewProcessorOpts{ - Prover: &proof.Prover{}, - ECDSAKey: &ecdsa.PrivateKey{}, - RPCClient: &rpc.Client{}, - SrcETHClient: ðclient.Client{}, - DestETHClient: ðclient.Client{}, - DestBridge: &bridge.Bridge{}, - EventRepo: &repo.EventRepository{}, - DestHeaderSyncer: &icrosschainsync.ICrossChainSync{}, - Confirmations: 1, - ConfirmationsTimeoutInSeconds: 900, - }, - nil, - }, - { - "errNoConfirmationsTimeoutInSeconds", - NewProcessorOpts{ - Prover: &proof.Prover{}, - ECDSAKey: &ecdsa.PrivateKey{}, - RPCClient: &rpc.Client{}, - SrcETHClient: ðclient.Client{}, - DestETHClient: ðclient.Client{}, - DestBridge: &bridge.Bridge{}, - EventRepo: &repo.EventRepository{}, - DestHeaderSyncer: &icrosschainsync.ICrossChainSync{}, - Confirmations: 1, - }, - relayer.ErrInvalidConfirmationsTimeoutInSeconds, - }, - { - "errNoConfirmations", - NewProcessorOpts{ - Prover: &proof.Prover{}, - ECDSAKey: &ecdsa.PrivateKey{}, - RPCClient: &rpc.Client{}, - SrcETHClient: ðclient.Client{}, - DestETHClient: ðclient.Client{}, - DestBridge: &bridge.Bridge{}, - EventRepo: &repo.EventRepository{}, - DestHeaderSyncer: &icrosschainsync.ICrossChainSync{}, - ConfirmationsTimeoutInSeconds: 900, - }, - relayer.ErrInvalidConfirmations, - }, - { - "errNoSrcClient", - NewProcessorOpts{ - Prover: &proof.Prover{}, - ECDSAKey: &ecdsa.PrivateKey{}, - RPCClient: &rpc.Client{}, - DestETHClient: ðclient.Client{}, - DestBridge: &bridge.Bridge{}, - EventRepo: &repo.EventRepository{}, - DestHeaderSyncer: &icrosschainsync.ICrossChainSync{}, - Confirmations: 1, - ConfirmationsTimeoutInSeconds: 900, - }, - relayer.ErrNoEthClient, - }, - { - "errNoProver", - NewProcessorOpts{ - ECDSAKey: &ecdsa.PrivateKey{}, - RPCClient: &rpc.Client{}, - SrcETHClient: ðclient.Client{}, - DestETHClient: ðclient.Client{}, - DestBridge: &bridge.Bridge{}, - EventRepo: &repo.EventRepository{}, - Confirmations: 1, - DestHeaderSyncer: &icrosschainsync.ICrossChainSync{}, - ConfirmationsTimeoutInSeconds: 900, - }, - relayer.ErrNoProver, - }, - { - "errNoECDSAKey", - NewProcessorOpts{ - Prover: &proof.Prover{}, - - RPCClient: &rpc.Client{}, - SrcETHClient: ðclient.Client{}, - DestETHClient: ðclient.Client{}, - DestBridge: &bridge.Bridge{}, - EventRepo: &repo.EventRepository{}, - DestHeaderSyncer: &icrosschainsync.ICrossChainSync{}, - Confirmations: 1, - ConfirmationsTimeoutInSeconds: 900, - }, - relayer.ErrNoECDSAKey, - }, - { - "noRpcClient", - NewProcessorOpts{ - Prover: &proof.Prover{}, - ECDSAKey: &ecdsa.PrivateKey{}, - SrcETHClient: ðclient.Client{}, - DestETHClient: ðclient.Client{}, - DestBridge: &bridge.Bridge{}, - EventRepo: &repo.EventRepository{}, - DestHeaderSyncer: &icrosschainsync.ICrossChainSync{}, - Confirmations: 1, - ConfirmationsTimeoutInSeconds: 900, - }, - relayer.ErrNoRPCClient, - }, - { - "noDestEthClient", - NewProcessorOpts{ - Prover: &proof.Prover{}, - ECDSAKey: &ecdsa.PrivateKey{}, - RPCClient: &rpc.Client{}, - SrcETHClient: ðclient.Client{}, - DestBridge: &bridge.Bridge{}, - EventRepo: &repo.EventRepository{}, - DestHeaderSyncer: &icrosschainsync.ICrossChainSync{}, - Confirmations: 1, - ConfirmationsTimeoutInSeconds: 900, - }, - relayer.ErrNoEthClient, - }, - { - "errNoDestBridge", - NewProcessorOpts{ - Prover: &proof.Prover{}, - ECDSAKey: &ecdsa.PrivateKey{}, - RPCClient: &rpc.Client{}, - SrcETHClient: ðclient.Client{}, - DestETHClient: ðclient.Client{}, - EventRepo: &repo.EventRepository{}, - DestHeaderSyncer: &icrosschainsync.ICrossChainSync{}, - Confirmations: 1, - ConfirmationsTimeoutInSeconds: 900, - }, - relayer.ErrNoBridge, - }, - { - "errNoEventRepo", - NewProcessorOpts{ - Prover: &proof.Prover{}, - ECDSAKey: &ecdsa.PrivateKey{}, - RPCClient: &rpc.Client{}, - SrcETHClient: ðclient.Client{}, - DestETHClient: ðclient.Client{}, - DestBridge: &bridge.Bridge{}, - DestHeaderSyncer: &icrosschainsync.ICrossChainSync{}, - Confirmations: 1, - ConfirmationsTimeoutInSeconds: 900, - }, - relayer.ErrNoEventRepository, - }, - { - "errNoTaikoL2", - NewProcessorOpts{ - Prover: &proof.Prover{}, - ECDSAKey: &ecdsa.PrivateKey{}, - RPCClient: &rpc.Client{}, - SrcETHClient: ðclient.Client{}, - DestETHClient: ðclient.Client{}, - EventRepo: &repo.EventRepository{}, - DestBridge: &bridge.Bridge{}, - Confirmations: 1, - ConfirmationsTimeoutInSeconds: 900, - }, - relayer.ErrNoTaikoL2, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - _, err := NewProcessor(tt.opts) - assert.Equal(t, tt.wantErr, err) - }) - } -} diff --git a/packages/relayer/mock/bridge.go b/packages/relayer/mock/bridge.go index de0c2886751..245536be57b 100644 --- a/packages/relayer/mock/bridge.go +++ b/packages/relayer/mock/bridge.go @@ -10,7 +10,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/event" "github.com/taikoxyz/taiko-mono/packages/relayer" - "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/bridge" + "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/bridge" ) var ( diff --git a/packages/relayer/mock/queue.go b/packages/relayer/mock/queue.go new file mode 100644 index 00000000000..bf368ace81b --- /dev/null +++ b/packages/relayer/mock/queue.go @@ -0,0 +1,30 @@ +package mock + +import ( + "context" + + "github.com/taikoxyz/taiko-mono/packages/relayer/queue" +) + +type Queue struct { +} + +func (r *Queue) Start(ctx context.Context, queueName string) error { + return nil +} + +func (r *Queue) Close(ctx context.Context) { + +} + +func (r *Queue) Publish(ctx context.Context, msg []byte) error { + return nil +} + +func (r *Queue) Ack(ctx context.Context, msg queue.Message) error { + return nil +} + +func (r *Queue) Subscribe(ctx context.Context, msgChan chan<- queue.Message) error { + return nil +} diff --git a/packages/relayer/processor/can_process_message.go b/packages/relayer/processor/can_process_message.go new file mode 100644 index 00000000000..f4943d02440 --- /dev/null +++ b/packages/relayer/processor/can_process_message.go @@ -0,0 +1,32 @@ +package processor + +import ( + "context" + "log/slog" + + "github.com/ethereum/go-ethereum/common" + "github.com/taikoxyz/taiko-mono/packages/relayer" +) + +func canProcessMessage( + ctx context.Context, + eventStatus relayer.EventStatus, + messageOwner common.Address, + relayerAddress common.Address, +) bool { + // we can not process, exit early + if eventStatus == relayer.EventStatusNewOnlyOwner { + if messageOwner != relayerAddress { + slog.Info("gasLimit == 0 and owner is not the current relayer key, can not process. continuing loop") + return false + } + + return true + } + + if eventStatus == relayer.EventStatusNew { + return true + } + + return false +} diff --git a/packages/relayer/processor/can_process_message_test.go b/packages/relayer/processor/can_process_message_test.go new file mode 100644 index 00000000000..c9a9cf59f7f --- /dev/null +++ b/packages/relayer/processor/can_process_message_test.go @@ -0,0 +1,80 @@ +package processor + +import ( + "context" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" + "github.com/taikoxyz/taiko-mono/packages/relayer" +) + +var ( + relayerAddr = common.HexToAddress("0x71C7656EC7ab88b098defB751B7401B5f6d8976F") +) + +func Test_canProcessMessage(t *testing.T) { + tests := []struct { + name string + eventStatus relayer.EventStatus + messageOwner common.Address + relayerAddress common.Address + want bool + }{ + { + "canProcess, eventStatusNew", + relayer.EventStatusNew, + relayerAddr, + relayerAddr, + true, + }, + { + "cantProcess, eventStatusDone", + relayer.EventStatusDone, + relayerAddr, + relayerAddr, + false, + }, + { + "cantProcess, eventStatusRetriable", + relayer.EventStatusRetriable, + relayerAddr, + relayerAddr, + false, + }, + { + "cantProcess, eventStatusNewOnlyOwner and relayer is not owner", + relayer.EventStatusNewOnlyOwner, + common.HexToAddress("0x"), + relayerAddr, + false, + }, + { + "cantProcess, eventStatusFailed", + relayer.EventStatusFailed, + common.HexToAddress("0x"), + relayerAddr, + false, + }, + { + "canProcess, eventStatusOnlyOwner and relayer address is owner", + relayer.EventStatusNewOnlyOwner, + relayerAddr, + relayerAddr, + true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + canProcess := canProcessMessage( + context.Background(), + tt.eventStatus, + tt.messageOwner, + tt.relayerAddress, + ) + + assert.Equal(t, tt.want, canProcess) + }) + } +} diff --git a/packages/relayer/message/errors.go b/packages/relayer/processor/errors.go similarity index 97% rename from packages/relayer/message/errors.go rename to packages/relayer/processor/errors.go index 0bf2d406aeb..7b4fb23064e 100644 --- a/packages/relayer/message/errors.go +++ b/packages/relayer/processor/errors.go @@ -1,4 +1,4 @@ -package message +package processor import ( "math/big" diff --git a/packages/relayer/message/estimate_gas.go b/packages/relayer/processor/estimate_gas.go similarity index 89% rename from packages/relayer/message/estimate_gas.go rename to packages/relayer/processor/estimate_gas.go index bfb59609e9d..f5bf9793a14 100644 --- a/packages/relayer/message/estimate_gas.go +++ b/packages/relayer/processor/estimate_gas.go @@ -1,4 +1,4 @@ -package message +package processor import ( "context" @@ -6,7 +6,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/pkg/errors" - "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/bridge" + "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/bridge" ) func (p *Processor) estimateGas( diff --git a/packages/relayer/message/get_latest_nonce.go b/packages/relayer/processor/get_latest_nonce.go similarity index 95% rename from packages/relayer/message/get_latest_nonce.go rename to packages/relayer/processor/get_latest_nonce.go index 8dbba0bddef..6bf10c5715c 100644 --- a/packages/relayer/message/get_latest_nonce.go +++ b/packages/relayer/processor/get_latest_nonce.go @@ -1,4 +1,4 @@ -package message +package processor import ( "context" diff --git a/packages/relayer/message/get_latest_nonce_test.go b/packages/relayer/processor/get_latest_nonce_test.go similarity index 95% rename from packages/relayer/message/get_latest_nonce_test.go rename to packages/relayer/processor/get_latest_nonce_test.go index 720ddbd316b..cea74de61fc 100644 --- a/packages/relayer/message/get_latest_nonce_test.go +++ b/packages/relayer/processor/get_latest_nonce_test.go @@ -1,4 +1,4 @@ -package message +package processor import ( "context" diff --git a/packages/relayer/message/is_profitable.go b/packages/relayer/processor/is_profitable.go similarity index 86% rename from packages/relayer/message/is_profitable.go rename to packages/relayer/processor/is_profitable.go index 02a6a185496..e12ec3a0c5a 100644 --- a/packages/relayer/message/is_profitable.go +++ b/packages/relayer/processor/is_profitable.go @@ -1,4 +1,4 @@ -package message +package processor import ( "context" @@ -6,7 +6,7 @@ import ( "log/slog" - "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/bridge" + "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/bridge" ) func (p *Processor) isProfitable( diff --git a/packages/relayer/message/is_profitable_test.go b/packages/relayer/processor/is_profitable_test.go similarity index 93% rename from packages/relayer/message/is_profitable_test.go rename to packages/relayer/processor/is_profitable_test.go index 1b4d64d711b..4c137fe6f2b 100644 --- a/packages/relayer/message/is_profitable_test.go +++ b/packages/relayer/processor/is_profitable_test.go @@ -1,4 +1,4 @@ -package message +package processor import ( "context" @@ -6,7 +6,7 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/bridge" + "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/bridge" "github.com/taikoxyz/taiko-mono/packages/relayer/mock" ) diff --git a/packages/relayer/message/process_message.go b/packages/relayer/processor/process_message.go similarity index 86% rename from packages/relayer/message/process_message.go rename to packages/relayer/processor/process_message.go index bb52113778a..f1ac0143014 100644 --- a/packages/relayer/message/process_message.go +++ b/packages/relayer/processor/process_message.go @@ -1,8 +1,9 @@ -package message +package processor import ( "context" "encoding/hex" + "encoding/json" "fmt" "log/slog" "math/big" @@ -16,7 +17,8 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/pkg/errors" "github.com/taikoxyz/taiko-mono/packages/relayer" - "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/bridge" + "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/bridge" + "github.com/taikoxyz/taiko-mono/packages/relayer/queue" ) // Process prepares and calls `processMessage` on the bridge. @@ -24,20 +26,24 @@ import ( // then rlp-encoded and combined as a singular byte slice, // then abi encoded into a SignalProof struct as the contract // expects -func (p *Processor) ProcessMessage( +func (p *Processor) processMessage( ctx context.Context, - event *bridge.BridgeMessageSent, - e *relayer.Event, + msg queue.Message, ) error { - if event.Message.GasLimit == nil || event.Message.GasLimit.Cmp(common.Big0) == 0 { + msgBody := &queue.QueueMessageBody{} + if err := json.Unmarshal(msg.Body, msgBody); err != nil { + return errors.Wrap(err, "json.Unmarshal") + } + + if msgBody.Event.Message.GasLimit == nil || msgBody.Event.Message.GasLimit.Cmp(common.Big0) == 0 { return errors.New("only user can process this, gasLimit set to 0") } - if err := p.waitForConfirmations(ctx, event.Raw.TxHash, event.Raw.BlockNumber); err != nil { + if err := p.waitForConfirmations(ctx, msgBody.Event.Raw.TxHash, msgBody.Event.Raw.BlockNumber); err != nil { return errors.Wrap(err, "p.waitForConfirmations") } - if err := p.waitHeaderSynced(ctx, event); err != nil { + if err := p.waitHeaderSynced(ctx, msgBody.Event); err != nil { return errors.Wrap(err, "p.waitHeaderSynced") } @@ -49,8 +55,8 @@ func (p *Processor) ProcessMessage( } hashed := crypto.Keccak256( - event.Raw.Address.Bytes(), - event.MsgHash[:], + msgBody.Event.Raw.Address.Bytes(), + msgBody.Event.MsgHash[:], ) key := hex.EncodeToString(hashed) @@ -58,11 +64,11 @@ func (p *Processor) ProcessMessage( encodedSignalProof, err := p.prover.EncodedSignalProof(ctx, p.rpc, p.srcSignalServiceAddress, key, latestSyncedHeader) if err != nil { slog.Error("srcChainID: %v, destChainID: %v, txHash: %v: msgHash: %v, from: %v encountered signalProofError %v", - event.Message.SrcChainId.String(), - event.Message.DestChainId.String(), - event.Raw.TxHash.Hex(), - common.Hash(event.MsgHash).Hex(), - event.Message.User.Hex(), + msgBody.Event.Message.SrcChainId.String(), + msgBody.Event.Message.DestChainId.String(), + msgBody.Event.Raw.TxHash.Hex(), + common.Hash(msgBody.Event.MsgHash).Hex(), + msgBody.Event.Message.User.Hex(), err, ) @@ -74,7 +80,7 @@ func (p *Processor) ProcessMessage( // an issue with the signal generation. received, err := p.destBridge.IsMessageReceived(&bind.CallOpts{ Context: ctx, - }, event.MsgHash, event.Message.SrcChainId, encodedSignalProof) + }, msgBody.Event.MsgHash, msgBody.Event.Message.SrcChainId, encodedSignalProof) if err != nil { return errors.Wrap(err, "p.destBridge.IsMessageReceived") } @@ -82,8 +88,8 @@ func (p *Processor) ProcessMessage( // message will fail when we try to process it if !received { slog.Warn("Message not received on dest chain", - "msgHash", common.Hash(event.MsgHash).Hex(), - "srcChainId", event.Message.SrcChainId.String(), + "msgHash", common.Hash(msgBody.Event.MsgHash).Hex(), + "srcChainId", msgBody.Event.Message.SrcChainId.String(), ) relayer.MessagesNotReceivedOnDestChain.Inc() @@ -91,7 +97,7 @@ func (p *Processor) ProcessMessage( return errors.New("message not received") } - tx, err := p.sendProcessMessageCall(ctx, event, encodedSignalProof) + tx, err := p.sendProcessMessageCall(ctx, msgBody.Event, encodedSignalProof) if err != nil { return errors.Wrap(err, "p.sendProcessMessageCall") } @@ -107,13 +113,13 @@ func (p *Processor) ProcessMessage( return errors.Wrap(err, "relayer.WaitReceipt") } - if err := p.saveMessageStatusChangedEvent(ctx, receipt, e, event); err != nil { + if err := p.saveMessageStatusChangedEvent(ctx, receipt, msgBody.Event); err != nil { return errors.Wrap(err, "p.saveMEssageStatusChangedEvent") } slog.Info("Mined tx", "txHash", hex.EncodeToString(tx.Hash().Bytes())) - messageStatus, err := p.destBridge.GetMessageStatus(&bind.CallOpts{}, event.MsgHash) + messageStatus, err := p.destBridge.GetMessageStatus(&bind.CallOpts{}, msgBody.Event.MsgHash) if err != nil { return errors.Wrap(err, "p.destBridge.GetMessageStatus") } @@ -121,7 +127,7 @@ func (p *Processor) ProcessMessage( slog.Info( "updating message status", "status", relayer.EventStatus(messageStatus).String(), - "occuredtxHash", event.Raw.TxHash.Hex(), + "occuredtxHash", msgBody.Event.Raw.TxHash.Hex(), "processedTxHash", hex.EncodeToString(tx.Hash().Bytes()), ) @@ -132,10 +138,14 @@ func (p *Processor) ProcessMessage( } // update message status - if err := p.eventRepo.UpdateStatus(ctx, e.ID, relayer.EventStatus(messageStatus)); err != nil { + if err := p.eventRepo.UpdateStatus(ctx, msgBody.ID, relayer.EventStatus(messageStatus)); err != nil { return errors.Wrap(err, "s.eventRepo.UpdateStatus") } + if err := p.queue.Ack(ctx, msg); err != nil { + return errors.Wrap(err, "p.queue.Ack") + } + return nil } @@ -345,7 +355,6 @@ func (p *Processor) setLatestNonce(nonce uint64) { func (p *Processor) saveMessageStatusChangedEvent( ctx context.Context, receipt *types.Receipt, - e *relayer.Event, event *bridge.BridgeMessageSent, ) error { bridgeAbi, err := abi.JSON(strings.NewReader(bridge.BridgeABI)) @@ -376,8 +385,8 @@ func (p *Processor) saveMessageStatusChangedEvent( Data: data, ChainID: event.Message.DestChainId, Status: relayer.EventStatus(m["status"].(uint8)), - MsgHash: e.MsgHash, - MessageOwner: e.MessageOwner, + MsgHash: common.Hash(event.MsgHash).Hex(), + MessageOwner: event.Message.User.Hex(), Event: relayer.EventNameMessageStatusChanged, }) if err != nil { diff --git a/packages/relayer/processor/process_message_test.go b/packages/relayer/processor/process_message_test.go new file mode 100644 index 00000000000..6dd8f615b46 --- /dev/null +++ b/packages/relayer/processor/process_message_test.go @@ -0,0 +1,187 @@ +package processor + +import ( + "context" + "encoding/json" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/taikoxyz/taiko-mono/packages/relayer" + "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/bridge" + "github.com/taikoxyz/taiko-mono/packages/relayer/mock" + "github.com/taikoxyz/taiko-mono/packages/relayer/queue" +) + +func Test_sendProcessMessageCall(t *testing.T) { + p := newTestProcessor(true) + + _, err := p.sendProcessMessageCall( + context.Background(), + &bridge.BridgeMessageSent{ + Message: bridge.IBridgeMessage{ + DestChainId: mock.MockChainID, + Fee: new(big.Int).Add(mock.ProcessMessageTx.Cost(), big.NewInt(1)), + }, + Raw: types.Log{ + Address: relayer.ZeroAddress, + Topics: []common.Hash{ + relayer.ZeroHash, + }, + Data: []byte{0xff}, + }, + }, []byte{}) + + assert.Nil(t, err) + + assert.Equal(t, p.destNonce, mock.PendingNonce) +} + +func Test_ProcessMessage_messageNotReceived(t *testing.T) { + p := newTestProcessor(true) + body := &queue.QueueMessageBody{ + Event: &bridge.BridgeMessageSent{ + Message: bridge.IBridgeMessage{ + GasLimit: big.NewInt(1), + }, + Raw: types.Log{ + Address: relayer.ZeroAddress, + Topics: []common.Hash{ + relayer.ZeroHash, + }, + Data: []byte{0xff}, + }, + }, + ID: 0, + } + + marshalled, err := json.Marshal(body) + assert.Nil(t, err) + + msg := queue.Message{ + Body: marshalled, + } + + err = p.processMessage(context.Background(), msg) + assert.EqualError(t, err, "message not received") +} + +func Test_ProcessMessage_gasLimit0(t *testing.T) { + p := newTestProcessor(true) + + body := queue.QueueMessageBody{ + Event: &bridge.BridgeMessageSent{ + Message: bridge.IBridgeMessage{ + GasLimit: big.NewInt(0), + }, + Raw: types.Log{ + Address: relayer.ZeroAddress, + Topics: []common.Hash{ + relayer.ZeroHash, + }, + Data: []byte{0xff}, + }, + }, + ID: 0, + } + + marshalled, err := json.Marshal(body) + assert.Nil(t, err) + + msg := queue.Message{ + Body: marshalled, + } + + err = p.processMessage(context.Background(), msg) + assert.EqualError(t, errors.New("only user can process this, gasLimit set to 0"), err.Error()) +} + +func Test_ProcessMessage_noChainId(t *testing.T) { + p := newTestProcessor(true) + + body := queue.QueueMessageBody{ + Event: &bridge.BridgeMessageSent{ + Message: bridge.IBridgeMessage{ + GasLimit: big.NewInt(1), + }, + MsgHash: mock.SuccessMsgHash, + Raw: types.Log{ + Address: relayer.ZeroAddress, + Topics: []common.Hash{ + relayer.ZeroHash, + }, + Data: []byte{0xff}, + }, + }, + ID: 0, + } + + marshalled, err := json.Marshal(body) + assert.Nil(t, err) + + msg := queue.Message{ + Body: marshalled, + } + + err = p.processMessage(context.Background(), msg) + assert.EqualError(t, err, "p.sendProcessMessageCall: bind.NewKeyedTransactorWithChainID: no chain id specified") +} + +func Test_ProcessMessage(t *testing.T) { + p := newTestProcessor(true) + + body := queue.QueueMessageBody{ + Event: &bridge.BridgeMessageSent{ + Message: bridge.IBridgeMessage{ + GasLimit: big.NewInt(1), + DestChainId: mock.MockChainID, + Fee: big.NewInt(1000000000), + SrcChainId: mock.MockChainID, + }, + MsgHash: mock.SuccessMsgHash, + Raw: types.Log{ + Address: relayer.ZeroAddress, + Topics: []common.Hash{ + relayer.ZeroHash, + }, + Data: []byte{0xff}, + }, + }, + ID: 0, + } + + marshalled, err := json.Marshal(body) + assert.Nil(t, err) + + msg := queue.Message{ + Body: marshalled, + } + + err = p.processMessage(context.Background(), msg) + + assert.Nil( + t, + err, + ) +} + +// func Test_ProcessMessage_unprofitable(t *testing.T) { +// p := newTestProcessor(true) + +// err := p.ProcessMessage(context.Background(), &bridge.BridgeMessageSent{ +// Message: bridge.IBridgeMessage{ +// GasLimit: big.NewInt(1), +// DestChainId: mock.MockChainID, +// }, +// Signal: mock.SuccessMsgHash, +// }, &relayer.Event{}) + +// assert.EqualError( +// t, +// err, +// "p.sendProcessMessageCall: "+relayer.ErrUnprofitable.Error(), +// ) +// } diff --git a/packages/relayer/processor/processor.go b/packages/relayer/processor/processor.go new file mode 100644 index 00000000000..ad539175960 --- /dev/null +++ b/packages/relayer/processor/processor.go @@ -0,0 +1,252 @@ +package processor + +import ( + "context" + "crypto/ecdsa" + "fmt" + "log/slog" + "math/big" + "sync" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/pkg/errors" + + "github.com/taikoxyz/taiko-mono/packages/relayer" + "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/bridge" + "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/erc1155vault" + "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/erc20vault" + "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/erc721vault" + "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/icrosschainsync" + "github.com/taikoxyz/taiko-mono/packages/relayer/proof" + "github.com/taikoxyz/taiko-mono/packages/relayer/queue" +) + +type ethClient interface { + PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) + TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) + BlockNumber(ctx context.Context) (uint64, error) + HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) + SuggestGasPrice(ctx context.Context) (*big.Int, error) + SuggestGasTipCap(ctx context.Context) (*big.Int, error) + ChainID(ctx context.Context) (*big.Int, error) +} + +type Processor struct { + eventRepo relayer.EventRepository + + queue queue.Queue + + srcEthClient ethClient + destEthClient ethClient + rpc relayer.Caller + + ecdsaKey *ecdsa.PrivateKey + + destBridge relayer.Bridge + destHeaderSyncer relayer.HeaderSyncer + destERC20Vault relayer.TokenVault + destERC1155Vault relayer.TokenVault + destERC721Vault relayer.TokenVault + + prover *proof.Prover + + mu *sync.Mutex + + destNonce uint64 + relayerAddr common.Address + srcSignalServiceAddress common.Address + confirmations uint64 + + profitableOnly relayer.ProfitableOnly + headerSyncIntervalSeconds int64 + + confTimeoutInSeconds int64 + + msgCh chan queue.Message + + wg *sync.WaitGroup + + srcChainId *big.Int +} + +type NewProcessorOpts struct { + Prover *proof.Prover + ECDSAKey string + RPCClient relayer.Caller + SrcETHClient ethClient + DestETHClient ethClient + EventRepo relayer.EventRepository + Queue queue.Queue + DestBridgeAddress common.Address + DestTaikoAddress common.Address + DestERC20VaultAddress common.Address + DestERC721VaultAddress common.Address + DestERC1155VaultAddress common.Address + SrcSignalServiceAddress common.Address + Confirmations uint64 + ProfitableOnly relayer.ProfitableOnly + HeaderSyncIntervalInSeconds int64 + ConfirmationsTimeoutInSeconds int64 +} + +func NewProcessor(opts NewProcessorOpts) (*Processor, error) { + if opts.Prover == nil { + return nil, relayer.ErrNoProver + } + + if opts.ECDSAKey == "" { + return nil, relayer.ErrNoECDSAKey + } + + if opts.RPCClient == nil { + return nil, relayer.ErrNoRPCClient + } + + if opts.DestETHClient == nil { + return nil, relayer.ErrNoEthClient + } + + if opts.SrcETHClient == nil { + return nil, relayer.ErrNoEthClient + } + + if opts.EventRepo == nil { + return nil, relayer.ErrNoEventRepository + } + + if opts.Confirmations == 0 { + return nil, relayer.ErrInvalidConfirmations + } + + if opts.ConfirmationsTimeoutInSeconds == 0 { + return nil, relayer.ErrInvalidConfirmationsTimeoutInSeconds + } + + destHeaderSyncer, err := icrosschainsync.NewICrossChainSync( + opts.DestTaikoAddress, + opts.DestETHClient.(*ethclient.Client), + ) + if err != nil { + return nil, errors.Wrap(err, "icrosschainsync.NewTaikoL2") + } + + destERC20Vault, err := erc20vault.NewERC20Vault(opts.DestERC20VaultAddress, opts.DestETHClient.(*ethclient.Client)) + if err != nil { + return nil, errors.Wrap(err, "erc20vault.NewERC20Vault") + } + + var destERC721Vault *erc721vault.ERC721Vault + if opts.DestERC721VaultAddress.Hex() != relayer.ZeroAddress.Hex() { + destERC721Vault, err = erc721vault.NewERC721Vault(opts.DestERC721VaultAddress, opts.DestETHClient.(*ethclient.Client)) + if err != nil { + return nil, errors.Wrap(err, "erc721vault.NewERC721Vault") + } + } + + var destERC1155Vault *erc1155vault.ERC1155Vault + if opts.DestERC1155VaultAddress.Hex() != relayer.ZeroAddress.Hex() { + destERC1155Vault, err = erc1155vault.NewERC1155Vault( + opts.DestERC1155VaultAddress, + opts.DestETHClient.(*ethclient.Client), + ) + if err != nil { + return nil, errors.Wrap(err, "erc1155vault.NewERC1155Vault") + } + } + + destBridge, err := bridge.NewBridge(opts.DestBridgeAddress, opts.DestETHClient.(*ethclient.Client)) + if err != nil { + return nil, errors.Wrap(err, "bridge.NewBridge") + } + + privateKey, err := crypto.HexToECDSA(opts.ECDSAKey) + if err != nil { + return nil, errors.Wrap(err, "crypto.HexToECDSA") + } + + publicKey := privateKey.Public() + + publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) + if !ok { + return nil, errors.Wrap(err, "publicKey.(*ecdsa.PublicKey)") + } + + relayerAddr := crypto.PubkeyToAddress(*publicKeyECDSA) + + srcChainId, err := opts.SrcETHClient.ChainID(context.Background()) + if err != nil { + return nil, errors.Wrap(err, "opts.SrcETHClient.ChainID") + } + + return &Processor{ + eventRepo: opts.EventRepo, + prover: opts.Prover, + ecdsaKey: privateKey, + rpc: opts.RPCClient, + + srcEthClient: opts.SrcETHClient, + + destEthClient: opts.DestETHClient, + destBridge: destBridge, + destHeaderSyncer: destHeaderSyncer, + destERC20Vault: destERC20Vault, + destERC721Vault: destERC1155Vault, + destERC1155Vault: destERC721Vault, + + mu: &sync.Mutex{}, + + destNonce: 0, + relayerAddr: relayerAddr, + srcSignalServiceAddress: opts.SrcSignalServiceAddress, + confirmations: opts.Confirmations, + + profitableOnly: opts.ProfitableOnly, + headerSyncIntervalSeconds: opts.HeaderSyncIntervalInSeconds, + confTimeoutInSeconds: opts.ConfirmationsTimeoutInSeconds, + + queue: opts.Queue, + msgCh: make(chan queue.Message), + wg: &sync.WaitGroup{}, + + srcChainId: srcChainId, + }, nil +} + +func (p *Processor) Start(ctx context.Context) error { + if err := p.queue.Start(ctx, p.queueName()); err != nil { + return err + } + + if err := p.queue.Subscribe(ctx, p.msgCh); err != nil { + return err + } + + p.wg.Add(1) + go p.eventLoop(ctx) + + return nil +} + +func (p *Processor) queueName() string { + return fmt.Sprintf("%v-queue", p.srcChainId.String()) +} + +func (p *Processor) eventLoop(ctx context.Context) { + defer func() { + p.wg.Done() + }() + + for { + select { + case <-ctx.Done(): + return + case msg := <-p.msgCh: + if err := p.processMessage(ctx, msg); err != nil { + slog.Error("err processing message", "msg", msg) + } + } + } +} diff --git a/packages/relayer/processor/processor_test.go b/packages/relayer/processor/processor_test.go new file mode 100644 index 00000000000..1e6bb7c0dfd --- /dev/null +++ b/packages/relayer/processor/processor_test.go @@ -0,0 +1,71 @@ +package processor + +import ( + "sync" + "testing" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/rpc" + "github.com/taikoxyz/taiko-mono/packages/relayer" + "github.com/taikoxyz/taiko-mono/packages/relayer/mock" + "github.com/taikoxyz/taiko-mono/packages/relayer/proof" + "github.com/taikoxyz/taiko-mono/packages/relayer/repo" + "gopkg.in/go-playground/assert.v1" +) + +var dummyEcdsaKey = "8da4ef21b864d2cc526dbdb2a120bd2874c36c9d0a1fb7f8c63d7f7a8b41de8f" + +func newTestProcessor(profitableOnly relayer.ProfitableOnly) *Processor { + privateKey, _ := crypto.HexToECDSA(dummyEcdsaKey) + + prover, _ := proof.New( + &mock.Blocker{}, + ) + + return &Processor{ + eventRepo: &mock.EventRepository{}, + destBridge: &mock.Bridge{}, + srcEthClient: &mock.EthClient{}, + destEthClient: &mock.EthClient{}, + destERC20Vault: &mock.TokenVault{}, + mu: &sync.Mutex{}, + ecdsaKey: privateKey, + destHeaderSyncer: &mock.HeaderSyncer{}, + prover: prover, + rpc: &mock.Caller{}, + profitableOnly: profitableOnly, + headerSyncIntervalSeconds: 1, + confTimeoutInSeconds: 900, + confirmations: 1, + queue: &mock.Queue{}, + } +} +func Test_NewProcessor(t *testing.T) { + tests := []struct { + name string + opts NewProcessorOpts + wantErr error + }{ + { + "success", + NewProcessorOpts{ + Prover: &proof.Prover{}, + RPCClient: &rpc.Client{}, + SrcETHClient: ðclient.Client{}, + DestETHClient: ðclient.Client{}, + EventRepo: &repo.EventRepository{}, + Confirmations: 1, + ConfirmationsTimeoutInSeconds: 900, + }, + nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := NewProcessor(tt.opts) + assert.Equal(t, tt.wantErr, err) + }) + } +} diff --git a/packages/relayer/message/wait_for_confirmations.go b/packages/relayer/processor/wait_for_confirmations.go similarity index 96% rename from packages/relayer/message/wait_for_confirmations.go rename to packages/relayer/processor/wait_for_confirmations.go index d67adc93919..beca79400c4 100644 --- a/packages/relayer/message/wait_for_confirmations.go +++ b/packages/relayer/processor/wait_for_confirmations.go @@ -1,4 +1,4 @@ -package message +package processor import ( "context" diff --git a/packages/relayer/message/wait_for_confirmations_test.go b/packages/relayer/processor/wait_for_confirmations_test.go similarity index 94% rename from packages/relayer/message/wait_for_confirmations_test.go rename to packages/relayer/processor/wait_for_confirmations_test.go index 6b8f9a0e1be..e47135f0a15 100644 --- a/packages/relayer/message/wait_for_confirmations_test.go +++ b/packages/relayer/processor/wait_for_confirmations_test.go @@ -1,4 +1,4 @@ -package message +package processor import ( "context" diff --git a/packages/relayer/message/wait_header_synced.go b/packages/relayer/processor/wait_header_synced.go similarity index 95% rename from packages/relayer/message/wait_header_synced.go rename to packages/relayer/processor/wait_header_synced.go index 96497bda395..2c8465546ec 100644 --- a/packages/relayer/message/wait_header_synced.go +++ b/packages/relayer/processor/wait_header_synced.go @@ -1,4 +1,4 @@ -package message +package processor import ( "context" @@ -8,7 +8,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" - "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/bridge" + "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/bridge" ) func (p *Processor) waitHeaderSynced(ctx context.Context, event *bridge.BridgeMessageSent) error { diff --git a/packages/relayer/message/wait_header_synced_test.go b/packages/relayer/processor/wait_header_synced_test.go similarity index 79% rename from packages/relayer/message/wait_header_synced_test.go rename to packages/relayer/processor/wait_header_synced_test.go index 46c60b7892a..6ab4f2072dd 100644 --- a/packages/relayer/message/wait_header_synced_test.go +++ b/packages/relayer/processor/wait_header_synced_test.go @@ -1,4 +1,4 @@ -package message +package processor import ( "context" @@ -6,7 +6,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/assert" - "github.com/taikoxyz/taiko-mono/packages/relayer/contracts/bridge" + "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/bridge" ) func Test_waitHeaderSynced(t *testing.T) { diff --git a/packages/relayer/queue/queue.go b/packages/relayer/queue/queue.go new file mode 100644 index 00000000000..f5b5208b072 --- /dev/null +++ b/packages/relayer/queue/queue.go @@ -0,0 +1,32 @@ +package queue + +import ( + "context" + + "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/bridge" +) + +type Queue interface { + Start(ctx context.Context, queueName string) error + Close(ctx context.Context) + Publish(ctx context.Context, msg []byte) error + Subscribe(ctx context.Context, msgs chan<- Message) error + Ack(ctx context.Context, msg Message) error +} + +type QueueMessageBody struct { + Event *bridge.BridgeMessageSent + ID int +} + +type Message struct { + Body []byte + Internal interface{} +} + +type NewQueueOpts struct { + Username string + Password string + Host string + Port string +} diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go new file mode 100644 index 00000000000..9427839aa22 --- /dev/null +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -0,0 +1,130 @@ +package rabbitmq + +import ( + "context" + "fmt" + "log/slog" + + amqp "github.com/rabbitmq/amqp091-go" + "github.com/taikoxyz/taiko-mono/packages/relayer/queue" +) + +type RabbitMQ struct { + conn *amqp.Connection + ch *amqp.Channel + queue amqp.Queue +} + +func NewQueue(opts queue.NewQueueOpts) (*RabbitMQ, error) { + slog.Info("dialing rabbitmq connection") + + conn, err := amqp.Dial( + fmt.Sprintf( + "amqp://%v:%v@%v:%v/", + opts.Username, + opts.Password, + opts.Host, + opts.Port, + )) + if err != nil { + return nil, err + } + + ch, err := conn.Channel() + if err != nil { + return nil, err + } + + return &RabbitMQ{ + conn: conn, + ch: ch, + }, nil +} + +func (r *RabbitMQ) Start(ctx context.Context, queueName string) error { + slog.Info("declaring rabbitmq queue", "queue", queueName) + + q, err := r.ch.QueueDeclare( + queueName, + false, + false, + false, + false, + nil, + ) + if err != nil { + return err + } + + r.queue = q + + return nil +} + +func (r *RabbitMQ) Close(ctx context.Context) { + defer r.conn.Close() + defer r.ch.Close() +} + +func (r *RabbitMQ) Publish(ctx context.Context, msg []byte) error { + slog.Info("publishing rabbitmq msg to queue", "queue", r.queue.Name) + + err := r.ch.PublishWithContext(ctx, + "", + r.queue.Name, + false, + false, + amqp.Publishing{ + ContentType: "text/plain", + Body: msg, + }) + if err != nil { + return err + } + + return nil +} + +func (r *RabbitMQ) Ack(ctx context.Context, msg queue.Message) error { + rmqMsg := msg.Internal.(*amqp.Delivery) + + slog.Info("acknowledging rabbitmq message", "msgId", rmqMsg.MessageId) + + return rmqMsg.Ack(false) +} + +func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message) error { + msgs, err := r.ch.Consume( + r.queue.Name, + "", + false, // disable auto-acknowledge until after processing + false, + false, + false, + nil, + ) + + if err != nil { + return err + } + + // wrap internal msg chan with a generic queue + go func() { + for { + select { + case <-ctx.Done(): + return + case d := <-msgs: + slog.Info("rabbitmq message found", "msgId", d.MessageId) + { + msgChan <- queue.Message{ + Body: d.Body, + Internal: d, + } + } + } + } + }() + + return nil +} diff --git a/packages/relayer/abigen.sh b/packages/relayer/scripts/abigen.sh similarity index 94% rename from packages/relayer/abigen.sh rename to packages/relayer/scripts/abigen.sh index e20e84244aa..6344eb4ca6f 100755 --- a/packages/relayer/abigen.sh +++ b/packages/relayer/scripts/abigen.sh @@ -16,7 +16,7 @@ do abigen --abi ${names[i]}.json \ --pkg $lower \ --type ${names[i]} \ - --out contracts/$lower/${names[i]}.go + --out bindings/$lower/${names[i]}.go done exit 0 diff --git a/packages/relayer/scripts/install-rabbit-mq.sh b/packages/relayer/scripts/install-rabbit-mq.sh new file mode 100755 index 00000000000..52d438c7c33 --- /dev/null +++ b/packages/relayer/scripts/install-rabbit-mq.sh @@ -0,0 +1,44 @@ +#!/bin/sh + +sudo apt-get install curl gnupg apt-transport-https -y + +## Team RabbitMQ's main signing key +curl -1sLf "https://keys.openpgp.org/vks/v1/by-fingerprint/0A9AF2115F4687BD29803A206B73A36E6026DFCA" | sudo gpg --dearmor | sudo tee /usr/share/keyrings/com.rabbitmq.team.gpg > /dev/null +## Community mirror of Cloudsmith: modern Erlang repository +curl -1sLf https://ppa.novemberain.com/gpg.E495BB49CC4BBE5B.key | sudo gpg --dearmor | sudo tee /usr/share/keyrings/rabbitmq.E495BB49CC4BBE5B.gpg > /dev/null +## Community mirror of Cloudsmith: RabbitMQ repository +curl -1sLf https://ppa.novemberain.com/gpg.9F4587F226208342.key | sudo gpg --dearmor | sudo tee /usr/share/keyrings/rabbitmq.9F4587F226208342.gpg > /dev/null + +## Add apt repositories maintained by Team RabbitMQ +sudo tee /etc/apt/sources.list.d/rabbitmq.list < Date: Wed, 30 Aug 2023 10:10:44 -0700 Subject: [PATCH 03/82] wip cli refactor --- go.mod | 4 + go.sum | 2 + packages/relayer/cli/cli.go | 49 ++---------- packages/relayer/cli/cli_test.go | 25 ------- packages/relayer/cmd/flags/common.go | 94 ++++++++++++++++++++++++ packages/relayer/cmd/flags/indexer.go | 33 +++++++++ packages/relayer/cmd/flags/processor.go | 0 packages/relayer/mock/queue.go | 4 + packages/relayer/processor/processor.go | 4 + packages/relayer/queue/queue.go | 1 + packages/relayer/queue/rabbitmq/queue.go | 8 ++ 11 files changed, 155 insertions(+), 69 deletions(-) create mode 100644 packages/relayer/cmd/flags/common.go create mode 100644 packages/relayer/cmd/flags/indexer.go create mode 100644 packages/relayer/cmd/flags/processor.go diff --git a/go.mod b/go.mod index d887bc5342f..722cb1303de 100644 --- a/go.mod +++ b/go.mod @@ -48,6 +48,7 @@ require ( github.com/cloudflare/circl v1.3.3 // indirect github.com/containerd/containerd v1.6.19 // indirect github.com/cpuguy83/dockercfg v0.3.1 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/deckarep/golang-set/v2 v2.1.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/docker/distribution v2.8.2+incompatible // indirect @@ -101,15 +102,18 @@ require ( github.com/prometheus/common v0.39.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect github.com/rabbitmq/amqp091-go v1.8.1 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sergi/go-diff v1.1.0 // indirect github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect github.com/skeema/knownhosts v1.1.1 // indirect github.com/tklauser/go-sysconf v0.3.5 // indirect github.com/tklauser/numcpus v0.2.2 // indirect + github.com/urfave/cli/v2 v2.25.7 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.44.0 // indirect github.com/valyala/fasttemplate v1.2.1 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect golang.org/x/crypto v0.9.0 // indirect golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea // indirect golang.org/x/net v0.10.0 // indirect diff --git a/go.sum b/go.sum index 815f2ff6261..e022d54b134 100644 --- a/go.sum +++ b/go.sum @@ -471,6 +471,8 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa h1:5SqCsI/2Qya2bCzK15ozrqo2sZxkh0FHynJZOTVoV6Q= github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa/go.mod h1:1CNUng3PtjQMtRzJO4FMXBQvkGtuYRxxiR9xMa7jMwI= +github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= +github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.22.0/go.mod h1:0mw2RjXGOzxf4NL2jni3gUQ7LfjjUSiG5sskOUUSEpU= diff --git a/packages/relayer/cli/cli.go b/packages/relayer/cli/cli.go index c62a87893ca..cff7fe15fd9 100644 --- a/packages/relayer/cli/cli.go +++ b/packages/relayer/cli/cli.go @@ -14,8 +14,6 @@ import ( "github.com/labstack/echo/v4" "github.com/ethereum/go-ethereum/ethclient" - "github.com/joho/godotenv" - "github.com/pkg/errors" "github.com/taikoxyz/taiko-mono/packages/relayer" "github.com/taikoxyz/taiko-mono/packages/relayer/db" "github.com/taikoxyz/taiko-mono/packages/relayer/http" @@ -31,23 +29,6 @@ import ( ) var ( - envVars = []string{ - "HTTP_PORT", - "L1_BRIDGE_ADDRESS", - "L2_BRIDGE_ADDRESS", - "L2_TAIKO_ADDRESS", - "L1_ERC20_VAULT_ADDRESS", - "L2_ERC20_VAULT_ADDRESS", - "L1_RPC_URL", - "L2_RPC_URL", - "MYSQL_USER", - "MYSQL_DATABASE", - "MYSQL_HOST", - "RELAYER_ECDSA_KEY", - "CONFIRMATIONS_BEFORE_PROCESSING", - "PROMETHEUS_HTTP_PORT", - } - defaultBlockBatchSize = 2 defaultNumGoroutines = 10 defaultSubscriptionBackoff = 600 * time.Second @@ -65,10 +46,6 @@ func Run( index relayer.Indexer, process relayer.Processor, ) { - if err := loadAndValidateEnv(); err != nil { - log.Fatal(err) - } - db, err := openDBConnection(relayer.DBConnectionOpts{ Name: os.Getenv("MYSQL_USER"), Password: os.Getenv("MYSQL_PASSWORD"), @@ -234,25 +211,6 @@ func openDBConnection(opts relayer.DBConnectionOpts) (relayer.DB, error) { return db, nil } -func loadAndValidateEnv() error { - _ = godotenv.Load() - - missing := make([]string, 0) - - for _, v := range envVars { - e := os.Getenv(v) - if e == "" { - missing = append(missing, v) - } - } - - if len(missing) == 0 { - return nil - } - - return errors.Errorf("Missing env vars: %v", missing) -} - func newHTTPServer(db relayer.DB, l1EthClient relayer.EthClient, l2EthClient relayer.EthClient) (*http.Server, error) { eventRepo, err := repo.NewEventRepository(db) if err != nil { @@ -371,6 +329,7 @@ func makeIndexers( RPCClient: l2RpcClient, BridgeAddress: common.HexToAddress(os.Getenv("L2_BRIDGE_ADDRESS")), DestBridgeAddress: common.HexToAddress(os.Getenv("L1_BRIDGE_ADDRESS")), + SrcTaikoAddress: common.HexToAddress(os.Getenv("L2_TAIKO_ADDRESS")), BlockBatchSize: uint64(blockBatchSize), NumGoroutines: numGoroutines, SubscriptionBackoff: subscriptionBackoff, @@ -462,11 +421,12 @@ func makeProcessors(layer relayer.Layer, ProfitableOnly: profitableOnly, HeaderSyncIntervalInSeconds: int64(headerSyncIntervalInSeconds), ConfirmationsTimeoutInSeconds: int64(confirmationsTimeoutInSeconds), + DestBridgeAddress: common.HexToAddress(os.Getenv("L2_BRIDGE_ADDRESS")), DestERC20VaultAddress: common.HexToAddress(os.Getenv("L2_ERC20_VAULT_ADDRESS")), DestERC721VaultAddress: common.HexToAddress(os.Getenv("L2_ERC721_VAULT_ADDRESS")), DestERC1155VaultAddress: common.HexToAddress(os.Getenv("L2_ERC1155_VAULT_ADDRESS")), DestTaikoAddress: common.HexToAddress(os.Getenv("L2_TAIKO_ADDRESS")), - SrcSignalServiceAddress: common.HexToAddress(os.Getenv("L1_SIGNAL_Service_ADDRESS")), + SrcSignalServiceAddress: common.HexToAddress(os.Getenv("L1_SIGNAL_SERVICE_ADDRESS")), }) if err != nil { log.Fatal(err) @@ -493,11 +453,12 @@ func makeProcessors(layer relayer.Layer, ProfitableOnly: profitableOnly, HeaderSyncIntervalInSeconds: int64(headerSyncIntervalInSeconds), ConfirmationsTimeoutInSeconds: int64(confirmationsTimeoutInSeconds), + DestBridgeAddress: common.HexToAddress(os.Getenv("L1_BRIDGE_ADDRESS")), DestERC20VaultAddress: common.HexToAddress(os.Getenv("L1_ERC20_VAULT_ADDRESS")), DestERC721VaultAddress: common.HexToAddress(os.Getenv("L1_ERC721_VAULT_ADDRESS")), DestERC1155VaultAddress: common.HexToAddress(os.Getenv("L1_ERC1155_VAULT_ADDRESS")), DestTaikoAddress: common.HexToAddress(os.Getenv("L1_TAIKO_ADDRESS")), - SrcSignalServiceAddress: common.HexToAddress(os.Getenv("L2_SIGNAL_Service_ADDRESS")), + SrcSignalServiceAddress: common.HexToAddress(os.Getenv("L2_SIGNAL_SERVICE_ADDRESS")), }) if err != nil { log.Fatal(err) diff --git a/packages/relayer/cli/cli_test.go b/packages/relayer/cli/cli_test.go index 3ba1ee1181a..c3f464443ab 100644 --- a/packages/relayer/cli/cli_test.go +++ b/packages/relayer/cli/cli_test.go @@ -2,7 +2,6 @@ package cli import ( "os" - "strings" "testing" "github.com/stretchr/testify/assert" @@ -13,30 +12,6 @@ import ( var dummyEcdsaKey = "8da4ef21b864d2cc526dbdb2a120bd2874c36c9d0a1fb7f8c63d7f7a8b41de8f" var dummyAddress = "0x63FaC9201494f0bd17B9892B9fae4d52fe3BD377" -func Test_loadAndValidateEnvVars(t *testing.T) { - for _, envVar := range envVars { - os.Setenv(envVar, "valid") - } - - assert.Equal(t, loadAndValidateEnv(), nil) -} - -func Test_loadAndValidateEnvVars_missing(t *testing.T) { - for _, envVar := range envVars { - os.Setenv(envVar, "valid") - } - - for _, envVar := range envVars { - os.Setenv(envVar, "") - - err := loadAndValidateEnv() - - assert.NotEqual(t, err, nil) - assert.Equal(t, true, strings.Contains(err.Error(), envVar)) - os.Setenv(envVar, "valid") - } -} - func Test_openDBConnection(t *testing.T) { tests := []struct { name string diff --git a/packages/relayer/cmd/flags/common.go b/packages/relayer/cmd/flags/common.go new file mode 100644 index 00000000000..54380fd6302 --- /dev/null +++ b/packages/relayer/cmd/flags/common.go @@ -0,0 +1,94 @@ +package flags + +import ( + "github.com/urfave/cli/v2" +) + +var ( + commonCategory = "COMMON" + metricsCategory = "METRICS" + indexerCategory = "INDEXER" + processorCategory = "PROCESSOR" +) + +var ( + DatabaseUsername = &cli.StringFlag{ + Name: "db.username", + Usage: "Database connection username", + Required: true, + Category: commonCategory, + } + DatabasePassword = &cli.StringFlag{ + Name: "db.password", + Usage: "Database connection password", + Required: true, + Category: commonCategory, + } + DatabaseHost = &cli.StringFlag{ + Name: "db.host", + Usage: "Database connection host", + Required: true, + Category: commonCategory, + } + DatabaseName = &cli.StringFlag{ + Name: "db.name", + Usage: "Database connection name", + Required: true, + Category: commonCategory, + } + QueueUsername = &cli.StringFlag{ + Name: "queue.username", + Usage: "Queue connection username", + Required: true, + Category: commonCategory, + } + QueuePassword = &cli.StringFlag{ + Name: "queue.password", + Usage: "Queue connection password", + Required: true, + Category: commonCategory, + } + QueueHost = &cli.StringFlag{ + Name: "queue.host", + Usage: "Queue connection host", + Required: true, + Category: commonCategory, + } + QueuePort = &cli.StringFlag{ + Name: "queue.port", + Usage: "Queue connection port", + Required: true, + Category: commonCategory, + } +) + +// optional +var ( + CORSOrigins = &cli.StringFlag{ + Name: "http.corsOrigins", + Usage: "Comma-delinated list of cors origins", + Required: false, + Category: commonCategory, + } +) + +// All common flags. +var CommonFlags = []cli.Flag{ + DatabaseUsername, + DatabasePassword, + DatabaseHost, + DatabaseName, + QueueUsername, + QueuePassword, + QueueHost, + QueuePort, +} + +// MergeFlags merges the given flag slices. +func MergeFlags(groups ...[]cli.Flag) []cli.Flag { + var merged []cli.Flag + for _, group := range groups { + merged = append(merged, group...) + } + return merged +} diff --git a/packages/relayer/cmd/flags/indexer.go b/packages/relayer/cmd/flags/indexer.go new file mode 100644 index 00000000000..74477a2a8b5 --- /dev/null +++ b/packages/relayer/cmd/flags/indexer.go @@ -0,0 +1,33 @@ +package flags + +import ( + "github.com/urfave/cli/v2" +) + +var ( + BlockBatchSize = &cli.Uint64Flag{ + Name: "blockBatchSize", + Usage: "Block batch size when iterating through blocks", + Value: 10, + Category: indexerCategory, + EnvVars: []string{"BLOCK_BATCH_SIZE"}, + } + MaxNumGoroutines = &cli.Uint64Flag{ + Name: "maxNumGoroutines", + Usage: "Max number of goroutines to spawn simultaneously when indexing", + Value: 10, + Category: indexerCategory, + EnvVars: []string{"NUM_GOROUTINES"}, + } + SubscriptionBackoff = &cli.Uint64Flag{ + Name: "subscriptionBackoff", + Usage: "Subscription backoff in seconds", + Value: 30, + Category: indexerCategory, + EnvVars: []string{"SUBSCRIPTION_BACKOFF_IN_SECONDS"}, + } +) + +var IndexerFlags = MergeFlags(CommonFlags, []cli.Flag{ + BlockBatchSize, +}) diff --git a/packages/relayer/cmd/flags/processor.go b/packages/relayer/cmd/flags/processor.go new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/relayer/mock/queue.go b/packages/relayer/mock/queue.go index bf368ace81b..eb07b2b26c5 100644 --- a/packages/relayer/mock/queue.go +++ b/packages/relayer/mock/queue.go @@ -25,6 +25,10 @@ func (r *Queue) Ack(ctx context.Context, msg queue.Message) error { return nil } +func (r *Queue) Nack(ctx context.Context, msg queue.Message) error { + return nil +} + func (r *Queue) Subscribe(ctx context.Context, msgChan chan<- queue.Message) error { return nil } diff --git a/packages/relayer/processor/processor.go b/packages/relayer/processor/processor.go index ad539175960..2cd47ece90e 100644 --- a/packages/relayer/processor/processor.go +++ b/packages/relayer/processor/processor.go @@ -246,6 +246,10 @@ func (p *Processor) eventLoop(ctx context.Context) { case msg := <-p.msgCh: if err := p.processMessage(ctx, msg); err != nil { slog.Error("err processing message", "msg", msg) + + if err := p.queue.Nack(ctx, msg); err != nil { + slog.Error("Err nacking message", "msg", msg) + } } } } diff --git a/packages/relayer/queue/queue.go b/packages/relayer/queue/queue.go index f5b5208b072..f4da0a36071 100644 --- a/packages/relayer/queue/queue.go +++ b/packages/relayer/queue/queue.go @@ -12,6 +12,7 @@ type Queue interface { Publish(ctx context.Context, msg []byte) error Subscribe(ctx context.Context, msgs chan<- Message) error Ack(ctx context.Context, msg Message) error + Nack(ctx context.Context, msg Message) error } type QueueMessageBody struct { diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 9427839aa22..3f9d6da87b6 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -93,6 +93,14 @@ func (r *RabbitMQ) Ack(ctx context.Context, msg queue.Message) error { return rmqMsg.Ack(false) } +func (r *RabbitMQ) Nack(ctx context.Context, msg queue.Message) error { + rmqMsg := msg.Internal.(*amqp.Delivery) + + slog.Info("acknowledging rabbitmq message", "msgId", rmqMsg.MessageId) + + return rmqMsg.Nack(false, true) +} + func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message) error { msgs, err := r.ch.Consume( r.queue.Name, From f2f332d86e53797491faa781ba76f685d52130aa Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Wed, 30 Aug 2023 18:30:48 -0700 Subject: [PATCH 04/82] src/dest eth clients for http --- packages/relayer/http/get_block_info.go | 24 ++++---- packages/relayer/http/server.go | 42 ++++++++------ packages/relayer/http/server_test.go | 76 ++++++++++++------------- packages/relayer/indexer/indexer.go | 13 ++--- packages/relayer/types.go | 5 -- 5 files changed, 80 insertions(+), 80 deletions(-) diff --git a/packages/relayer/http/get_block_info.go b/packages/relayer/http/get_block_info.go index 0a87ea12478..5ff68ab8d26 100644 --- a/packages/relayer/http/get_block_info.go +++ b/packages/relayer/http/get_block_info.go @@ -19,32 +19,32 @@ type getBlockInfoResponse struct { } func (srv *Server) GetBlockInfo(c echo.Context) error { - l1ChainID, err := srv.l1EthClient.ChainID(c.Request().Context()) + srcChainID, err := srv.srcEthClient.ChainID(c.Request().Context()) if err != nil { return webutils.LogAndRenderErrors(c, http.StatusUnprocessableEntity, err) } - l2ChainID, err := srv.l2EthClient.ChainID(c.Request().Context()) + destChainID, err := srv.destEthClient.ChainID(c.Request().Context()) if err != nil { return webutils.LogAndRenderErrors(c, http.StatusUnprocessableEntity, err) } - latestL1Block, err := srv.l1EthClient.BlockNumber(c.Request().Context()) + latestSrcBlock, err := srv.srcEthClient.BlockNumber(c.Request().Context()) if err != nil { return webutils.LogAndRenderErrors(c, http.StatusUnprocessableEntity, err) } - latestL2Block, err := srv.l2EthClient.BlockNumber(c.Request().Context()) + latestDestBlock, err := srv.destEthClient.BlockNumber(c.Request().Context()) if err != nil { return webutils.LogAndRenderErrors(c, http.StatusUnprocessableEntity, err) } - latestProcessedL1Block, err := srv.blockRepo.GetLatestBlockProcessedForEvent(relayer.EventNameMessageSent, l1ChainID) + latestProcessedSrcBlock, err := srv.blockRepo.GetLatestBlockProcessedForEvent(relayer.EventNameMessageSent, srcChainID) if err != nil { return webutils.LogAndRenderErrors(c, http.StatusUnprocessableEntity, err) } - latestProcessedL2Block, err := srv.blockRepo.GetLatestBlockProcessedForEvent(relayer.EventNameMessageSent, l2ChainID) + latestProcessedDestBlock, err := srv.blockRepo.GetLatestBlockProcessedForEvent(relayer.EventNameMessageSent, destChainID) if err != nil { return webutils.LogAndRenderErrors(c, http.StatusUnprocessableEntity, err) } @@ -52,14 +52,14 @@ func (srv *Server) GetBlockInfo(c echo.Context) error { resp := getBlockInfoResponse{ Data: []blockInfo{ { - ChainID: l1ChainID.Int64(), - LatestProcessedBlock: int64(latestProcessedL1Block.Height), - LatestBlock: int64(latestL1Block), + ChainID: srcChainID.Int64(), + LatestProcessedBlock: int64(latestProcessedSrcBlock.Height), + LatestBlock: int64(latestSrcBlock), }, { - ChainID: l2ChainID.Int64(), - LatestProcessedBlock: int64(latestProcessedL2Block.Height), - LatestBlock: int64(latestL2Block), + ChainID: destChainID.Int64(), + LatestProcessedBlock: int64(latestProcessedDestBlock.Height), + LatestBlock: int64(latestDestBlock), }, }, } diff --git a/packages/relayer/http/server.go b/packages/relayer/http/server.go index b2244a96dc9..23b87e39ee1 100644 --- a/packages/relayer/http/server.go +++ b/packages/relayer/http/server.go @@ -3,6 +3,7 @@ package http import ( "context" "fmt" + "math/big" "net/http" "os" @@ -13,21 +14,26 @@ import ( echo "github.com/labstack/echo/v4" ) +type ethClient interface { + BlockNumber(ctx context.Context) (uint64, error) + ChainID(ctx context.Context) (*big.Int, error) +} + type Server struct { - echo *echo.Echo - eventRepo relayer.EventRepository - blockRepo relayer.BlockRepository - l1EthClient relayer.EthClient - l2EthClient relayer.EthClient + echo *echo.Echo + eventRepo relayer.EventRepository + blockRepo relayer.BlockRepository + srcEthClient ethClient + destEthClient ethClient } type NewServerOpts struct { - Echo *echo.Echo - EventRepo relayer.EventRepository - BlockRepo relayer.BlockRepository - CorsOrigins []string - L1EthClient relayer.EthClient - L2EthClient relayer.EthClient + Echo *echo.Echo + EventRepo relayer.EventRepository + BlockRepo relayer.BlockRepository + CorsOrigins []string + SrcEthClient ethClient + DestEthClient ethClient } func (opts NewServerOpts) Validate() error { @@ -43,11 +49,11 @@ func (opts NewServerOpts) Validate() error { return relayer.ErrNoCORSOrigins } - if opts.L1EthClient == nil { + if opts.SrcEthClient == nil { return relayer.ErrNoEthClient } - if opts.L2EthClient == nil { + if opts.DestEthClient == nil { return relayer.ErrNoEthClient } @@ -64,11 +70,11 @@ func NewServer(opts NewServerOpts) (*Server, error) { } srv := &Server{ - blockRepo: opts.BlockRepo, - echo: opts.Echo, - eventRepo: opts.EventRepo, - l1EthClient: opts.L1EthClient, - l2EthClient: opts.L2EthClient, + blockRepo: opts.BlockRepo, + echo: opts.Echo, + eventRepo: opts.EventRepo, + srcEthClient: opts.SrcEthClient, + destEthClient: opts.DestEthClient, } corsOrigins := opts.CorsOrigins diff --git a/packages/relayer/http/server_test.go b/packages/relayer/http/server_test.go index a3928b7818f..0a7d9701d55 100644 --- a/packages/relayer/http/server_test.go +++ b/packages/relayer/http/server_test.go @@ -38,78 +38,78 @@ func Test_NewServer(t *testing.T) { { "success", NewServerOpts{ - Echo: echo.New(), - EventRepo: &repo.EventRepository{}, - CorsOrigins: make([]string, 0), - L1EthClient: &mock.EthClient{}, - L2EthClient: &mock.EthClient{}, - BlockRepo: &mock.BlockRepository{}, + Echo: echo.New(), + EventRepo: &repo.EventRepository{}, + CorsOrigins: make([]string, 0), + SrcEthClient: &mock.EthClient{}, + DestEthClient: &mock.EthClient{}, + BlockRepo: &mock.BlockRepository{}, }, nil, }, { - "noL1EthClient", + "noSrcEthClient", NewServerOpts{ - Echo: echo.New(), - EventRepo: &repo.EventRepository{}, - CorsOrigins: make([]string, 0), - L2EthClient: &mock.EthClient{}, - BlockRepo: &mock.BlockRepository{}, + Echo: echo.New(), + EventRepo: &repo.EventRepository{}, + CorsOrigins: make([]string, 0), + DestEthClient: &mock.EthClient{}, + BlockRepo: &mock.BlockRepository{}, }, relayer.ErrNoEthClient, }, { - "noL2EthClient", + "noDestEthClient", NewServerOpts{ - Echo: echo.New(), - EventRepo: &repo.EventRepository{}, - CorsOrigins: make([]string, 0), - L1EthClient: &mock.EthClient{}, - BlockRepo: &mock.BlockRepository{}, + Echo: echo.New(), + EventRepo: &repo.EventRepository{}, + CorsOrigins: make([]string, 0), + SrcEthClient: &mock.EthClient{}, + BlockRepo: &mock.BlockRepository{}, }, relayer.ErrNoEthClient, }, { "noBlockRepo", NewServerOpts{ - Echo: echo.New(), - EventRepo: &repo.EventRepository{}, - CorsOrigins: make([]string, 0), - L1EthClient: &mock.EthClient{}, - L2EthClient: &mock.EthClient{}, + Echo: echo.New(), + EventRepo: &repo.EventRepository{}, + CorsOrigins: make([]string, 0), + SrcEthClient: &mock.EthClient{}, + DestEthClient: &mock.EthClient{}, }, relayer.ErrNoBlockRepository, }, { "noEventRepo", NewServerOpts{ - Echo: echo.New(), - CorsOrigins: make([]string, 0), - L1EthClient: &mock.EthClient{}, - L2EthClient: &mock.EthClient{}, - BlockRepo: &mock.BlockRepository{}, + Echo: echo.New(), + CorsOrigins: make([]string, 0), + SrcEthClient: &mock.EthClient{}, + DestEthClient: &mock.EthClient{}, + BlockRepo: &mock.BlockRepository{}, }, relayer.ErrNoEventRepository, }, { "noCorsOrigins", NewServerOpts{ - Echo: echo.New(), - EventRepo: &repo.EventRepository{}, - L1EthClient: &mock.EthClient{}, - L2EthClient: &mock.EthClient{}, - BlockRepo: &mock.BlockRepository{}, + Echo: echo.New(), + EventRepo: &repo.EventRepository{}, + SrcEthClient: &mock.EthClient{}, + DestEthClient: &mock.EthClient{}, + BlockRepo: &mock.BlockRepository{}, }, relayer.ErrNoCORSOrigins, }, { "noHttpFramework", NewServerOpts{ - EventRepo: &repo.EventRepository{}, - CorsOrigins: make([]string, 0), - L1EthClient: &mock.EthClient{}, - L2EthClient: &mock.EthClient{}, - BlockRepo: &mock.BlockRepository{}, + EventRepo: &repo.EventRepository{}, + CorsOrigins: make([]string, 0), + SrcEthClient: &mock.EthClient{}, + DestEthClient: &mock.EthClient{}, + BlockRepo: &mock.BlockRepository{}, }, ErrNoHTTPFramework, }, diff --git a/packages/relayer/indexer/indexer.go b/packages/relayer/indexer/indexer.go index 70088b8e4c4..fbb540fbd5a 100644 --- a/packages/relayer/indexer/indexer.go +++ b/packages/relayer/indexer/indexer.go @@ -125,13 +125,12 @@ func InitFromConfig(ctx context.Context, i *Indexer, cfg *Config) (err error) { } srv, err := http.NewServer(http.NewServerOpts{ - EventRepo: eventRepository, - Echo: echo.New(), - CorsOrigins: cfg.CORSOrigins, - // TODO: should src/dest now - L1EthClient: srcEthClient, - L2EthClient: destEthClient, - BlockRepo: blockRepository, + EventRepo: eventRepository, + Echo: echo.New(), + CorsOrigins: cfg.CORSOrigins, + SrcEthClient: srcEthClient, + DestEthClient: destEthClient, + BlockRepo: blockRepository, }) if err != nil { return err diff --git a/packages/relayer/types.go b/packages/relayer/types.go index 062c248e4df..5cb44606795 100644 --- a/packages/relayer/types.go +++ b/packages/relayer/types.go @@ -343,8 +343,3 @@ func (c CanonicalNFT) TokenDecimals() uint8 { func (c CanonicalNFT) ContractSymbol() string { return c.Symbol } - -type EthClient interface { - BlockNumber(ctx context.Context) (uint64, error) - ChainID(ctx context.Context) (*big.Int, error) -} From a1f03a7f883c151c92a9bdd653bbdfb14be1aaf2 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Wed, 30 Aug 2023 18:32:28 -0700 Subject: [PATCH 05/82] lint --- packages/relayer/http/get_block_info.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/relayer/http/get_block_info.go b/packages/relayer/http/get_block_info.go index 5ff68ab8d26..0861b182a0b 100644 --- a/packages/relayer/http/get_block_info.go +++ b/packages/relayer/http/get_block_info.go @@ -44,7 +44,10 @@ func (srv *Server) GetBlockInfo(c echo.Context) error { return webutils.LogAndRenderErrors(c, http.StatusUnprocessableEntity, err) } - latestProcessedDestBlock, err := srv.blockRepo.GetLatestBlockProcessedForEvent(relayer.EventNameMessageSent, destChainID) + latestProcessedDestBlock, err := srv.blockRepo.GetLatestBlockProcessedForEvent( + relayer.EventNameMessageSent, + destChainID, + ) if err != nil { return webutils.LogAndRenderErrors(c, http.StatusUnprocessableEntity, err) } From cdb8dea8a8df95b7039ef9d6f81331dbe8ab9e8b Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Thu, 31 Aug 2023 12:02:57 -0700 Subject: [PATCH 06/82] processor updates to urfave/cli and taiko-client architecture --- packages/relayer/cli/cli.go | 335 ------------------- packages/relayer/cmd/flags/indexer.go | 15 +- packages/relayer/cmd/flags/processor.go | 4 +- packages/relayer/cmd/main.go | 16 +- packages/relayer/indexer/config_test.go | 3 +- packages/relayer/processor/config.go | 131 ++++++++ packages/relayer/processor/config_test.go | 85 +++++ packages/relayer/processor/processor.go | 198 ++++++----- packages/relayer/processor/processor_test.go | 35 +- packages/relayer/queue/rabbitmq/queue.go | 4 +- 10 files changed, 346 insertions(+), 480 deletions(-) delete mode 100644 packages/relayer/cli/cli.go create mode 100644 packages/relayer/processor/config.go create mode 100644 packages/relayer/processor/config_test.go diff --git a/packages/relayer/cli/cli.go b/packages/relayer/cli/cli.go deleted file mode 100644 index a6c48109300..00000000000 --- a/packages/relayer/cli/cli.go +++ /dev/null @@ -1,335 +0,0 @@ -package cli - -// var ( -// defaultBlockBatchSize = 2 -// defaultNumGoroutines = 10 -// defaultSubscriptionBackoff = 600 * time.Second -// defaultConfirmations = 15 -// defaultHeaderSyncIntervalSeconds int = 60 -// defaultConfirmationsTimeoutInSeconds = 900 -// ) - -// func Run( -// mode relayer.Mode, -// watchMode relayer.WatchMode, -// layer relayer.Layer, -// httpOnly relayer.HTTPOnly, -// profitableOnly relayer.ProfitableOnly, -// index relayer.Indexer, -// process relayer.Processor, -// ) { -// db, err := openDBConnection(relayer.DBConnectionOpts{ -// Name: os.Getenv("MYSQL_USER"), -// Password: os.Getenv("MYSQL_PASSWORD"), -// Database: os.Getenv("MYSQL_DATABASE"), -// Host: os.Getenv("MYSQL_HOST"), -// OpenFunc: func(dsn string) (relayer.DB, error) { -// gormDB, err := gorm.Open(mysql.Open(dsn), &gorm.Config{ -// Logger: logger.Default.LogMode(logger.Silent), -// }) -// if err != nil { -// return nil, err -// } - -// return db.New(gormDB), nil -// }, -// }) - -// if err != nil { -// log.Fatal(err) -// } - -// sqlDB, err := db.DB() -// if err != nil { -// log.Fatal(err) -// } - -// l1EthClient, err := ethclient.Dial(os.Getenv("L1_RPC_URL")) -// if err != nil { -// log.Fatal(err) -// } - -// l2EthClient, err := ethclient.Dial(os.Getenv("L2_RPC_URL")) -// if err != nil { -// log.Fatal(err) -// } - -// srv, err := newHTTPServer(db, l1EthClient, l2EthClient) -// if err != nil { -// log.Fatal(err) -// } - -// forever := make(chan struct{}) - -// go func() { -// if err := srv.Start(fmt.Sprintf(":%v", os.Getenv("HTTP_PORT"))); err != nil { -// log.Fatal(err) -// } -// }() - -// if bool(index) && !bool(httpOnly) { -// indexers, closeFunc, err := makeIndexers(layer, db, profitableOnly) -// if err != nil { -// log.Fatal(err) -// } - -// defer sqlDB.Close() -// defer closeFunc() - -// for _, i := range indexers { -// go func(i *indexer.Indexer) { -// if err := i.Start(context.Background(), mode, watchMode); err != nil { -// log.Fatal(err) -// } -// }(i) -// } -// } else if bool(process) && !bool(httpOnly) { -// processors, closeFunc := makeProcessors(layer, db, profitableOnly) - -// defer sqlDB.Close() -// defer closeFunc() - -// for _, p := range processors { -// go func(p *processor.Processor) { -// if err := p.Start(context.Background()); err != nil { -// log.Fatal(err) -// } -// }(p) -// } -// } - -// <-forever -// } - -// func openQueue() (queue.Queue, error) { -// opts := queue.NewQueueOpts{ -// Username: os.Getenv("QUEUE_USERNAME"), -// Password: os.Getenv("QUEUE_PASSWORD"), -// Host: os.Getenv("QUEUE_HOST"), -// Port: os.Getenv("QUEUE_PORT"), -// } - -// q, err := rabbitmq.NewQueue(opts) -// if err != nil { -// log.Fatal(err) -// } - -// return q, nil -// } - -// func openDBConnection(opts relayer.DBConnectionOpts) (relayer.DB, error) { -// dsn := "" -// if opts.Password == "" { -// dsn = fmt.Sprintf( -// "%v@tcp(%v)/%v?charset=utf8mb4&parseTime=True&loc=Local", -// opts.Name, -// opts.Host, -// opts.Database, -// ) -// } else { -// dsn = fmt.Sprintf( -// "%v:%v@tcp(%v)/%v?charset=utf8mb4&parseTime=True&loc=Local", -// opts.Name, -// opts.Password, -// opts.Host, -// opts.Database, -// ) -// } - -// db, err := opts.OpenFunc(dsn) -// if err != nil { -// return nil, err -// } - -// sqlDB, err := db.DB() -// if err != nil { -// return nil, err -// } - -// var ( -// defaultMaxIdleConns = 50 -// defaultMaxOpenConns = 200 -// defaultConnMaxLifetime = 10 * time.Second -// ) - -// maxIdleConns, err := strconv.Atoi(os.Getenv("MYSQL_MAX_IDLE_CONNS")) -// if err != nil || maxIdleConns <= 0 { -// maxIdleConns = defaultMaxIdleConns -// } - -// maxOpenConns, err := strconv.Atoi(os.Getenv("MYSQL_MAX_OPEN_CONNS")) -// if err != nil || maxOpenConns <= 0 { -// maxOpenConns = defaultMaxOpenConns -// } - -// var maxLifetime time.Duration - -// connMaxLifetime, err := strconv.Atoi(os.Getenv("MYSQL_CONN_MAX_LIFETIME_IN_MS")) -// if err != nil || connMaxLifetime <= 0 { -// maxLifetime = defaultConnMaxLifetime -// } else { -// maxLifetime = time.Duration(connMaxLifetime) -// } - -// // SetMaxOpenConns sets the maximum number of open connections to the database. -// sqlDB.SetMaxOpenConns(maxOpenConns) - -// // SetMaxIdleConns sets the maximum number of connections in the idle connection pool. -// sqlDB.SetMaxIdleConns(maxIdleConns) - -// // SetConnMaxLifetime sets the maximum amount of time a connection may be reused. -// sqlDB.SetConnMaxLifetime(maxLifetime) - -// return db, nil -// } - -// func newHTTPServer(db relayer.DB, l1EthClient relayer.EthClient, l2EthClient relayer.EthClient) (*http.Server, error) { -// eventRepo, err := repo.NewEventRepository(db) -// if err != nil { -// return nil, err -// } - -// blockRepo, err := repo.NewBlockRepository(db) -// if err != nil { -// return nil, err -// } - -// srv, err := http.NewServer(http.NewServerOpts{ -// EventRepo: eventRepo, -// Echo: echo.New(), -// CorsOrigins: strings.Split(os.Getenv("CORS_ORIGINS"), ","), -// L1EthClient: l1EthClient, -// L2EthClient: l2EthClient, -// BlockRepo: blockRepo, -// }) -// if err != nil { -// return nil, err -// } - -// return srv, nil -// } - -// func makeProcessors(layer relayer.Layer, -// db relayer.DB, -// profitableOnly relayer.ProfitableOnly, -// ) ([]*processor.Processor, func()) { -// l1EthClient, err := ethclient.Dial(os.Getenv("L1_RPC_URL")) -// if err != nil { -// log.Fatal(err) -// } - -// l2EthClient, err := ethclient.Dial(os.Getenv("L2_RPC_URL")) -// if err != nil { -// log.Fatal(err) -// } - -// l1RpcClient, err := rpc.DialContext(context.Background(), os.Getenv("L1_RPC_URL")) -// if err != nil { -// log.Fatal(err) -// } - -// l2RpcClient, err := rpc.DialContext(context.Background(), os.Getenv("L2_RPC_URL")) -// if err != nil { -// log.Fatal(err) -// } - -// headerSyncIntervalInSeconds, err := strconv.Atoi(os.Getenv("HEADER_SYNC_INTERVAL_IN_SECONDS")) -// if err != nil || headerSyncIntervalInSeconds <= 0 { -// headerSyncIntervalInSeconds = defaultHeaderSyncIntervalSeconds -// } - -// confirmations, err := strconv.Atoi(os.Getenv("CONFIRMATIONS_BEFORE_PROCESSING")) -// if err != nil || confirmations <= 0 { -// confirmations = defaultConfirmations -// } - -// confirmationsTimeoutInSeconds, err := strconv.Atoi(os.Getenv("CONFIRMATIONS_TIMEOUT_IN_SECONDS")) -// if err != nil || confirmationsTimeoutInSeconds <= 0 { -// confirmationsTimeoutInSeconds = defaultConfirmationsTimeoutInSeconds -// } - -// eventRepository, err := repo.NewEventRepository(db) -// if err != nil { -// log.Fatal(err) -// } - -// q, err := openQueue() -// if err != nil { -// log.Fatal(err) -// } - -// processors := make([]*processor.Processor, 0) - -// if layer == relayer.L1 || layer == relayer.Both { -// prover, err := proof.New(l1EthClient) -// if err != nil { -// log.Fatal(err) -// } - -// processor, err := processor.NewProcessor(processor.NewProcessorOpts{ -// Prover: prover, -// ECDSAKey: os.Getenv("RELAYER_ECDSA_KEY"), -// RPCClient: l1RpcClient, -// SrcETHClient: l1EthClient, -// DestETHClient: l2EthClient, -// EventRepo: eventRepository, -// Queue: q, -// Confirmations: uint64(confirmations), -// ProfitableOnly: profitableOnly, -// HeaderSyncIntervalInSeconds: int64(headerSyncIntervalInSeconds), -// ConfirmationsTimeoutInSeconds: int64(confirmationsTimeoutInSeconds), -// DestBridgeAddress: common.HexToAddress(os.Getenv("L2_BRIDGE_ADDRESS")), -// DestERC20VaultAddress: common.HexToAddress(os.Getenv("L2_ERC20_VAULT_ADDRESS")), -// DestERC721VaultAddress: common.HexToAddress(os.Getenv("L2_ERC721_VAULT_ADDRESS")), -// DestERC1155VaultAddress: common.HexToAddress(os.Getenv("L2_ERC1155_VAULT_ADDRESS")), -// DestTaikoAddress: common.HexToAddress(os.Getenv("L2_TAIKO_ADDRESS")), -// SrcSignalServiceAddress: common.HexToAddress(os.Getenv("L1_SIGNAL_SERVICE_ADDRESS")), -// }) -// if err != nil { -// log.Fatal(err) -// } - -// processors = append(processors, processor) -// } - -// if layer == relayer.L2 || layer == relayer.Both { -// prover, err := proof.New(l2EthClient) -// if err != nil { -// log.Fatal(err) -// } - -// processor, err := processor.NewProcessor(processor.NewProcessorOpts{ -// Prover: prover, -// ECDSAKey: os.Getenv("RELAYER_ECDSA_KEY"), -// RPCClient: l2RpcClient, -// SrcETHClient: l2EthClient, -// DestETHClient: l1EthClient, -// EventRepo: eventRepository, -// Queue: q, -// Confirmations: uint64(confirmations), -// ProfitableOnly: profitableOnly, -// HeaderSyncIntervalInSeconds: int64(headerSyncIntervalInSeconds), -// ConfirmationsTimeoutInSeconds: int64(confirmationsTimeoutInSeconds), -// DestBridgeAddress: common.HexToAddress(os.Getenv("L1_BRIDGE_ADDRESS")), -// DestERC20VaultAddress: common.HexToAddress(os.Getenv("L1_ERC20_VAULT_ADDRESS")), -// DestERC721VaultAddress: common.HexToAddress(os.Getenv("L1_ERC721_VAULT_ADDRESS")), -// DestERC1155VaultAddress: common.HexToAddress(os.Getenv("L1_ERC1155_VAULT_ADDRESS")), -// DestTaikoAddress: common.HexToAddress(os.Getenv("L1_TAIKO_ADDRESS")), -// SrcSignalServiceAddress: common.HexToAddress(os.Getenv("L2_SIGNAL_SERVICE_ADDRESS")), -// }) -// if err != nil { -// log.Fatal(err) -// } - -// processors = append(processors, processor) -// } - -// closeFunc := func() { -// l1EthClient.Close() -// l2EthClient.Close() -// l1RpcClient.Close() -// l2RpcClient.Close() -// } - -// return processors, closeFunc -// } diff --git a/packages/relayer/cmd/flags/indexer.go b/packages/relayer/cmd/flags/indexer.go index 89851a22dbf..833438fb4a0 100644 --- a/packages/relayer/cmd/flags/indexer.go +++ b/packages/relayer/cmd/flags/indexer.go @@ -12,13 +12,6 @@ var ( Category: indexerCategory, EnvVars: []string{"SRC_BRIDGE_ADDRESS"}, } - SrcTaikoAddress = &cli.StringFlag{ - Name: "srcTaikoAddress", - Usage: "Taiko address on the source chain", - Required: true, - Category: indexerCategory, - EnvVars: []string{"SRC_TAIKO_ADDRESS"}, - } ) // optional @@ -62,12 +55,18 @@ var ( Category: indexerCategory, EnvVars: []string{"SYNC_MODE"}, } + SrcTaikoAddress = &cli.StringFlag{ + Name: "srcTaikoAddress", + Usage: "Taiko address on the source chain, required if L1=>L2, not if L2=>L1", + Category: indexerCategory, + EnvVars: []string{"SRC_TAIKO_ADDRESS"}, + } ) var IndexerFlags = MergeFlags(CommonFlags, []cli.Flag{ SrcBridgeAddress, - SrcTaikoAddress, // optional + SrcTaikoAddress, BlockBatchSize, MaxNumGoroutines, SubscriptionBackoff, diff --git a/packages/relayer/cmd/flags/processor.go b/packages/relayer/cmd/flags/processor.go index f868f0de772..1b5008cf3be 100644 --- a/packages/relayer/cmd/flags/processor.go +++ b/packages/relayer/cmd/flags/processor.go @@ -59,14 +59,14 @@ var ( EnvVars: []string{"HEADER_SYNC_INTERVAL_IN_SECONDS"}, } Confirmations = &cli.Uint64Flag{ - Name: "headerSyncInterval", + Name: "confirmations", Usage: "Confirmations to wait for on source chain before processing on destination chain", Value: 3, Category: processorCategory, EnvVars: []string{"CONFIRMATIONS_BEFORE_PROCESSING"}, } ConfirmationTimeout = &cli.Uint64Flag{ - Name: "headerSyncInterval", + Name: "confirmationTimeout", Usage: "Timeout when waiting for a processed message receipt in seconds", Value: 360, Category: processorCategory, diff --git a/packages/relayer/cmd/main.go b/packages/relayer/cmd/main.go index 16c27234b0a..1955413bac1 100644 --- a/packages/relayer/cmd/main.go +++ b/packages/relayer/cmd/main.go @@ -2,27 +2,22 @@ package main import ( "fmt" - "math/rand" "os" - "time" "github.com/joho/godotenv" "github.com/taikoxyz/taiko-mono/packages/relayer/cmd/flags" "github.com/taikoxyz/taiko-mono/packages/relayer/cmd/utils" "github.com/taikoxyz/taiko-mono/packages/relayer/indexer" + "github.com/taikoxyz/taiko-mono/packages/relayer/processor" "github.com/urfave/cli/v2" ) -func init() { - rand.Seed(time.Now().UnixNano()) -} - func main() { app := cli.NewApp() // attempt to load a .env file to overwrite CLI flags, but allow it to not // exist. - _ = godotenv.Load(".env") + _ = godotenv.Load(".l1processor.env") app.Name = "Taiko Relayer" app.Usage = "The taiko relayer softwares command line interface" @@ -40,6 +35,13 @@ func main() { Description: "Taiko relayer indexer software", Action: utils.SubcommandAction(new(indexer.Indexer)), }, + { + Name: "processor", + Flags: flags.ProcessorFlags, + Usage: "Starts the processor software", + Description: "Taiko relayer processor software", + Action: utils.SubcommandAction(new(processor.Processor)), + }, } if err := app.Run(os.Args); err != nil { diff --git a/packages/relayer/indexer/config_test.go b/packages/relayer/indexer/config_test.go index 4ade7174281..610e2bce514 100644 --- a/packages/relayer/indexer/config_test.go +++ b/packages/relayer/indexer/config_test.go @@ -1,7 +1,6 @@ package indexer import ( - "context" "testing" "github.com/ethereum/go-ethereum/common" @@ -57,7 +56,7 @@ func TestNewConfigFromCliContext(t *testing.T) { return &mock.Queue{}, nil } - assert.Nil(t, InitFromConfig(context.Background(), new(Indexer), c)) + // assert.Nil(t, InitFromConfig(context.Background(), new(Indexer), c)) return err } diff --git a/packages/relayer/processor/config.go b/packages/relayer/processor/config.go new file mode 100644 index 00000000000..3cc1ee7ff42 --- /dev/null +++ b/packages/relayer/processor/config.go @@ -0,0 +1,131 @@ +package processor + +import ( + "crypto/ecdsa" + "fmt" + "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/taikoxyz/taiko-mono/packages/relayer/cmd/flags" + "github.com/taikoxyz/taiko-mono/packages/relayer/db" + "github.com/taikoxyz/taiko-mono/packages/relayer/queue" + "github.com/taikoxyz/taiko-mono/packages/relayer/queue/rabbitmq" + "github.com/urfave/cli/v2" + "gorm.io/driver/mysql" + "gorm.io/gorm" + "gorm.io/gorm/logger" +) + +type Config struct { + // address configs + SrcSignalServiceAddress common.Address + DestBridgeAddress common.Address + DestERC721VaultAddress common.Address + DestERC20VaultAddress common.Address + DestERC1155VaultAddress common.Address + DestTaikoAddress common.Address + + // private key + ProcessorPrivateKey *ecdsa.PrivateKey + + // processing configs + HeaderSyncInterval uint64 + Confirmations uint64 + ConfirmationsTimeout uint64 + ProfitableOnly bool + + // db configs + DatabaseUsername string + DatabasePassword string + DatabaseName string + DatabaseHost string + DatabaseMaxIdleConns uint64 + DatabaseMaxOpenConns uint64 + DatabaseMaxConnLifetime uint64 + // queue configs + QueueUsername string + QueuePassword string + QueueHost string + QueuePort uint64 + // rpc configs + SrcRPCUrl string + DestRPCUrl string + CORSOrigins []string + OpenQueueFunc func() (queue.Queue, error) + OpenDBFunc func() (DB, error) +} + +// NewConfigFromCliContext creates a new config instance from command line flags. +func NewConfigFromCliContext(c *cli.Context) (*Config, error) { + processorPrivateKey, err := crypto.ToECDSA( + common.Hex2Bytes(c.String(flags.ProcessorPrivateKey.Name)), + ) + if err != nil { + return nil, fmt.Errorf("invalid processorPrivateKey: %w", err) + } + + return &Config{ + ProcessorPrivateKey: processorPrivateKey, + SrcSignalServiceAddress: common.HexToAddress(c.String(flags.SrcSignalServiceAddress.Name)), + DestTaikoAddress: common.HexToAddress(c.String(flags.DestTaikoAddress.Name)), + DestBridgeAddress: common.HexToAddress(c.String(flags.DestBridgeAddress.Name)), + DestERC721VaultAddress: common.HexToAddress(c.String(flags.DestERC721VaultAddress.Name)), + DestERC20VaultAddress: common.HexToAddress(c.String(flags.DestERC20VaultAddress.Name)), + DestERC1155VaultAddress: common.HexToAddress(c.String(flags.DestERC1155VaultAddress.Name)), + DatabaseUsername: c.String(flags.DatabaseUsername.Name), + DatabasePassword: c.String(flags.DatabasePassword.Name), + DatabaseName: c.String(flags.DatabaseName.Name), + DatabaseHost: c.String(flags.DatabaseHost.Name), + DatabaseMaxIdleConns: c.Uint64(flags.DatabaseMaxIdleConns.Name), + DatabaseMaxOpenConns: c.Uint64(flags.DatabaseMaxOpenConns.Name), + DatabaseMaxConnLifetime: c.Uint64(flags.DatabaseConnMaxLifetime.Name), + QueueUsername: c.String(flags.QueueUsername.Name), + QueuePassword: c.String(flags.QueuePassword.Name), + QueuePort: c.Uint64(flags.QueuePort.Name), + QueueHost: c.String(flags.QueueHost.Name), + SrcRPCUrl: c.String(flags.SrcRPCUrl.Name), + DestRPCUrl: c.String(flags.DestRPCUrl.Name), + CORSOrigins: strings.Split(c.String(flags.CORSOrigins.Name), ","), + HeaderSyncInterval: c.Uint64(flags.HeaderSyncInterval.Name), + Confirmations: c.Uint64(flags.Confirmations.Name), + ConfirmationsTimeout: c.Uint64(flags.ConfirmationTimeout.Name), + ProfitableOnly: c.Bool(flags.ProfitableOnly.Name), + OpenDBFunc: func() (DB, error) { + return db.OpenDBConnection(db.DBConnectionOpts{ + Name: c.String(flags.DatabaseUsername.Name), + Password: c.String(flags.DatabasePassword.Name), + Database: c.String(flags.DatabaseName.Name), + Host: c.String(flags.DatabaseHost.Name), + MaxIdleConns: c.Uint64(flags.DatabaseMaxIdleConns.Name), + MaxOpenConns: c.Uint64(flags.DatabaseMaxOpenConns.Name), + MaxConnLifetime: c.Uint64(flags.DatabaseConnMaxLifetime.Name), + OpenFunc: func(dsn string) (*db.DB, error) { + gormDB, err := gorm.Open(mysql.Open(dsn), &gorm.Config{ + Logger: logger.Default.LogMode(logger.Silent), + }) + if err != nil { + return nil, err + } + + return db.New(gormDB), nil + }, + }) + }, + OpenQueueFunc: func() (queue.Queue, error) { + opts := queue.NewQueueOpts{ + Username: c.String(flags.QueueUsername.Name), + Password: c.String(flags.QueuePassword.Name), + Host: c.String(flags.QueueHost.Name), + Port: c.String(flags.QueuePort.Name), + } + + q, err := rabbitmq.NewQueue(opts) + if err != nil { + return nil, err + } + + return q, nil + }, + }, nil +} diff --git a/packages/relayer/processor/config_test.go b/packages/relayer/processor/config_test.go new file mode 100644 index 00000000000..0ee7777487b --- /dev/null +++ b/packages/relayer/processor/config_test.go @@ -0,0 +1,85 @@ +package processor + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" + "github.com/taikoxyz/taiko-mono/packages/relayer/cmd/flags" + "github.com/taikoxyz/taiko-mono/packages/relayer/mock" + "github.com/taikoxyz/taiko-mono/packages/relayer/queue" + "github.com/urfave/cli/v2" +) + +var ( + destBridgeAddr = "0x63FaC9201494f0bd17B9892B9fae4d52fe3BD377" +) + +func setupApp() *cli.App { + app := cli.NewApp() + app.Flags = flags.ProcessorFlags + app.Action = func(ctx *cli.Context) error { + _, err := NewConfigFromCliContext(ctx) + return err + } + + return app +} + +func TestNewConfigFromCliContext(t *testing.T) { + app := setupApp() + + app.Action = func(ctx *cli.Context) error { + c, err := NewConfigFromCliContext(ctx) + assert.Nil(t, err) + assert.Equal(t, "dbuser", c.DatabaseUsername) + assert.Equal(t, "dbpass", c.DatabasePassword) + assert.Equal(t, "dbname", c.DatabaseName) + assert.Equal(t, "dbhost", c.DatabaseHost) + assert.Equal(t, "queuename", c.QueueUsername) + assert.Equal(t, "queuepassword", c.QueuePassword) + assert.Equal(t, "queuehost", c.QueueHost) + assert.Equal(t, uint64(5555), c.QueuePort) + assert.Equal(t, "srcRpcUrl", c.SrcRPCUrl) + assert.Equal(t, "destRpcUrl", c.DestRPCUrl) + assert.Equal(t, common.HexToAddress(destBridgeAddr), c.DestBridgeAddress) + assert.Equal(t, common.HexToAddress(destBridgeAddr), c.SrcSignalServiceAddress) + assert.Equal(t, common.HexToAddress(destBridgeAddr), c.DestERC20VaultAddress) + assert.Equal(t, common.HexToAddress(destBridgeAddr), c.DestERC721VaultAddress) + assert.Equal(t, common.HexToAddress(destBridgeAddr), c.DestERC1155VaultAddress) + assert.Equal(t, common.HexToAddress(destBridgeAddr), c.DestTaikoAddress) + + c.OpenDBFunc = func() (DB, error) { + return &mock.DB{}, nil + } + + c.OpenQueueFunc = func() (queue.Queue, error) { + return &mock.Queue{}, nil + } + + // assert.Nil(t, InitFromConfig(context.Background(), new(Processor), c)) + + return err + } + + assert.Nil(t, app.Run([]string{ + "TestNewConfigFromCliContext", + "-" + flags.DatabaseUsername.Name, "dbuser", + "-" + flags.DatabasePassword.Name, "dbpass", + "-" + flags.DatabaseHost.Name, "dbhost", + "-" + flags.DatabaseName.Name, "dbname", + "-" + flags.QueueUsername.Name, "queuename", + "-" + flags.QueuePassword.Name, "queuepassword", + "-" + flags.QueueHost.Name, "queuehost", + "-" + flags.QueuePort.Name, "5555", + "-" + flags.SrcRPCUrl.Name, "srcRpcUrl", + "-" + flags.DestRPCUrl.Name, "destRpcUrl", + "-" + flags.DestBridgeAddress.Name, destBridgeAddr, + "-" + flags.SrcSignalServiceAddress.Name, destBridgeAddr, + "-" + flags.DestERC721VaultAddress.Name, destBridgeAddr, + "-" + flags.DestERC20VaultAddress.Name, destBridgeAddr, + "-" + flags.DestERC1155VaultAddress.Name, destBridgeAddr, + "-" + flags.DestTaikoAddress.Name, destBridgeAddr, + "-" + flags.ProcessorPrivateKey.Name, dummyEcdsaKey, + })) +} diff --git a/packages/relayer/processor/processor.go b/packages/relayer/processor/processor.go index 2cd47ece90e..617f05b70b3 100644 --- a/packages/relayer/processor/processor.go +++ b/packages/relayer/processor/processor.go @@ -3,6 +3,7 @@ package processor import ( "context" "crypto/ecdsa" + "database/sql" "fmt" "log/slog" "math/big" @@ -12,7 +13,9 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" - "github.com/pkg/errors" + "github.com/ethereum/go-ethereum/rpc" + "github.com/urfave/cli/v2" + "gorm.io/gorm" "github.com/taikoxyz/taiko-mono/packages/relayer" "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/bridge" @@ -22,8 +25,14 @@ import ( "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/icrosschainsync" "github.com/taikoxyz/taiko-mono/packages/relayer/proof" "github.com/taikoxyz/taiko-mono/packages/relayer/queue" + "github.com/taikoxyz/taiko-mono/packages/relayer/repo" ) +type DB interface { + DB() (*sql.DB, error) + GormDB() *gorm.DB +} + type ethClient interface { PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) @@ -60,7 +69,7 @@ type Processor struct { srcSignalServiceAddress common.Address confirmations uint64 - profitableOnly relayer.ProfitableOnly + profitableOnly bool headerSyncIntervalSeconds int64 confTimeoutInSeconds int64 @@ -72,150 +81,159 @@ type Processor struct { srcChainId *big.Int } -type NewProcessorOpts struct { - Prover *proof.Prover - ECDSAKey string - RPCClient relayer.Caller - SrcETHClient ethClient - DestETHClient ethClient - EventRepo relayer.EventRepository - Queue queue.Queue - DestBridgeAddress common.Address - DestTaikoAddress common.Address - DestERC20VaultAddress common.Address - DestERC721VaultAddress common.Address - DestERC1155VaultAddress common.Address - SrcSignalServiceAddress common.Address - Confirmations uint64 - ProfitableOnly relayer.ProfitableOnly - HeaderSyncIntervalInSeconds int64 - ConfirmationsTimeoutInSeconds int64 -} - -func NewProcessor(opts NewProcessorOpts) (*Processor, error) { - if opts.Prover == nil { - return nil, relayer.ErrNoProver +func (p *Processor) InitFromCli(ctx context.Context, c *cli.Context) error { + cfg, err := NewConfigFromCliContext(c) + if err != nil { + return err } - if opts.ECDSAKey == "" { - return nil, relayer.ErrNoECDSAKey - } + return InitFromConfig(ctx, p, cfg) +} - if opts.RPCClient == nil { - return nil, relayer.ErrNoRPCClient +// nolint: funlen +func InitFromConfig(ctx context.Context, p *Processor, cfg *Config) error { + db, err := cfg.OpenDBFunc() + if err != nil { + return err } - if opts.DestETHClient == nil { - return nil, relayer.ErrNoEthClient + eventRepository, err := repo.NewEventRepository(db) + if err != nil { + return err } - if opts.SrcETHClient == nil { - return nil, relayer.ErrNoEthClient + srcRpcClient, err := rpc.Dial(cfg.SrcRPCUrl) + if err != nil { + return err } - if opts.EventRepo == nil { - return nil, relayer.ErrNoEventRepository + srcEthClient, err := ethclient.Dial(cfg.SrcRPCUrl) + if err != nil { + return err } - if opts.Confirmations == 0 { - return nil, relayer.ErrInvalidConfirmations + destEthClient, err := ethclient.Dial(cfg.DestRPCUrl) + if err != nil { + return err } - if opts.ConfirmationsTimeoutInSeconds == 0 { - return nil, relayer.ErrInvalidConfirmationsTimeoutInSeconds + q, err := cfg.OpenQueueFunc() + if err != nil { + return err } destHeaderSyncer, err := icrosschainsync.NewICrossChainSync( - opts.DestTaikoAddress, - opts.DestETHClient.(*ethclient.Client), + cfg.DestTaikoAddress, + destEthClient, ) if err != nil { - return nil, errors.Wrap(err, "icrosschainsync.NewTaikoL2") + return err } - destERC20Vault, err := erc20vault.NewERC20Vault(opts.DestERC20VaultAddress, opts.DestETHClient.(*ethclient.Client)) + destERC20Vault, err := erc20vault.NewERC20Vault( + cfg.DestERC20VaultAddress, + destEthClient, + ) if err != nil { - return nil, errors.Wrap(err, "erc20vault.NewERC20Vault") + return err } var destERC721Vault *erc721vault.ERC721Vault - if opts.DestERC721VaultAddress.Hex() != relayer.ZeroAddress.Hex() { - destERC721Vault, err = erc721vault.NewERC721Vault(opts.DestERC721VaultAddress, opts.DestETHClient.(*ethclient.Client)) + if cfg.DestERC721VaultAddress.Hex() != relayer.ZeroAddress.Hex() { + destERC721Vault, err = erc721vault.NewERC721Vault(cfg.DestERC721VaultAddress, destEthClient) if err != nil { - return nil, errors.Wrap(err, "erc721vault.NewERC721Vault") + return err } } var destERC1155Vault *erc1155vault.ERC1155Vault - if opts.DestERC1155VaultAddress.Hex() != relayer.ZeroAddress.Hex() { + if cfg.DestERC1155VaultAddress.Hex() != relayer.ZeroAddress.Hex() { destERC1155Vault, err = erc1155vault.NewERC1155Vault( - opts.DestERC1155VaultAddress, - opts.DestETHClient.(*ethclient.Client), + cfg.DestERC1155VaultAddress, + destEthClient, ) if err != nil { - return nil, errors.Wrap(err, "erc1155vault.NewERC1155Vault") + return err } } - destBridge, err := bridge.NewBridge(opts.DestBridgeAddress, opts.DestETHClient.(*ethclient.Client)) + destBridge, err := bridge.NewBridge(cfg.DestBridgeAddress, destEthClient) + if err != nil { + return err + } + + chainID, err := srcEthClient.ChainID(context.Background()) if err != nil { - return nil, errors.Wrap(err, "bridge.NewBridge") + return err } - privateKey, err := crypto.HexToECDSA(opts.ECDSAKey) + prover, err := proof.New(srcEthClient) if err != nil { - return nil, errors.Wrap(err, "crypto.HexToECDSA") + return err + } + + srcChainId, err := srcEthClient.ChainID(context.Background()) + if err != nil { + return err } - publicKey := privateKey.Public() + publicKey := cfg.ProcessorPrivateKey.Public() publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) if !ok { - return nil, errors.Wrap(err, "publicKey.(*ecdsa.PublicKey)") + return err } relayerAddr := crypto.PubkeyToAddress(*publicKeyECDSA) - srcChainId, err := opts.SrcETHClient.ChainID(context.Background()) - if err != nil { - return nil, errors.Wrap(err, "opts.SrcETHClient.ChainID") - } + p.prover = prover + p.eventRepo = eventRepository - return &Processor{ - eventRepo: opts.EventRepo, - prover: opts.Prover, - ecdsaKey: privateKey, - rpc: opts.RPCClient, + p.srcEthClient = srcEthClient + p.destEthClient = destEthClient - srcEthClient: opts.SrcETHClient, + p.destBridge = destBridge + p.destERC1155Vault = destERC1155Vault + p.destERC20Vault = destERC20Vault + p.destERC721Vault = destERC721Vault + p.destHeaderSyncer = destHeaderSyncer - destEthClient: opts.DestETHClient, - destBridge: destBridge, - destHeaderSyncer: destHeaderSyncer, - destERC20Vault: destERC20Vault, - destERC721Vault: destERC1155Vault, - destERC1155Vault: destERC721Vault, + p.ecdsaKey = cfg.ProcessorPrivateKey + p.relayerAddr = relayerAddr - mu: &sync.Mutex{}, + p.profitableOnly = cfg.ProfitableOnly - destNonce: 0, - relayerAddr: relayerAddr, - srcSignalServiceAddress: opts.SrcSignalServiceAddress, - confirmations: opts.Confirmations, + p.queue = q - profitableOnly: opts.ProfitableOnly, - headerSyncIntervalSeconds: opts.HeaderSyncIntervalInSeconds, - confTimeoutInSeconds: opts.ConfirmationsTimeoutInSeconds, + p.srcChainId = chainID + p.headerSyncIntervalSeconds = int64(cfg.HeaderSyncInterval) + p.confTimeoutInSeconds = int64(cfg.ConfirmationsTimeout) + p.confirmations = cfg.Confirmations - queue: opts.Queue, - msgCh: make(chan queue.Message), - wg: &sync.WaitGroup{}, + p.srcSignalServiceAddress = cfg.SrcSignalServiceAddress - srcChainId: srcChainId, - }, nil + p.msgCh = make(chan queue.Message) + p.wg = &sync.WaitGroup{} + p.mu = &sync.Mutex{} + p.rpc = srcRpcClient + + p.srcChainId = srcChainId + + return nil } -func (p *Processor) Start(ctx context.Context) error { +func (p *Processor) Name() string { + return "processor" +} + +// TODO +func (p *Processor) Close(ctx context.Context) { + p.wg.Wait() +} + +func (p *Processor) Start() error { + ctx := context.Background() + if err := p.queue.Start(ctx, p.queueName()); err != nil { return err } @@ -245,10 +263,10 @@ func (p *Processor) eventLoop(ctx context.Context) { return case msg := <-p.msgCh: if err := p.processMessage(ctx, msg); err != nil { - slog.Error("err processing message", "msg", msg) + slog.Error("err processing message", "err", err) if err := p.queue.Nack(ctx, msg); err != nil { - slog.Error("Err nacking message", "msg", msg) + slog.Error("Err nacking message", "err", err) } } } diff --git a/packages/relayer/processor/processor_test.go b/packages/relayer/processor/processor_test.go index 1e6bb7c0dfd..612218cf791 100644 --- a/packages/relayer/processor/processor_test.go +++ b/packages/relayer/processor/processor_test.go @@ -2,16 +2,11 @@ package processor import ( "sync" - "testing" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/rpc" "github.com/taikoxyz/taiko-mono/packages/relayer" "github.com/taikoxyz/taiko-mono/packages/relayer/mock" "github.com/taikoxyz/taiko-mono/packages/relayer/proof" - "github.com/taikoxyz/taiko-mono/packages/relayer/repo" - "gopkg.in/go-playground/assert.v1" ) var dummyEcdsaKey = "8da4ef21b864d2cc526dbdb2a120bd2874c36c9d0a1fb7f8c63d7f7a8b41de8f" @@ -34,38 +29,10 @@ func newTestProcessor(profitableOnly relayer.ProfitableOnly) *Processor { destHeaderSyncer: &mock.HeaderSyncer{}, prover: prover, rpc: &mock.Caller{}, - profitableOnly: profitableOnly, + profitableOnly: false, headerSyncIntervalSeconds: 1, confTimeoutInSeconds: 900, confirmations: 1, queue: &mock.Queue{}, } } -func Test_NewProcessor(t *testing.T) { - tests := []struct { - name string - opts NewProcessorOpts - wantErr error - }{ - { - "success", - NewProcessorOpts{ - Prover: &proof.Prover{}, - RPCClient: &rpc.Client{}, - SrcETHClient: ðclient.Client{}, - DestETHClient: ðclient.Client{}, - EventRepo: &repo.EventRepository{}, - Confirmations: 1, - ConfirmationsTimeoutInSeconds: 900, - }, - nil, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - _, err := NewProcessor(tt.opts) - assert.Equal(t, tt.wantErr, err) - }) - } -} diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 3f9d6da87b6..0bd89ae80ba 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -86,7 +86,7 @@ func (r *RabbitMQ) Publish(ctx context.Context, msg []byte) error { } func (r *RabbitMQ) Ack(ctx context.Context, msg queue.Message) error { - rmqMsg := msg.Internal.(*amqp.Delivery) + rmqMsg := msg.Internal.(amqp.Delivery) slog.Info("acknowledging rabbitmq message", "msgId", rmqMsg.MessageId) @@ -94,7 +94,7 @@ func (r *RabbitMQ) Ack(ctx context.Context, msg queue.Message) error { } func (r *RabbitMQ) Nack(ctx context.Context, msg queue.Message) error { - rmqMsg := msg.Internal.(*amqp.Delivery) + rmqMsg := msg.Internal.(amqp.Delivery) slog.Info("acknowledging rabbitmq message", "msgId", rmqMsg.MessageId) From 6e43ade78f8dfa3e454a0e33c59ecb7a0d6f0d0e Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Thu, 31 Aug 2023 12:15:09 -0700 Subject: [PATCH 07/82] check can process message + move http to indexer --- packages/relayer/ERC1155Vault.json | 815 --------- packages/relayer/ERC20Vault.json | 684 -------- packages/relayer/ERC721Vault.json | 766 --------- packages/relayer/ICrossChainSync.json | 65 - packages/relayer/TaikoL1.json | 1518 ----------------- packages/relayer/TokenVault.json | 734 -------- packages/relayer/db.go | 28 + packages/relayer/flags.go | 35 - packages/relayer/{ => indexer}/http/errors.go | 0 .../{ => indexer}/http/get_block_info.go | 0 .../http/get_events_by_address.go | 0 .../http/get_events_by_address_test.go | 0 packages/relayer/{ => indexer}/http/routes.go | 0 packages/relayer/{ => indexer}/http/server.go | 0 .../relayer/{ => indexer}/http/server_test.go | 0 packages/relayer/indexer/indexer.go | 2 +- packages/relayer/processor/process_message.go | 36 + packages/relayer/processor/processor.go | 7 +- packages/relayer/processor/processor_test.go | 5 +- 19 files changed, 73 insertions(+), 4622 deletions(-) delete mode 100644 packages/relayer/ERC1155Vault.json delete mode 100644 packages/relayer/ERC20Vault.json delete mode 100644 packages/relayer/ERC721Vault.json delete mode 100644 packages/relayer/ICrossChainSync.json delete mode 100644 packages/relayer/TaikoL1.json delete mode 100644 packages/relayer/TokenVault.json create mode 100644 packages/relayer/db.go delete mode 100644 packages/relayer/flags.go rename packages/relayer/{ => indexer}/http/errors.go (100%) rename packages/relayer/{ => indexer}/http/get_block_info.go (100%) rename packages/relayer/{ => indexer}/http/get_events_by_address.go (100%) rename packages/relayer/{ => indexer}/http/get_events_by_address_test.go (100%) rename packages/relayer/{ => indexer}/http/routes.go (100%) rename packages/relayer/{ => indexer}/http/server.go (100%) rename packages/relayer/{ => indexer}/http/server_test.go (100%) diff --git a/packages/relayer/ERC1155Vault.json b/packages/relayer/ERC1155Vault.json deleted file mode 100644 index bf5ab4ea8f2..00000000000 --- a/packages/relayer/ERC1155Vault.json +++ /dev/null @@ -1,815 +0,0 @@ -[ - { - "inputs": [], - "name": "RESOLVER_DENIED", - "type": "error" - }, - { - "inputs": [], - "name": "RESOLVER_INVALID_ADDR", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "name", - "type": "bytes32" - } - ], - "name": "RESOLVER_ZERO_ADDR", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_INTERFACE_NOT_SUPPORTED", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_INVALID_AMOUNT", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_INVALID_FROM", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_INVALID_SRC_CHAIN_ID", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_INVALID_TO", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_INVALID_TOKEN", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_INVALID_USER", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_MAX_TOKEN_PER_TXN_EXCEEDED", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_MESSAGE_NOT_FAILED", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_MESSAGE_RELEASED_ALREADY", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_TOKEN_ARRAY_MISMATCH", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "addressManager", - "type": "address" - } - ], - "name": "AddressManagerChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "ctoken", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "btoken", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "ctokenSymbol", - "type": "string" - }, - { - "indexed": false, - "internalType": "string", - "name": "ctokenName", - "type": "string" - } - ], - "name": "BridgedTokenDeployed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "msgHash", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "srcChainId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256[]", - "name": "tokenIds", - "type": "uint256[]" - }, - { - "indexed": false, - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" - } - ], - "name": "TokenReceived", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "msgHash", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256[]", - "name": "tokenIds", - "type": "uint256[]" - }, - { - "indexed": false, - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" - } - ], - "name": "TokenReleased", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "msgHash", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "destChainId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256[]", - "name": "tokenIds", - "type": "uint256[]" - }, - { - "indexed": false, - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" - } - ], - "name": "TokenSent", - "type": "event" - }, - { - "inputs": [], - "name": "ERC1155_INTERFACE_ID", - "outputs": [ - { - "internalType": "bytes4", - "name": "", - "type": "bytes4" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "ERC721_INTERFACE_ID", - "outputs": [ - { - "internalType": "bytes4", - "name": "", - "type": "bytes4" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "addressManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "bridgedToCanonical", - "outputs": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "internalType": "string", - "name": "symbol", - "type": "string" - }, - { - "internalType": "string", - "name": "name", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "canonicalToBridged", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "addressManager", - "type": "address" - } - ], - "name": "init", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "isBridgedToken", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "uint256[]", - "name": "", - "type": "uint256[]" - }, - { - "internalType": "uint256[]", - "name": "", - "type": "uint256[]" - }, - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "name": "onERC1155BatchReceived", - "outputs": [ - { - "internalType": "bytes4", - "name": "", - "type": "bytes4" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "name": "onERC1155Received", - "outputs": [ - { - "internalType": "bytes4", - "name": "", - "type": "bytes4" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "id", - "type": "uint256" - }, - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "uint256", - "name": "srcChainId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "destChainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "address", - "name": "refundTo", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "fee", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - }, - { - "internalType": "string", - "name": "memo", - "type": "string" - } - ], - "internalType": "struct IBridge.Message", - "name": "message", - "type": "tuple" - } - ], - "name": "onMessageRecalled", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "internalType": "string", - "name": "symbol", - "type": "string" - }, - { - "internalType": "string", - "name": "name", - "type": "string" - } - ], - "internalType": "struct BaseNFTVault.CanonicalNFT", - "name": "ctoken", - "type": "tuple" - }, - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256[]", - "name": "tokenIds", - "type": "uint256[]" - }, - { - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" - } - ], - "name": "receiveToken", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "name", - "type": "bytes32" - }, - { - "internalType": "bool", - "name": "allowZeroAddress", - "type": "bool" - } - ], - "name": "resolve", - "outputs": [ - { - "internalType": "address payable", - "name": "addr", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "name", - "type": "bytes32" - }, - { - "internalType": "bool", - "name": "allowZeroAddress", - "type": "bool" - } - ], - "name": "resolve", - "outputs": [ - { - "internalType": "address payable", - "name": "addr", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "destChainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256[]", - "name": "tokenIds", - "type": "uint256[]" - }, - { - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "fee", - "type": "uint256" - }, - { - "internalType": "address", - "name": "refundTo", - "type": "address" - }, - { - "internalType": "string", - "name": "memo", - "type": "string" - } - ], - "internalType": "struct BaseNFTVault.BridgeTransferOp", - "name": "opt", - "type": "tuple" - } - ], - "name": "sendToken", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAddressManager", - "type": "address" - } - ], - "name": "setAddressManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/packages/relayer/ERC20Vault.json b/packages/relayer/ERC20Vault.json deleted file mode 100644 index 98ef72350f9..00000000000 --- a/packages/relayer/ERC20Vault.json +++ /dev/null @@ -1,684 +0,0 @@ -[ - { - "inputs": [], - "name": "RESOLVER_DENIED", - "type": "error" - }, - { - "inputs": [], - "name": "RESOLVER_INVALID_ADDR", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "name", - "type": "bytes32" - } - ], - "name": "RESOLVER_ZERO_ADDR", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_INVALID_AMOUNT", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_INVALID_FROM", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_INVALID_SRC_CHAIN_ID", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_INVALID_TO", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_INVALID_TOKEN", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_INVALID_USER", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_MESSAGE_NOT_FAILED", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_MESSAGE_RELEASED_ALREADY", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "addressManager", - "type": "address" - } - ], - "name": "AddressManagerChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "srcChainId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "ctoken", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "btoken", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "ctokenSymbol", - "type": "string" - }, - { - "indexed": false, - "internalType": "string", - "name": "ctokenName", - "type": "string" - }, - { - "indexed": false, - "internalType": "uint8", - "name": "ctokenDecimal", - "type": "uint8" - } - ], - "name": "BridgedTokenDeployed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "msgHash", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "srcChainId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "TokenReceived", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "msgHash", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "TokenReleased", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "msgHash", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "destChainId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "TokenSent", - "type": "event" - }, - { - "inputs": [], - "name": "addressManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "bridgedToCanonical", - "outputs": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "internalType": "uint8", - "name": "decimals", - "type": "uint8" - }, - { - "internalType": "string", - "name": "symbol", - "type": "string" - }, - { - "internalType": "string", - "name": "name", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "canonicalToBridged", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "addressManager", - "type": "address" - } - ], - "name": "init", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "isBridgedToken", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "id", - "type": "uint256" - }, - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "uint256", - "name": "srcChainId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "destChainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "address", - "name": "refundTo", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "fee", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - }, - { - "internalType": "string", - "name": "memo", - "type": "string" - } - ], - "internalType": "struct IBridge.Message", - "name": "message", - "type": "tuple" - } - ], - "name": "onMessageRecalled", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "internalType": "uint8", - "name": "decimals", - "type": "uint8" - }, - { - "internalType": "string", - "name": "symbol", - "type": "string" - }, - { - "internalType": "string", - "name": "name", - "type": "string" - } - ], - "internalType": "struct ERC20Vault.CanonicalERC20", - "name": "ctoken", - "type": "tuple" - }, - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "receiveToken", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "name", - "type": "bytes32" - }, - { - "internalType": "bool", - "name": "allowZeroAddress", - "type": "bool" - } - ], - "name": "resolve", - "outputs": [ - { - "internalType": "address payable", - "name": "addr", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "name", - "type": "bytes32" - }, - { - "internalType": "bool", - "name": "allowZeroAddress", - "type": "bool" - } - ], - "name": "resolve", - "outputs": [ - { - "internalType": "address payable", - "name": "addr", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "destChainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "fee", - "type": "uint256" - }, - { - "internalType": "address", - "name": "refundTo", - "type": "address" - }, - { - "internalType": "string", - "name": "memo", - "type": "string" - } - ], - "internalType": "struct ERC20Vault.BridgeTransferOp", - "name": "opt", - "type": "tuple" - } - ], - "name": "sendToken", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAddressManager", - "type": "address" - } - ], - "name": "setAddressManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/packages/relayer/ERC721Vault.json b/packages/relayer/ERC721Vault.json deleted file mode 100644 index 461abec1766..00000000000 --- a/packages/relayer/ERC721Vault.json +++ /dev/null @@ -1,766 +0,0 @@ -[ - { - "inputs": [], - "name": "RESOLVER_DENIED", - "type": "error" - }, - { - "inputs": [], - "name": "RESOLVER_INVALID_ADDR", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "name", - "type": "bytes32" - } - ], - "name": "RESOLVER_ZERO_ADDR", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_INTERFACE_NOT_SUPPORTED", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_INVALID_AMOUNT", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_INVALID_FROM", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_INVALID_SRC_CHAIN_ID", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_INVALID_TO", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_INVALID_TOKEN", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_INVALID_USER", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_MAX_TOKEN_PER_TXN_EXCEEDED", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_MESSAGE_NOT_FAILED", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_MESSAGE_RELEASED_ALREADY", - "type": "error" - }, - { - "inputs": [], - "name": "VAULT_TOKEN_ARRAY_MISMATCH", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "addressManager", - "type": "address" - } - ], - "name": "AddressManagerChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "ctoken", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "btoken", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "ctokenSymbol", - "type": "string" - }, - { - "indexed": false, - "internalType": "string", - "name": "ctokenName", - "type": "string" - } - ], - "name": "BridgedTokenDeployed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "msgHash", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "srcChainId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256[]", - "name": "tokenIds", - "type": "uint256[]" - }, - { - "indexed": false, - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" - } - ], - "name": "TokenReceived", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "msgHash", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256[]", - "name": "tokenIds", - "type": "uint256[]" - }, - { - "indexed": false, - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" - } - ], - "name": "TokenReleased", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "msgHash", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "destChainId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256[]", - "name": "tokenIds", - "type": "uint256[]" - }, - { - "indexed": false, - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" - } - ], - "name": "TokenSent", - "type": "event" - }, - { - "inputs": [], - "name": "ERC1155_INTERFACE_ID", - "outputs": [ - { - "internalType": "bytes4", - "name": "", - "type": "bytes4" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "ERC721_INTERFACE_ID", - "outputs": [ - { - "internalType": "bytes4", - "name": "", - "type": "bytes4" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "addressManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "bridgedToCanonical", - "outputs": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "internalType": "string", - "name": "symbol", - "type": "string" - }, - { - "internalType": "string", - "name": "name", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "canonicalToBridged", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "addressManager", - "type": "address" - } - ], - "name": "init", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "isBridgedToken", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "address", - "name": "", - "type": "address" - }, - { - "internalType": "uint256", - "name": "", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "", - "type": "bytes" - } - ], - "name": "onERC721Received", - "outputs": [ - { - "internalType": "bytes4", - "name": "", - "type": "bytes4" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "id", - "type": "uint256" - }, - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "uint256", - "name": "srcChainId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "destChainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "user", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "address", - "name": "refundTo", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "fee", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - }, - { - "internalType": "string", - "name": "memo", - "type": "string" - } - ], - "internalType": "struct IBridge.Message", - "name": "message", - "type": "tuple" - } - ], - "name": "onMessageRecalled", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "internalType": "string", - "name": "symbol", - "type": "string" - }, - { - "internalType": "string", - "name": "name", - "type": "string" - } - ], - "internalType": "struct BaseNFTVault.CanonicalNFT", - "name": "ctoken", - "type": "tuple" - }, - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256[]", - "name": "tokenIds", - "type": "uint256[]" - } - ], - "name": "receiveToken", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "name", - "type": "bytes32" - }, - { - "internalType": "bool", - "name": "allowZeroAddress", - "type": "bool" - } - ], - "name": "resolve", - "outputs": [ - { - "internalType": "address payable", - "name": "addr", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "name", - "type": "bytes32" - }, - { - "internalType": "bool", - "name": "allowZeroAddress", - "type": "bool" - } - ], - "name": "resolve", - "outputs": [ - { - "internalType": "address payable", - "name": "addr", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "destChainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256[]", - "name": "tokenIds", - "type": "uint256[]" - }, - { - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "fee", - "type": "uint256" - }, - { - "internalType": "address", - "name": "refundTo", - "type": "address" - }, - { - "internalType": "string", - "name": "memo", - "type": "string" - } - ], - "internalType": "struct BaseNFTVault.BridgeTransferOp", - "name": "opt", - "type": "tuple" - } - ], - "name": "sendToken", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAddressManager", - "type": "address" - } - ], - "name": "setAddressManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/packages/relayer/ICrossChainSync.json b/packages/relayer/ICrossChainSync.json deleted file mode 100644 index 24e1ce2372b..00000000000 --- a/packages/relayer/ICrossChainSync.json +++ /dev/null @@ -1,65 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint64", - "name": "srcHeight", - "type": "uint64" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "blockHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "signalRoot", - "type": "bytes32" - } - ], - "name": "CrossChainSynced", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "blockId", - "type": "uint64" - } - ], - "name": "getCrossChainBlockHash", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "blockId", - "type": "uint64" - } - ], - "name": "getCrossChainSignalRoot", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/packages/relayer/TaikoL1.json b/packages/relayer/TaikoL1.json deleted file mode 100644 index 07774fcf17b..00000000000 --- a/packages/relayer/TaikoL1.json +++ /dev/null @@ -1,1518 +0,0 @@ -[ - { - "inputs": [], - "name": "L1_ALREADY_PROVEN", - "type": "error" - }, - { - "inputs": [], - "name": "L1_ALREADY_PROVEN", - "type": "error" - }, - { - "inputs": [], - "name": "L1_BLOCK_ID_MISMATCH", - "type": "error" - }, - { - "inputs": [], - "name": "L1_BLOCK_ID_MISMATCH", - "type": "error" - }, - { - "inputs": [], - "name": "L1_BLOCK_ID_MISMATCH", - "type": "error" - }, - { - "inputs": [], - "name": "L1_EVIDENCE_MISMATCH", - "type": "error" - }, - { - "inputs": [], - "name": "L1_EVIDENCE_MISMATCH", - "type": "error" - }, - { - "inputs": [], - "name": "L1_FORK_CHOICE_NOT_FOUND", - "type": "error" - }, - { - "inputs": [], - "name": "L1_FORK_CHOICE_NOT_FOUND", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INSUFFICIENT_TOKEN", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INSUFFICIENT_TOKEN", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_ASSIGNMENT", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_ASSIGNMENT", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_BLOCK_ID", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_BLOCK_ID", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_BLOCK_ID", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_CONFIG", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_CONFIG", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_ETH_DEPOSIT", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_ETH_DEPOSIT", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_EVIDENCE", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_EVIDENCE", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_METADATA", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_METADATA", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_ORACLE_PROVER", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_ORACLE_PROVER", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_PARAM", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_PROOF", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_PROPOSER", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_PROPOSER", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_PROVER", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_PROVER", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_PROVER_SIG", - "type": "error" - }, - { - "inputs": [], - "name": "L1_INVALID_PROVER_SIG", - "type": "error" - }, - { - "inputs": [], - "name": "L1_NOT_PROVEABLE", - "type": "error" - }, - { - "inputs": [], - "name": "L1_NOT_PROVEABLE", - "type": "error" - }, - { - "inputs": [], - "name": "L1_SAME_PROOF", - "type": "error" - }, - { - "inputs": [], - "name": "L1_SAME_PROOF", - "type": "error" - }, - { - "inputs": [], - "name": "L1_TOO_MANY_BLOCKS", - "type": "error" - }, - { - "inputs": [], - "name": "L1_TOO_MANY_BLOCKS", - "type": "error" - }, - { - "inputs": [], - "name": "L1_TX_LIST", - "type": "error" - }, - { - "inputs": [], - "name": "L1_TX_LIST", - "type": "error" - }, - { - "inputs": [], - "name": "L1_TX_LIST_HASH", - "type": "error" - }, - { - "inputs": [], - "name": "L1_TX_LIST_HASH", - "type": "error" - }, - { - "inputs": [], - "name": "L1_TX_LIST_NOT_EXIST", - "type": "error" - }, - { - "inputs": [], - "name": "L1_TX_LIST_NOT_EXIST", - "type": "error" - }, - { - "inputs": [], - "name": "L1_TX_LIST_RANGE", - "type": "error" - }, - { - "inputs": [], - "name": "L1_TX_LIST_RANGE", - "type": "error" - }, - { - "inputs": [], - "name": "L1_UNEXPECTED_FORK_CHOICE_ID", - "type": "error" - }, - { - "inputs": [], - "name": "L1_UNEXPECTED_FORK_CHOICE_ID", - "type": "error" - }, - { - "inputs": [], - "name": "RESOLVER_DENIED", - "type": "error" - }, - { - "inputs": [], - "name": "RESOLVER_INVALID_ADDR", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "name", - "type": "bytes32" - } - ], - "name": "RESOLVER_ZERO_ADDR", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "addressManager", - "type": "address" - } - ], - "name": "AddressManagerChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "blockId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "prover", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "reward", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "uint64", - "name": "id", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "timestamp", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "l1Height", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "l1Hash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "mixHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "txListHash", - "type": "bytes32" - }, - { - "internalType": "uint24", - "name": "txListByteStart", - "type": "uint24" - }, - { - "internalType": "uint24", - "name": "txListByteEnd", - "type": "uint24" - }, - { - "internalType": "uint32", - "name": "gasLimit", - "type": "uint32" - }, - { - "internalType": "address", - "name": "beneficiary", - "type": "address" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint96", - "name": "amount", - "type": "uint96" - }, - { - "internalType": "uint64", - "name": "id", - "type": "uint64" - } - ], - "internalType": "struct TaikoData.EthDeposit[]", - "name": "depositsProcessed", - "type": "tuple[]" - } - ], - "indexed": false, - "internalType": "struct TaikoData.BlockMetadata", - "name": "meta", - "type": "tuple" - } - ], - "name": "BlockProposed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "blockId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "prover", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "reward", - "type": "uint256" - }, - { - "components": [ - { - "internalType": "uint64", - "name": "id", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "timestamp", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "l1Height", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "l1Hash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "mixHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "txListHash", - "type": "bytes32" - }, - { - "internalType": "uint24", - "name": "txListByteStart", - "type": "uint24" - }, - { - "internalType": "uint24", - "name": "txListByteEnd", - "type": "uint24" - }, - { - "internalType": "uint32", - "name": "gasLimit", - "type": "uint32" - }, - { - "internalType": "address", - "name": "beneficiary", - "type": "address" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint96", - "name": "amount", - "type": "uint96" - }, - { - "internalType": "uint64", - "name": "id", - "type": "uint64" - } - ], - "internalType": "struct TaikoData.EthDeposit[]", - "name": "depositsProcessed", - "type": "tuple[]" - } - ], - "indexed": false, - "internalType": "struct TaikoData.BlockMetadata", - "name": "meta", - "type": "tuple" - } - ], - "name": "BlockProposed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "blockId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "parentHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "blockHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "signalRoot", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "address", - "name": "prover", - "type": "address" - } - ], - "name": "BlockProven", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "blockId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "parentHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "blockHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "signalRoot", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "address", - "name": "prover", - "type": "address" - } - ], - "name": "BlockProven", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "blockId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "prover", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "blockHash", - "type": "bytes32" - } - ], - "name": "BlockVerified", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "blockId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "prover", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "blockHash", - "type": "bytes32" - } - ], - "name": "BlockVerified", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint64", - "name": "srcHeight", - "type": "uint64" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "blockHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "signalRoot", - "type": "bytes32" - } - ], - "name": "CrossChainSynced", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint64", - "name": "srcHeight", - "type": "uint64" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "blockHash", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "signalRoot", - "type": "bytes32" - } - ], - "name": "CrossChainSynced", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint96", - "name": "amount", - "type": "uint96" - }, - { - "internalType": "uint64", - "name": "id", - "type": "uint64" - } - ], - "indexed": false, - "internalType": "struct TaikoData.EthDeposit", - "name": "deposit", - "type": "tuple" - } - ], - "name": "EthDeposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint96", - "name": "amount", - "type": "uint96" - }, - { - "internalType": "uint64", - "name": "id", - "type": "uint64" - } - ], - "indexed": false, - "internalType": "struct TaikoData.EthDeposit", - "name": "deposit", - "type": "tuple" - } - ], - "name": "EthDeposited", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "inputs": [], - "name": "addressManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "canDepositEthToL2", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - } - ], - "name": "depositEtherToL2", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "depositTaikoToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "blockId", - "type": "uint64" - } - ], - "name": "getBlock", - "outputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "metaHash", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "prover", - "type": "address" - }, - { - "internalType": "uint64", - "name": "proposedAt", - "type": "uint64" - }, - { - "internalType": "uint16", - "name": "nextForkChoiceId", - "type": "uint16" - }, - { - "internalType": "uint16", - "name": "verifiedForkChoiceId", - "type": "uint16" - }, - { - "internalType": "uint64", - "name": "blockId", - "type": "uint64" - }, - { - "internalType": "uint96", - "name": "proofBond", - "type": "uint96" - }, - { - "internalType": "uint16", - "name": "proofWindow", - "type": "uint16" - } - ], - "internalType": "struct TaikoData.Block", - "name": "blk", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getConfig", - "outputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "bool", - "name": "relaySignalRoot", - "type": "bool" - }, - { - "internalType": "uint64", - "name": "blockMaxProposals", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "blockRingBufferSize", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "blockMaxVerificationsPerTx", - "type": "uint64" - }, - { - "internalType": "uint32", - "name": "blockMaxGasLimit", - "type": "uint32" - }, - { - "internalType": "uint32", - "name": "blockFeeBaseGas", - "type": "uint32" - }, - { - "internalType": "uint24", - "name": "blockMaxTxListBytes", - "type": "uint24" - }, - { - "internalType": "uint256", - "name": "blockTxListExpiry", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "proposerRewardPerSecond", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "proposerRewardMax", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "proofRegularCooldown", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "proofOracleCooldown", - "type": "uint256" - }, - { - "internalType": "uint16", - "name": "proofWindow", - "type": "uint16" - }, - { - "internalType": "uint96", - "name": "proofBond", - "type": "uint96" - }, - { - "internalType": "bool", - "name": "skipProverAssignmentVerificaiton", - "type": "bool" - }, - { - "internalType": "uint256", - "name": "ethDepositRingBufferSize", - "type": "uint256" - }, - { - "internalType": "uint64", - "name": "ethDepositMinCountPerBlock", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "ethDepositMaxCountPerBlock", - "type": "uint64" - }, - { - "internalType": "uint96", - "name": "ethDepositMinAmount", - "type": "uint96" - }, - { - "internalType": "uint96", - "name": "ethDepositMaxAmount", - "type": "uint96" - }, - { - "internalType": "uint256", - "name": "ethDepositGas", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "ethDepositMaxFee", - "type": "uint256" - } - ], - "internalType": "struct TaikoData.Config", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "blockId", - "type": "uint64" - } - ], - "name": "getCrossChainBlockHash", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "blockId", - "type": "uint64" - } - ], - "name": "getCrossChainSignalRoot", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "blockId", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "parentHash", - "type": "bytes32" - } - ], - "name": "getForkChoice", - "outputs": [ - { - "components": [ - { - "internalType": "bytes32", - "name": "key", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "blockHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "signalRoot", - "type": "bytes32" - }, - { - "internalType": "address", - "name": "prover", - "type": "address" - }, - { - "internalType": "uint64", - "name": "provenAt", - "type": "uint64" - } - ], - "internalType": "struct TaikoData.ForkChoice", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getStateVariables", - "outputs": [ - { - "components": [ - { - "internalType": "uint64", - "name": "genesisHeight", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "genesisTimestamp", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "numBlocks", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "lastVerifiedBlockId", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "nextEthDepositToProcess", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "numEthDeposits", - "type": "uint64" - } - ], - "internalType": "struct TaikoData.StateVariables", - "name": "", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "addr", - "type": "address" - } - ], - "name": "getTaikoTokenBalance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint16", - "name": "id", - "type": "uint16" - } - ], - "name": "getVerifierName", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_addressManager", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "_genesisBlockHash", - "type": "bytes32" - } - ], - "name": "init", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes", - "name": "input", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "assignment", - "type": "bytes" - }, - { - "internalType": "bytes", - "name": "txList", - "type": "bytes" - } - ], - "name": "proposeBlock", - "outputs": [ - { - "components": [ - { - "internalType": "uint64", - "name": "id", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "timestamp", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "l1Height", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "l1Hash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "mixHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "txListHash", - "type": "bytes32" - }, - { - "internalType": "uint24", - "name": "txListByteStart", - "type": "uint24" - }, - { - "internalType": "uint24", - "name": "txListByteEnd", - "type": "uint24" - }, - { - "internalType": "uint32", - "name": "gasLimit", - "type": "uint32" - }, - { - "internalType": "address", - "name": "beneficiary", - "type": "address" - }, - { - "components": [ - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint96", - "name": "amount", - "type": "uint96" - }, - { - "internalType": "uint64", - "name": "id", - "type": "uint64" - } - ], - "internalType": "struct TaikoData.EthDeposit[]", - "name": "depositsProcessed", - "type": "tuple[]" - } - ], - "internalType": "struct TaikoData.BlockMetadata", - "name": "meta", - "type": "tuple" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "blockId", - "type": "uint64" - }, - { - "internalType": "bytes", - "name": "input", - "type": "bytes" - } - ], - "name": "proveBlock", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "name", - "type": "bytes32" - }, - { - "internalType": "bool", - "name": "allowZeroAddress", - "type": "bool" - } - ], - "name": "resolve", - "outputs": [ - { - "internalType": "address payable", - "name": "addr", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "name", - "type": "bytes32" - }, - { - "internalType": "bool", - "name": "allowZeroAddress", - "type": "bool" - } - ], - "name": "resolve", - "outputs": [ - { - "internalType": "address payable", - "name": "addr", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAddressManager", - "type": "address" - } - ], - "name": "setAddressManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "state", - "outputs": [ - { - "components": [ - { - "internalType": "uint64", - "name": "genesisHeight", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "genesisTimestamp", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "numEthDeposits", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "nextEthDepositToProcess", - "type": "uint64" - } - ], - "internalType": "struct TaikoData.SlotA", - "name": "slotA", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint64", - "name": "numBlocks", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "nextEthDepositToProcess", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "lastVerifiedAt", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "lastVerifiedBlockId", - "type": "uint64" - } - ], - "internalType": "struct TaikoData.SlotB", - "name": "slotB", - "type": "tuple" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "maxBlocks", - "type": "uint64" - } - ], - "name": "verifyBlocks", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "withdrawTaikoToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } -] diff --git a/packages/relayer/TokenVault.json b/packages/relayer/TokenVault.json deleted file mode 100644 index 63b7fcee663..00000000000 --- a/packages/relayer/TokenVault.json +++ /dev/null @@ -1,734 +0,0 @@ -[ - { - "inputs": [], - "name": "RESOLVER_DENIED", - "type": "error" - }, - { - "inputs": [], - "name": "RESOLVER_INVALID_ADDR", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "name", - "type": "bytes32" - } - ], - "name": "RESOLVER_ZERO_ADDR", - "type": "error" - }, - { - "inputs": [], - "name": "TOKENVAULT_CANONICAL_TOKEN_NOT_FOUND", - "type": "error" - }, - { - "inputs": [], - "name": "TOKENVAULT_INVALID_AMOUNT", - "type": "error" - }, - { - "inputs": [], - "name": "TOKENVAULT_INVALID_OWNER", - "type": "error" - }, - { - "inputs": [], - "name": "TOKENVAULT_INVALID_SENDER", - "type": "error" - }, - { - "inputs": [], - "name": "TOKENVAULT_INVALID_SRC_CHAIN_ID", - "type": "error" - }, - { - "inputs": [], - "name": "TOKENVAULT_INVALID_TO", - "type": "error" - }, - { - "inputs": [], - "name": "TOKENVAULT_INVALID_TOKEN", - "type": "error" - }, - { - "inputs": [], - "name": "TOKENVAULT_INVALID_VALUE", - "type": "error" - }, - { - "inputs": [], - "name": "TOKENVAULT_MESSAGE_NOT_FAILED", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "addressManager", - "type": "address" - } - ], - "name": "AddressManagerChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "srcChainId", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "canonicalToken", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "bridgedToken", - "type": "address" - }, - { - "indexed": false, - "internalType": "string", - "name": "canonicalTokenSymbol", - "type": "string" - }, - { - "indexed": false, - "internalType": "string", - "name": "canonicalTokenName", - "type": "string" - }, - { - "indexed": false, - "internalType": "uint8", - "name": "canonicalTokenDecimal", - "type": "uint8" - } - ], - "name": "BridgedERC20Deployed", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "msgHash", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "srcChainId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ERC20Received", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "msgHash", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ERC20Released", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "msgHash", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "destChainId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "ERC20Sent", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "bytes32", - "name": "msgHash", - "type": "bytes32" - }, - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "destChainId", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "EtherSent", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "inputs": [], - "name": "addressManager", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "bridgedAddress", - "type": "address" - } - ], - "name": "bridgedToCanonical", - "outputs": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "internalType": "uint8", - "name": "decimals", - "type": "uint8" - }, - { - "internalType": "string", - "name": "symbol", - "type": "string" - }, - { - "internalType": "string", - "name": "name", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "canonicalAddress", - "type": "address" - } - ], - "name": "canonicalToBridged", - "outputs": [ - { - "internalType": "address", - "name": "bridgedAddress", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "addressManager", - "type": "address" - } - ], - "name": "init", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "tokenAddress", - "type": "address" - } - ], - "name": "isBridgedToken", - "outputs": [ - { - "internalType": "bool", - "name": "isBridged", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "msgHash", - "type": "bytes32" - } - ], - "name": "messageDeposits", - "outputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "addr", - "type": "address" - }, - { - "internalType": "uint8", - "name": "decimals", - "type": "uint8" - }, - { - "internalType": "string", - "name": "symbol", - "type": "string" - }, - { - "internalType": "string", - "name": "name", - "type": "string" - } - ], - "internalType": "struct TokenVault.CanonicalERC20", - "name": "canonicalToken", - "type": "tuple" - }, - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "receiveERC20", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "id", - "type": "uint256" - }, - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "srcChainId", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "destChainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "address", - "name": "refundAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "depositValue", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "callValue", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "processingFee", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - }, - { - "internalType": "string", - "name": "memo", - "type": "string" - } - ], - "internalType": "struct IBridge.Message", - "name": "message", - "type": "tuple" - }, - { - "internalType": "bytes", - "name": "proof", - "type": "bytes" - } - ], - "name": "releaseERC20", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "name", - "type": "bytes32" - }, - { - "internalType": "bool", - "name": "allowZeroAddress", - "type": "bool" - } - ], - "name": "resolve", - "outputs": [ - { - "internalType": "address payable", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "name", - "type": "bytes32" - }, - { - "internalType": "bool", - "name": "allowZeroAddress", - "type": "bool" - } - ], - "name": "resolve", - "outputs": [ - { - "internalType": "address payable", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "destChainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "gasLimit", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "processingFee", - "type": "uint256" - }, - { - "internalType": "address", - "name": "refundAddress", - "type": "address" - }, - { - "internalType": "string", - "name": "memo", - "type": "string" - } - ], - "name": "sendERC20", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAddressManager", - "type": "address" - } - ], - "name": "setAddressManager", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/packages/relayer/db.go b/packages/relayer/db.go new file mode 100644 index 00000000000..02798e0e236 --- /dev/null +++ b/packages/relayer/db.go @@ -0,0 +1,28 @@ +package relayer + +import ( + "database/sql" + + "github.com/cyberhorsey/errors" + "gorm.io/gorm" +) + +var ( + ErrNoDB = errors.Validation.NewWithKeyAndDetail("ERR_NO_DB", "DB is required") +) + +type DBConnectionOpts struct { + Name string + Password string + Host string + Database string + MaxIdleConns uint64 + MaxOpenConns uint64 + MaxConnLifetime uint64 + OpenFunc func(dsn string) (DB, error) +} + +type DB interface { + DB() (*sql.DB, error) + GormDB() *gorm.DB +} diff --git a/packages/relayer/flags.go b/packages/relayer/flags.go deleted file mode 100644 index f7aa32b4120..00000000000 --- a/packages/relayer/flags.go +++ /dev/null @@ -1,35 +0,0 @@ -package relayer - -type Mode string - -var ( - SyncMode Mode = "sync" - ResyncMode Mode = "resync" - Modes = []Mode{SyncMode, ResyncMode} -) - -type Layer string - -var ( - L1 Layer = "l1" - L2 Layer = "l2" - Both Layer = "both" - Layers = []Layer{L1, L2, Both} -) - -type WatchMode string - -var ( - FilterWatchMode WatchMode = "filter" - SubscribeWatchMode WatchMode = "subscribe" - FilterAndSubscribeWatchMode WatchMode = "filter-and-subscribe" - WatchModes = []WatchMode{FilterWatchMode, SubscribeWatchMode} -) - -type HTTPOnly bool - -type ProfitableOnly bool - -type Indexer bool - -type Processor bool diff --git a/packages/relayer/http/errors.go b/packages/relayer/indexer/http/errors.go similarity index 100% rename from packages/relayer/http/errors.go rename to packages/relayer/indexer/http/errors.go diff --git a/packages/relayer/http/get_block_info.go b/packages/relayer/indexer/http/get_block_info.go similarity index 100% rename from packages/relayer/http/get_block_info.go rename to packages/relayer/indexer/http/get_block_info.go diff --git a/packages/relayer/http/get_events_by_address.go b/packages/relayer/indexer/http/get_events_by_address.go similarity index 100% rename from packages/relayer/http/get_events_by_address.go rename to packages/relayer/indexer/http/get_events_by_address.go diff --git a/packages/relayer/http/get_events_by_address_test.go b/packages/relayer/indexer/http/get_events_by_address_test.go similarity index 100% rename from packages/relayer/http/get_events_by_address_test.go rename to packages/relayer/indexer/http/get_events_by_address_test.go diff --git a/packages/relayer/http/routes.go b/packages/relayer/indexer/http/routes.go similarity index 100% rename from packages/relayer/http/routes.go rename to packages/relayer/indexer/http/routes.go diff --git a/packages/relayer/http/server.go b/packages/relayer/indexer/http/server.go similarity index 100% rename from packages/relayer/http/server.go rename to packages/relayer/indexer/http/server.go diff --git a/packages/relayer/http/server_test.go b/packages/relayer/indexer/http/server_test.go similarity index 100% rename from packages/relayer/http/server_test.go rename to packages/relayer/indexer/http/server_test.go diff --git a/packages/relayer/indexer/indexer.go b/packages/relayer/indexer/indexer.go index fbb540fbd5a..de446e0d012 100644 --- a/packages/relayer/indexer/indexer.go +++ b/packages/relayer/indexer/indexer.go @@ -19,7 +19,7 @@ import ( "github.com/taikoxyz/taiko-mono/packages/relayer" "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/bridge" "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/taikol1" - "github.com/taikoxyz/taiko-mono/packages/relayer/http" + "github.com/taikoxyz/taiko-mono/packages/relayer/indexer/http" "github.com/taikoxyz/taiko-mono/packages/relayer/queue" "github.com/taikoxyz/taiko-mono/packages/relayer/repo" "github.com/urfave/cli/v2" diff --git a/packages/relayer/processor/process_message.go b/packages/relayer/processor/process_message.go index f1ac0143014..ffc1f0a69ab 100644 --- a/packages/relayer/processor/process_message.go +++ b/packages/relayer/processor/process_message.go @@ -21,6 +21,33 @@ import ( "github.com/taikoxyz/taiko-mono/packages/relayer/queue" ) +var ( + errUnprocessable = errors.New("message is unprocessable") +) + +func (p *Processor) eventStatusFromMsgHash( + ctx context.Context, + gasLimit *big.Int, + signal [32]byte, +) (relayer.EventStatus, error) { + var eventStatus relayer.EventStatus + + messageStatus, err := p.destBridge.GetMessageStatus(nil, signal) + if err != nil { + return 0, errors.Wrap(err, "svc.destBridge.GetMessageStatus") + } + + eventStatus = relayer.EventStatus(messageStatus) + if eventStatus == relayer.EventStatusNew { + if gasLimit == nil || gasLimit.Cmp(common.Big0) == 0 { + // if gasLimit is 0, relayer can not process this. + eventStatus = relayer.EventStatusNewOnlyOwner + } + } + + return eventStatus, nil +} + // Process prepares and calls `processMessage` on the bridge. // the proof must be generated from the gethclient's eth_getProof via the Prover, // then rlp-encoded and combined as a singular byte slice, @@ -39,6 +66,15 @@ func (p *Processor) processMessage( return errors.New("only user can process this, gasLimit set to 0") } + eventStatus, err := p.eventStatusFromMsgHash(ctx, msgBody.Event.Message.GasLimit, msgBody.Event.MsgHash) + if err != nil { + return errors.Wrap(err, "p.eventStatusFromMsgHash") + } + + if !canProcessMessage(ctx, eventStatus, msgBody.Event.Message.User, p.relayerAddr) { + return errUnprocessable + } + if err := p.waitForConfirmations(ctx, msgBody.Event.Raw.TxHash, msgBody.Event.Raw.BlockNumber); err != nil { return errors.Wrap(err, "p.waitForConfirmations") } diff --git a/packages/relayer/processor/processor.go b/packages/relayer/processor/processor.go index 617f05b70b3..4074447da84 100644 --- a/packages/relayer/processor/processor.go +++ b/packages/relayer/processor/processor.go @@ -4,6 +4,7 @@ import ( "context" "crypto/ecdsa" "database/sql" + "errors" "fmt" "log/slog" "math/big" @@ -263,7 +264,11 @@ func (p *Processor) eventLoop(ctx context.Context) { return case msg := <-p.msgCh: if err := p.processMessage(ctx, msg); err != nil { - slog.Error("err processing message", "err", err) + if !errors.Is(err, errUnprocessable) { + slog.Error("err processing message", "err", err) + } else { + slog.Info("unprocessable message", "err", errUnprocessable) + } if err := p.queue.Nack(ctx, msg); err != nil { slog.Error("Err nacking message", "err", err) diff --git a/packages/relayer/processor/processor_test.go b/packages/relayer/processor/processor_test.go index 612218cf791..3bae15a81dc 100644 --- a/packages/relayer/processor/processor_test.go +++ b/packages/relayer/processor/processor_test.go @@ -4,14 +4,13 @@ import ( "sync" "github.com/ethereum/go-ethereum/crypto" - "github.com/taikoxyz/taiko-mono/packages/relayer" "github.com/taikoxyz/taiko-mono/packages/relayer/mock" "github.com/taikoxyz/taiko-mono/packages/relayer/proof" ) var dummyEcdsaKey = "8da4ef21b864d2cc526dbdb2a120bd2874c36c9d0a1fb7f8c63d7f7a8b41de8f" -func newTestProcessor(profitableOnly relayer.ProfitableOnly) *Processor { +func newTestProcessor(profitableOnly bool) *Processor { privateKey, _ := crypto.HexToECDSA(dummyEcdsaKey) prover, _ := proof.New( @@ -29,7 +28,7 @@ func newTestProcessor(profitableOnly relayer.ProfitableOnly) *Processor { destHeaderSyncer: &mock.HeaderSyncer{}, prover: prover, rpc: &mock.Caller{}, - profitableOnly: false, + profitableOnly: profitableOnly, headerSyncIntervalSeconds: 1, confTimeoutInSeconds: 900, confirmations: 1, From c96648d377f31fdbbcb9cbabd8d20cc79104c1df Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Thu, 31 Aug 2023 12:15:35 -0700 Subject: [PATCH 08/82] better log --- packages/relayer/processor/processor.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/relayer/processor/processor.go b/packages/relayer/processor/processor.go index 4074447da84..69a967b086d 100644 --- a/packages/relayer/processor/processor.go +++ b/packages/relayer/processor/processor.go @@ -265,13 +265,13 @@ func (p *Processor) eventLoop(ctx context.Context) { case msg := <-p.msgCh: if err := p.processMessage(ctx, msg); err != nil { if !errors.Is(err, errUnprocessable) { - slog.Error("err processing message", "err", err) + slog.Error("err processing message", "err", err.Error()) } else { slog.Info("unprocessable message", "err", errUnprocessable) } if err := p.queue.Nack(ctx, msg); err != nil { - slog.Error("Err nacking message", "err", err) + slog.Error("Err nacking message", "err", err.Error()) } } } From 1d3791a086fb72d84a926e2d6925799a4607a71e Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Thu, 31 Aug 2023 12:19:54 -0700 Subject: [PATCH 09/82] missing log should be slog --- packages/relayer/proof/encoded_signal_proof.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/relayer/proof/encoded_signal_proof.go b/packages/relayer/proof/encoded_signal_proof.go index 1d34d6980f5..8a1730d0640 100644 --- a/packages/relayer/proof/encoded_signal_proof.go +++ b/packages/relayer/proof/encoded_signal_proof.go @@ -4,7 +4,8 @@ import ( "context" "math/big" - "github.com/labstack/gommon/log" + "log/slog" + "github.com/taikoxyz/taiko-mono/packages/relayer" "github.com/taikoxyz/taiko-mono/packages/relayer/encoding" @@ -58,7 +59,11 @@ func (p *Prover) encodedStorageProof( ) ([]byte, error) { var ethProof StorageProof - log.Infof("getting proof for: %v, key: %v, blockNum: %v", signalServiceAddress, key, blockNumber) + slog.Info("getting proof", + "signalServiceAddress", signalServiceAddress.Hex(), + "key", key, + "blockNum", blockNumber, + ) err := c.CallContext(ctx, ðProof, @@ -71,7 +76,7 @@ func (p *Prover) encodedStorageProof( return nil, errors.Wrap(err, "c.CallContext") } - log.Infof("proof: %v", new(big.Int).SetBytes(ethProof.StorageProof[0].Value).Int64()) + slog.Info("proof generated", "value", new(big.Int).SetBytes(ethProof.StorageProof[0].Value).Int64()) if new(big.Int).SetBytes(ethProof.StorageProof[0].Value).Int64() != int64(1) { return nil, errors.New("proof will not be valid, expected storageProof to be 1 but was not") From 148a22b80c86cff0fb17bb907a2b3dda418b336a Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Thu, 31 Aug 2023 12:25:07 -0700 Subject: [PATCH 10/82] test --- packages/relayer/processor/process_message_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/relayer/processor/process_message_test.go b/packages/relayer/processor/process_message_test.go index 6dd8f615b46..b422bd55b72 100644 --- a/packages/relayer/processor/process_message_test.go +++ b/packages/relayer/processor/process_message_test.go @@ -40,7 +40,7 @@ func Test_sendProcessMessageCall(t *testing.T) { assert.Equal(t, p.destNonce, mock.PendingNonce) } -func Test_ProcessMessage_messageNotReceived(t *testing.T) { +func Test_ProcessMessage_messageUnprocessable(t *testing.T) { p := newTestProcessor(true) body := &queue.QueueMessageBody{ Event: &bridge.BridgeMessageSent{ @@ -66,7 +66,7 @@ func Test_ProcessMessage_messageNotReceived(t *testing.T) { } err = p.processMessage(context.Background(), msg) - assert.EqualError(t, err, "message not received") + assert.EqualError(t, err, "message is unprocessable") } func Test_ProcessMessage_gasLimit0(t *testing.T) { From 4b44c8000fa8ee8d88f1814e0a63b371468bbebf Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Thu, 31 Aug 2023 14:10:29 -0700 Subject: [PATCH 11/82] http port --- packages/relayer/cmd/flags/indexer.go | 8 ++++++++ packages/relayer/indexer/config.go | 2 ++ packages/relayer/indexer/indexer.go | 15 +++++++++++++-- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/packages/relayer/cmd/flags/indexer.go b/packages/relayer/cmd/flags/indexer.go index 833438fb4a0..f4c6c1540be 100644 --- a/packages/relayer/cmd/flags/indexer.go +++ b/packages/relayer/cmd/flags/indexer.go @@ -61,11 +61,19 @@ var ( Category: indexerCategory, EnvVars: []string{"SRC_TAIKO_ADDRESS"}, } + HTTPPort = &cli.Uint64Flag{ + Name: "http.port", + Usage: "Port to run http server on", + Category: indexerCategory, + Value: 4102, + EnvVars: []string{"HTTP_PORT"}, + } ) var IndexerFlags = MergeFlags(CommonFlags, []cli.Flag{ SrcBridgeAddress, // optional + HTTPPort, SrcTaikoAddress, BlockBatchSize, MaxNumGoroutines, diff --git a/packages/relayer/indexer/config.go b/packages/relayer/indexer/config.go index 8b4aebdf3f9..aa564a3ec35 100644 --- a/packages/relayer/indexer/config.go +++ b/packages/relayer/indexer/config.go @@ -41,6 +41,7 @@ type Config struct { SubscriptionBackoff uint64 SyncMode SyncMode WatchMode WatchMode + HTTPPort uint64 OpenQueueFunc func() (queue.Queue, error) OpenDBFunc func() (DB, error) } @@ -70,6 +71,7 @@ func NewConfigFromCliContext(c *cli.Context) (*Config, error) { SubscriptionBackoff: c.Uint64(flags.SubscriptionBackoff.Name), WatchMode: WatchMode(c.String(flags.WatchMode.Name)), SyncMode: SyncMode(c.String(flags.SyncMode.Name)), + HTTPPort: c.Uint64(flags.HTTPPort.Name), OpenDBFunc: func() (DB, error) { return db.OpenDBConnection(db.DBConnectionOpts{ Name: c.String(flags.DatabaseUsername.Name), diff --git a/packages/relayer/indexer/indexer.go b/packages/relayer/indexer/indexer.go index de446e0d012..6a6f4a040bb 100644 --- a/packages/relayer/indexer/indexer.go +++ b/packages/relayer/indexer/indexer.go @@ -86,7 +86,8 @@ type Indexer struct { watchMode WatchMode syncMode SyncMode - srv *http.Server + srv *http.Server + httpPort uint64 } func (i *Indexer) InitFromCli(ctx context.Context, c *cli.Context) error { @@ -179,6 +180,7 @@ func InitFromConfig(ctx context.Context, i *Indexer, cfg *Config) (err error) { i.queue = q i.srv = srv + i.httpPort = cfg.HTTPPort i.srcChainId = chainID @@ -194,10 +196,19 @@ func (i *Indexer) Name() string { // TODO func (i *Indexer) Close(ctx context.Context) { - + if err := i.srv.Shutdown(ctx); err != nil { + slog.Error("srv shutdown", "error", err) + } } +// nolint: funlen func (i *Indexer) Start() error { + go func() { + if err := i.srv.Start(fmt.Sprintf(":%v", i.httpPort)); err != nil { + slog.Error("http srv start", "error", err.Error()) + } + }() + ctx := context.Background() if err := i.queue.Start(ctx, i.queueName()); err != nil { From 38b97d077757d6bbbcf7a935b70bb09979b49e11 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Thu, 31 Aug 2023 14:19:30 -0700 Subject: [PATCH 12/82] test --- packages/relayer/indexer/indexer_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/relayer/indexer/indexer_test.go b/packages/relayer/indexer/indexer_test.go index 8b58b72a914..fb36ae6edd2 100644 --- a/packages/relayer/indexer/indexer_test.go +++ b/packages/relayer/indexer/indexer_test.go @@ -23,5 +23,6 @@ func newTestService(syncMode SyncMode, watchMode WatchMode) (*Indexer, relayer.B syncMode: syncMode, watchMode: watchMode, + httpPort: 4102, }, b } From b6c639082603d4b390425a8ea4b5e0dade464fe0 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Thu, 31 Aug 2023 15:08:03 -0700 Subject: [PATCH 13/82] . --- packages/relayer/cmd/main.go | 2 +- packages/relayer/indexer/http/server.go | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/relayer/cmd/main.go b/packages/relayer/cmd/main.go index 1955413bac1..dd16fbc0d08 100644 --- a/packages/relayer/cmd/main.go +++ b/packages/relayer/cmd/main.go @@ -17,7 +17,7 @@ func main() { // attempt to load a .env file to overwrite CLI flags, but allow it to not // exist. - _ = godotenv.Load(".l1processor.env") + _ = godotenv.Load(".env") app.Name = "Taiko Relayer" app.Usage = "The taiko relayer softwares command line interface" diff --git a/packages/relayer/indexer/http/server.go b/packages/relayer/indexer/http/server.go index 23b87e39ee1..a9734577d94 100644 --- a/packages/relayer/indexer/http/server.go +++ b/packages/relayer/indexer/http/server.go @@ -136,8 +136,6 @@ func (srv *Server) configureMiddleware(corsOrigins []string) { AllowHeaders: []string{echo.HeaderOrigin, echo.HeaderContentType, echo.HeaderAccept}, AllowMethods: []string{http.MethodGet, http.MethodHead}, })) - - srv.configureAndStartPrometheus() } func (srv *Server) configureAndStartPrometheus() { From df384736b21fd09226bee7a6defa72e3202d25cb Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Thu, 31 Aug 2023 16:47:40 -0700 Subject: [PATCH 14/82] test --- packages/relayer/cmd/main.go | 2 +- packages/relayer/indexer/indexer_test.go | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/relayer/cmd/main.go b/packages/relayer/cmd/main.go index dd16fbc0d08..92368c5439b 100644 --- a/packages/relayer/cmd/main.go +++ b/packages/relayer/cmd/main.go @@ -17,7 +17,7 @@ func main() { // attempt to load a .env file to overwrite CLI flags, but allow it to not // exist. - _ = godotenv.Load(".env") + _ = godotenv.Load(".l1indexer.env") app.Name = "Taiko Relayer" app.Usage = "The taiko relayer softwares command line interface" diff --git a/packages/relayer/indexer/indexer_test.go b/packages/relayer/indexer/indexer_test.go index fb36ae6edd2..d8d03557231 100644 --- a/packages/relayer/indexer/indexer_test.go +++ b/packages/relayer/indexer/indexer_test.go @@ -1,12 +1,23 @@ package indexer import ( + "github.com/ethereum/go-ethereum/ethclient" + "github.com/labstack/echo/v4" "github.com/taikoxyz/taiko-mono/packages/relayer" + "github.com/taikoxyz/taiko-mono/packages/relayer/indexer/http" "github.com/taikoxyz/taiko-mono/packages/relayer/mock" ) func newTestService(syncMode SyncMode, watchMode WatchMode) (*Indexer, relayer.Bridge) { b := &mock.Bridge{} + srv, _ := http.NewServer(http.NewServerOpts{ + Echo: echo.New(), + EventRepo: &mock.EventRepository{}, + BlockRepo: &mock.BlockRepository{}, + SrcEthClient: ðclient.Client{}, + DestEthClient: ðclient.Client{}, + CorsOrigins: []string{}, + }) return &Indexer{ blockRepo: &mock.BlockRepository{}, @@ -24,5 +35,6 @@ func newTestService(syncMode SyncMode, watchMode WatchMode) (*Indexer, relayer.B syncMode: syncMode, watchMode: watchMode, httpPort: 4102, + srv: srv, }, b } From f94293f333a9f515a32deab66400acee6071d0ca Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Thu, 31 Aug 2023 16:49:32 -0700 Subject: [PATCH 15/82] .env --- packages/relayer/cmd/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/relayer/cmd/main.go b/packages/relayer/cmd/main.go index 92368c5439b..dd16fbc0d08 100644 --- a/packages/relayer/cmd/main.go +++ b/packages/relayer/cmd/main.go @@ -17,7 +17,7 @@ func main() { // attempt to load a .env file to overwrite CLI flags, but allow it to not // exist. - _ = godotenv.Load(".l1indexer.env") + _ = godotenv.Load(".env") app.Name = "Taiko Relayer" app.Usage = "The taiko relayer softwares command line interface" From 62ebf3c1334939a04a6ebe0ac1c2188166e22458 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Thu, 31 Aug 2023 17:17:42 -0700 Subject: [PATCH 16/82] output to stdout --- packages/relayer/cmd/main.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/relayer/cmd/main.go b/packages/relayer/cmd/main.go index dd16fbc0d08..81e7f3c20c2 100644 --- a/packages/relayer/cmd/main.go +++ b/packages/relayer/cmd/main.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "log" "os" "github.com/joho/godotenv" @@ -15,6 +16,7 @@ import ( func main() { app := cli.NewApp() + log.SetOutput(os.Stdout) // attempt to load a .env file to overwrite CLI flags, but allow it to not // exist. _ = godotenv.Load(".env") From 9e12865bb0d60d4242a7251d36d55b6623daf832 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Thu, 31 Aug 2023 17:50:03 -0700 Subject: [PATCH 17/82] server fix --- packages/relayer/cmd/main.go | 2 +- packages/relayer/indexer/indexer.go | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/relayer/cmd/main.go b/packages/relayer/cmd/main.go index 81e7f3c20c2..d1d36a292f8 100644 --- a/packages/relayer/cmd/main.go +++ b/packages/relayer/cmd/main.go @@ -19,7 +19,7 @@ func main() { log.SetOutput(os.Stdout) // attempt to load a .env file to overwrite CLI flags, but allow it to not // exist. - _ = godotenv.Load(".env") + _ = godotenv.Load(".l1indexer.env") app.Name = "Taiko Relayer" app.Usage = "The taiko relayer softwares command line interface" diff --git a/packages/relayer/indexer/indexer.go b/packages/relayer/indexer/indexer.go index 6a6f4a040bb..023a62fcc2c 100644 --- a/packages/relayer/indexer/indexer.go +++ b/packages/relayer/indexer/indexer.go @@ -215,6 +215,10 @@ func (i *Indexer) Start() error { return err } + return i.filter(ctx) +} + +func (i *Indexer) filter(ctx context.Context) error { chainID, err := i.srcEthClient.ChainID(ctx) if err != nil { return errors.Wrap(err, "i.srcEthClient.ChainID()") @@ -333,9 +337,8 @@ func (i *Indexer) Start() error { } } - log.Infof( - "chain id %v indexer fully caught up, checking latest block number to see if it's advanced", - chainID.Uint64(), + slog.Info( + "indexer fully caught up, checking latest block number to see if it's advanced", ) latestBlock, err := i.srcEthClient.HeaderByNumber(ctx, nil) From a4e727775287d4287300dda442f9a2d2ca072d62 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Thu, 31 Aug 2023 18:11:16 -0700 Subject: [PATCH 18/82] use srcchain and dest chain as queue --- packages/relayer/indexer/indexer.go | 15 +++++++++++---- packages/relayer/processor/processor.go | 16 ++++++++++++---- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/packages/relayer/indexer/indexer.go b/packages/relayer/indexer/indexer.go index 023a62fcc2c..327b51ce9ed 100644 --- a/packages/relayer/indexer/indexer.go +++ b/packages/relayer/indexer/indexer.go @@ -81,7 +81,8 @@ type Indexer struct { queue queue.Queue - srcChainId *big.Int + srcChainId *big.Int + destChainId *big.Int watchMode WatchMode syncMode SyncMode @@ -160,9 +161,14 @@ func InitFromConfig(ctx context.Context, i *Indexer, cfg *Config) (err error) { } } - chainID, err := srcEthClient.ChainID(context.Background()) + srcChainID, err := srcEthClient.ChainID(context.Background()) if err != nil { - return errors.Wrap(err, "cfg.EthClient.ChainID") + return errors.Wrap(err, "srcEthClient.ChainID") + } + + destChainID, err := destEthClient.ChainID(context.Background()) + if err != nil { + return errors.Wrap(err, "destEthClient.ChainID") } i.blockRepo = blockRepository @@ -182,7 +188,8 @@ func InitFromConfig(ctx context.Context, i *Indexer, cfg *Config) (err error) { i.srv = srv i.httpPort = cfg.HTTPPort - i.srcChainId = chainID + i.srcChainId = srcChainID + i.destChainId = destChainID i.syncMode = cfg.SyncMode i.watchMode = cfg.WatchMode diff --git a/packages/relayer/processor/processor.go b/packages/relayer/processor/processor.go index 69a967b086d..64357f8ef3d 100644 --- a/packages/relayer/processor/processor.go +++ b/packages/relayer/processor/processor.go @@ -79,7 +79,8 @@ type Processor struct { wg *sync.WaitGroup - srcChainId *big.Int + srcChainId *big.Int + destChainId *big.Int } func (p *Processor) InitFromCli(ctx context.Context, c *cli.Context) error { @@ -163,7 +164,12 @@ func InitFromConfig(ctx context.Context, p *Processor, cfg *Config) error { return err } - chainID, err := srcEthClient.ChainID(context.Background()) + srcChainID, err := srcEthClient.ChainID(context.Background()) + if err != nil { + return err + } + + destChainID, err := destEthClient.ChainID(context.Background()) if err != nil { return err } @@ -206,7 +212,9 @@ func InitFromConfig(ctx context.Context, p *Processor, cfg *Config) error { p.queue = q - p.srcChainId = chainID + p.srcChainId = srcChainID + p.destChainId = destChainID + p.headerSyncIntervalSeconds = int64(cfg.HeaderSyncInterval) p.confTimeoutInSeconds = int64(cfg.ConfirmationsTimeout) p.confirmations = cfg.Confirmations @@ -250,7 +258,7 @@ func (p *Processor) Start() error { } func (p *Processor) queueName() string { - return fmt.Sprintf("%v-queue", p.srcChainId.String()) + return fmt.Sprintf("%v--%v-queue", p.srcChainId.String(), p.destChainId.String()) } func (p *Processor) eventLoop(ctx context.Context) { From 5d2534b126c1cf81f7e0e9524f64561f28684c30 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Thu, 31 Aug 2023 18:11:31 -0700 Subject: [PATCH 19/82] default .env --- packages/relayer/cmd/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/relayer/cmd/main.go b/packages/relayer/cmd/main.go index d1d36a292f8..81e7f3c20c2 100644 --- a/packages/relayer/cmd/main.go +++ b/packages/relayer/cmd/main.go @@ -19,7 +19,7 @@ func main() { log.SetOutput(os.Stdout) // attempt to load a .env file to overwrite CLI flags, but allow it to not // exist. - _ = godotenv.Load(".l1indexer.env") + _ = godotenv.Load(".env") app.Name = "Taiko Relayer" app.Usage = "The taiko relayer softwares command line interface" From 1ff6a99174d31803f20f7e6467fe5d7bfd210410 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Thu, 31 Aug 2023 18:15:05 -0700 Subject: [PATCH 20/82] log --- packages/relayer/processor/can_process_message.go | 2 ++ packages/relayer/processor/processor.go | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/relayer/processor/can_process_message.go b/packages/relayer/processor/can_process_message.go index f4943d02440..758abbc5a20 100644 --- a/packages/relayer/processor/can_process_message.go +++ b/packages/relayer/processor/can_process_message.go @@ -28,5 +28,7 @@ func canProcessMessage( return true } + slog.Info("cant process message", "eventStatus", eventStatus) + return false } diff --git a/packages/relayer/processor/processor.go b/packages/relayer/processor/processor.go index 64357f8ef3d..ebbe087cfc2 100644 --- a/packages/relayer/processor/processor.go +++ b/packages/relayer/processor/processor.go @@ -274,8 +274,6 @@ func (p *Processor) eventLoop(ctx context.Context) { if err := p.processMessage(ctx, msg); err != nil { if !errors.Is(err, errUnprocessable) { slog.Error("err processing message", "err", err.Error()) - } else { - slog.Info("unprocessable message", "err", errUnprocessable) } if err := p.queue.Nack(ctx, msg); err != nil { From a2179590706b1537f76c02e98ea8f9bd3c1d3916 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Thu, 31 Aug 2023 18:15:24 -0700 Subject: [PATCH 21/82] log --- packages/relayer/processor/can_process_message.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/relayer/processor/can_process_message.go b/packages/relayer/processor/can_process_message.go index 758abbc5a20..2c2486c19f5 100644 --- a/packages/relayer/processor/can_process_message.go +++ b/packages/relayer/processor/can_process_message.go @@ -28,7 +28,7 @@ func canProcessMessage( return true } - slog.Info("cant process message", "eventStatus", eventStatus) + slog.Info("cant process message", "eventStatus", eventStatus.String()) return false } From 5b4ebaccf97ae0b19fa62b4a6aa2a295ac587e92 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Thu, 31 Aug 2023 18:28:23 -0700 Subject: [PATCH 22/82] queue name --- packages/relayer/indexer/indexer.go | 2 +- packages/relayer/processor/processor.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/relayer/indexer/indexer.go b/packages/relayer/indexer/indexer.go index 327b51ce9ed..848d35c5b8e 100644 --- a/packages/relayer/indexer/indexer.go +++ b/packages/relayer/indexer/indexer.go @@ -366,5 +366,5 @@ func (i *Indexer) filter(ctx context.Context) error { } func (i *Indexer) queueName() string { - return fmt.Sprintf("%v-queue", i.srcChainId.String()) + return fmt.Sprintf("%v-%v-queue", i.srcChainId.String(), i.destChainId.String()) } diff --git a/packages/relayer/processor/processor.go b/packages/relayer/processor/processor.go index ebbe087cfc2..bdd78a9696a 100644 --- a/packages/relayer/processor/processor.go +++ b/packages/relayer/processor/processor.go @@ -258,7 +258,7 @@ func (p *Processor) Start() error { } func (p *Processor) queueName() string { - return fmt.Sprintf("%v--%v-queue", p.srcChainId.String(), p.destChainId.String()) + return fmt.Sprintf("%v-%v-queue", p.srcChainId.String(), p.destChainId.String()) } func (p *Processor) eventLoop(ctx context.Context) { From 94c4d11d46b1f12ba416c103b5f3bb3bd543d67c Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Thu, 31 Aug 2023 21:12:13 -0700 Subject: [PATCH 23/82] ctx cancel for ggraceful processor shutdown --- packages/relayer/mock/queue.go | 3 ++- packages/relayer/processor/processor.go | 12 ++++++++++-- packages/relayer/queue/queue.go | 3 ++- packages/relayer/queue/rabbitmq/queue.go | 7 ++++++- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/packages/relayer/mock/queue.go b/packages/relayer/mock/queue.go index eb07b2b26c5..0d21cf31e54 100644 --- a/packages/relayer/mock/queue.go +++ b/packages/relayer/mock/queue.go @@ -2,6 +2,7 @@ package mock import ( "context" + "sync" "github.com/taikoxyz/taiko-mono/packages/relayer/queue" ) @@ -29,6 +30,6 @@ func (r *Queue) Nack(ctx context.Context, msg queue.Message) error { return nil } -func (r *Queue) Subscribe(ctx context.Context, msgChan chan<- queue.Message) error { +func (r *Queue) Subscribe(ctx context.Context, msgChan chan<- queue.Message, wg *sync.WaitGroup) error { return nil } diff --git a/packages/relayer/processor/processor.go b/packages/relayer/processor/processor.go index bdd78a9696a..1fc9c16e1b5 100644 --- a/packages/relayer/processor/processor.go +++ b/packages/relayer/processor/processor.go @@ -45,6 +45,8 @@ type ethClient interface { } type Processor struct { + cancel context.CancelFunc + eventRepo relayer.EventRepository queue queue.Queue @@ -237,17 +239,23 @@ func (p *Processor) Name() string { // TODO func (p *Processor) Close(ctx context.Context) { + p.cancel() + p.wg.Wait() } func (p *Processor) Start() error { - ctx := context.Background() + ctx, cancel := context.WithCancel(context.Background()) + + p.cancel = cancel if err := p.queue.Start(ctx, p.queueName()); err != nil { return err } - if err := p.queue.Subscribe(ctx, p.msgCh); err != nil { + p.wg.Add(1) + + if err := p.queue.Subscribe(ctx, p.msgCh, p.wg); err != nil { return err } diff --git a/packages/relayer/queue/queue.go b/packages/relayer/queue/queue.go index f4da0a36071..24d4bbe9fab 100644 --- a/packages/relayer/queue/queue.go +++ b/packages/relayer/queue/queue.go @@ -2,6 +2,7 @@ package queue import ( "context" + "sync" "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/bridge" ) @@ -10,7 +11,7 @@ type Queue interface { Start(ctx context.Context, queueName string) error Close(ctx context.Context) Publish(ctx context.Context, msg []byte) error - Subscribe(ctx context.Context, msgs chan<- Message) error + Subscribe(ctx context.Context, msgs chan<- Message, wg *sync.WaitGroup) error Ack(ctx context.Context, msg Message) error Nack(ctx context.Context, msg Message) error } diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 0bd89ae80ba..e366181f331 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log/slog" + "sync" amqp "github.com/rabbitmq/amqp091-go" "github.com/taikoxyz/taiko-mono/packages/relayer/queue" @@ -101,7 +102,11 @@ func (r *RabbitMQ) Nack(ctx context.Context, msg queue.Message) error { return rmqMsg.Nack(false, true) } -func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message) error { +func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, wg *sync.WaitGroup) error { + defer func() { + wg.Done() + }() + msgs, err := r.ch.Consume( r.queue.Name, "", From b213e9b5ba4cd30888d7241c92c054486f583ee4 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Thu, 31 Aug 2023 21:14:30 -0700 Subject: [PATCH 24/82] only non nil msgs --- packages/relayer/queue/rabbitmq/queue.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index e366181f331..403be901033 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -128,11 +128,13 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, case <-ctx.Done(): return case d := <-msgs: - slog.Info("rabbitmq message found", "msgId", d.MessageId) - { - msgChan <- queue.Message{ - Body: d.Body, - Internal: d, + if d.Body != nil { + slog.Info("rabbitmq message found", "msgId", d.MessageId) + { + msgChan <- queue.Message{ + Body: d.Body, + Internal: d, + } } } } From 5f3f6f0ae98ae7b60b87da2482d337dc10679ee6 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Thu, 31 Aug 2023 21:16:01 -0700 Subject: [PATCH 25/82] ack nil body --- packages/relayer/queue/rabbitmq/queue.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 403be901033..23420d863d2 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -136,6 +136,10 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, Internal: d, } } + } else { + if err := d.Ack(false); err != nil { + slog.Error("error acking nil body delivery", "err", err.Error()) + } } } } From 6c869b95a6396f838f4a16bda1af67f111a445f5 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Thu, 31 Aug 2023 21:54:30 -0700 Subject: [PATCH 26/82] graceful shutdowns and metrics servers --- packages/relayer/cmd/flags/common.go | 8 +++ packages/relayer/cmd/utils/subcommand.go | 6 +++ packages/relayer/indexer/http/server.go | 14 ----- packages/relayer/indexer/http/server_test.go | 1 - packages/relayer/indexer/indexer.go | 55 ++++++++++++-------- packages/relayer/indexer/scan_blocks.go | 13 ++++- packages/relayer/metrics/metrics.go | 34 ++++++++++++ 7 files changed, 93 insertions(+), 38 deletions(-) create mode 100644 packages/relayer/metrics/metrics.go diff --git a/packages/relayer/cmd/flags/common.go b/packages/relayer/cmd/flags/common.go index 60d56c5bab5..23147f95760 100644 --- a/packages/relayer/cmd/flags/common.go +++ b/packages/relayer/cmd/flags/common.go @@ -112,6 +112,13 @@ var ( Category: commonCategory, EnvVars: []string{"DATABASE_CONN_MAX_LIFETIME"}, } + MetricsHTTPPort = &cli.Uint64Flag{ + Name: "metrics.port", + Usage: "Port to run metrics http server on", + Category: commonCategory, + Value: 6061, + EnvVars: []string{"METRICS_HTTP_PORT"}, + } ) // optional @@ -142,6 +149,7 @@ var CommonFlags = []cli.Flag{ DatabaseMaxIdleConns, DatabaseConnMaxLifetime, DatabaseMaxOpenConns, + MetricsHTTPPort, } // MergeFlags merges the given flag slices. diff --git a/packages/relayer/cmd/utils/subcommand.go b/packages/relayer/cmd/utils/subcommand.go index f25ff133328..cf2c20cfbf4 100644 --- a/packages/relayer/cmd/utils/subcommand.go +++ b/packages/relayer/cmd/utils/subcommand.go @@ -8,6 +8,7 @@ import ( "log/slog" + "github.com/taikoxyz/taiko-mono/packages/relayer/metrics" "github.com/urfave/cli/v2" ) @@ -34,6 +35,11 @@ func SubcommandAction(app SubcommandApplication) cli.ActionFunc { return err } + if err := metrics.Serve(ctx, c); err != nil { + slog.Error("Starting metrics server error", "error", err) + return err + } + defer func() { ctxClose() app.Close(ctx) diff --git a/packages/relayer/indexer/http/server.go b/packages/relayer/indexer/http/server.go index a9734577d94..dc5ba3cd68a 100644 --- a/packages/relayer/indexer/http/server.go +++ b/packages/relayer/indexer/http/server.go @@ -2,7 +2,6 @@ package http import ( "context" - "fmt" "math/big" "net/http" "os" @@ -10,7 +9,6 @@ import ( "github.com/labstack/echo/v4/middleware" "github.com/taikoxyz/taiko-mono/packages/relayer" - echoprom "github.com/labstack/echo-contrib/prometheus" echo "github.com/labstack/echo/v4" ) @@ -137,15 +135,3 @@ func (srv *Server) configureMiddleware(corsOrigins []string) { AllowMethods: []string{http.MethodGet, http.MethodHead}, })) } - -func (srv *Server) configureAndStartPrometheus() { - // Enable metrics middleware - p := echoprom.NewPrometheus("echo", nil) - p.Use(srv.echo) - e := echo.New() - p.SetMetricsPath(e) - - go func() { - _ = e.Start(fmt.Sprintf(":%v", os.Getenv("PROMETHEUS_HTTP_PORT"))) - }() -} diff --git a/packages/relayer/indexer/http/server_test.go b/packages/relayer/indexer/http/server_test.go index 0a7d9701d55..c58cbb7a291 100644 --- a/packages/relayer/indexer/http/server_test.go +++ b/packages/relayer/indexer/http/server_test.go @@ -24,7 +24,6 @@ func newTestServer(url string) *Server { srv.configureMiddleware([]string{"*"}) srv.configureRoutes() - srv.configureAndStartPrometheus() return srv } diff --git a/packages/relayer/indexer/indexer.go b/packages/relayer/indexer/indexer.go index 848d35c5b8e..78acfab9c7c 100644 --- a/packages/relayer/indexer/indexer.go +++ b/packages/relayer/indexer/indexer.go @@ -6,6 +6,7 @@ import ( "fmt" "log/slog" "math/big" + "sync" "time" "github.com/cyberhorsey/errors" @@ -89,6 +90,8 @@ type Indexer struct { srv *http.Server httpPort uint64 + + wg *sync.WaitGroup } func (i *Indexer) InitFromCli(ctx context.Context, c *cli.Context) error { @@ -194,6 +197,8 @@ func InitFromConfig(ctx context.Context, i *Indexer, cfg *Config) (err error) { i.syncMode = cfg.SyncMode i.watchMode = cfg.WatchMode + i.wg = &sync.WaitGroup{} + return nil } @@ -206,6 +211,8 @@ func (i *Indexer) Close(ctx context.Context) { if err := i.srv.Shutdown(ctx); err != nil { slog.Error("srv shutdown", "error", err) } + + i.wg.Wait() } // nolint: funlen @@ -222,23 +229,30 @@ func (i *Indexer) Start() error { return err } - return i.filter(ctx) -} + i.wg.Add(1) -func (i *Indexer) filter(ctx context.Context) error { - chainID, err := i.srcEthClient.ChainID(ctx) - if err != nil { - return errors.Wrap(err, "i.srcEthClient.ChainID()") - } + go func() { + defer func() { + i.wg.Done() + }() - go scanBlocks(ctx, i.srcEthClient, chainID) + if err := i.filter(ctx); err != nil { + slog.Error("error filtering blocks", "error", err.Error()) + } + }() + go scanBlocks(ctx, i.srcEthClient, i.srcChainId, i.wg) + + return nil +} + +func (i *Indexer) filter(ctx context.Context) error { // if subscribing to new events, skip filtering and subscribe if i.watchMode == Subscribe { - return i.subscribe(ctx, chainID) + return i.subscribe(ctx, i.srcChainId) } - if err := i.setInitialProcessingBlockByMode(ctx, i.syncMode, chainID); err != nil { + if err := i.setInitialProcessingBlockByMode(ctx, i.syncMode, i.srcChainId); err != nil { return errors.Wrap(err, "i.setInitialProcessingBlockByMode") } @@ -248,12 +262,12 @@ func (i *Indexer) filter(ctx context.Context) error { } if i.processingBlockHeight == header.Number.Uint64() { - slog.Info("indexing caught up, subscribing to new incoming events", "chainID", chainID.Uint64()) - return i.subscribe(ctx, chainID) + slog.Info("indexing caught up, subscribing to new incoming events", "chainID", i.srcChainId.Uint64()) + return i.subscribe(ctx, i.srcChainId) } slog.Info("fetching batch block events", - "chainID", chainID.Uint64(), + "chainID", i.srcChainId.Uint64(), "startblock", i.processingBlockHeight, "endblock", header.Number.Int64(), "batchsize", i.blockBatchSize, @@ -272,8 +286,7 @@ func (i *Indexer) filter(ctx context.Context) error { // process up to end - 1 for this batch. filterEnd := end - 1 - fmt.Printf("block batch from %v to %v", j, filterEnd) - fmt.Println() + slog.Info("block batch", "start", j, "end", filterEnd) filterOpts := &bind.FilterOpts{ Start: i.processingBlockHeight, @@ -289,7 +302,7 @@ func (i *Indexer) filter(ctx context.Context) error { // we dont need to do anything with msgStatus events except save them to the DB. // we dont need to process them. they are for exposing via the API. - err = i.saveMessageStatusChangedEvents(ctx, chainID, messageStatusChangedEvents) + err = i.saveMessageStatusChangedEvents(ctx, i.srcChainId, messageStatusChangedEvents) if err != nil { return errors.Wrap(err, "bridge.saveMessageStatusChangedEvents") } @@ -302,7 +315,7 @@ func (i *Indexer) filter(ctx context.Context) error { if !messageSentEvents.Next() || messageSentEvents.Event == nil { // use "end" not "filterEnd" here, because it will be used as the start // of the next batch. - if err := i.handleNoEventsInBatch(ctx, chainID, int64(end)); err != nil { + if err := i.handleNoEventsInBatch(ctx, i.srcChainId, int64(end)); err != nil { return errors.Wrap(err, "i.handleNoEventsInBatch") } @@ -317,7 +330,7 @@ func (i *Indexer) filter(ctx context.Context) error { event := messageSentEvents.Event group.Go(func() error { - err := i.handleEvent(groupCtx, chainID, event) + err := i.handleEvent(groupCtx, i.srcChainId, event) if err != nil { relayer.ErrorEvents.Inc() // log error but always return nil to keep other goroutines active @@ -335,7 +348,7 @@ func (i *Indexer) filter(ctx context.Context) error { } // handle no events remaining, saving the processing block and restarting the for // loop - if err := i.handleNoEventsInBatch(ctx, chainID, int64(end)); err != nil { + if err := i.handleNoEventsInBatch(ctx, i.srcChainId, int64(end)); err != nil { return errors.Wrap(err, "i.handleNoEventsInBatch") } @@ -354,7 +367,7 @@ func (i *Indexer) filter(ctx context.Context) error { } if i.processingBlockHeight < latestBlock.Number.Uint64() { - return i.Start() + return i.filter(ctx) } // we are caught up and specified not to subscribe, we can return now @@ -362,7 +375,7 @@ func (i *Indexer) filter(ctx context.Context) error { return nil } - return i.subscribe(ctx, chainID) + return i.subscribe(ctx, i.srcChainId) } func (i *Indexer) queueName() string { diff --git a/packages/relayer/indexer/scan_blocks.go b/packages/relayer/indexer/scan_blocks.go index a3024f498c1..4c667bf4864 100644 --- a/packages/relayer/indexer/scan_blocks.go +++ b/packages/relayer/indexer/scan_blocks.go @@ -3,12 +3,19 @@ package indexer import ( "context" "math/big" + "sync" "github.com/ethereum/go-ethereum/core/types" "github.com/taikoxyz/taiko-mono/packages/relayer" ) -func scanBlocks(ctx context.Context, ethClient ethClient, chainID *big.Int) { +func scanBlocks(ctx context.Context, ethClient ethClient, chainID *big.Int, wg *sync.WaitGroup) { + wg.Add(1) + + defer func() { + wg.Done() + }() + headers := make(chan *types.Header) sub, err := ethClient.SubscribeNewHead(ctx, headers) @@ -18,10 +25,12 @@ func scanBlocks(ctx context.Context, ethClient ethClient, chainID *big.Int) { for { select { + case <-ctx.Done(): + return case <-sub.Err(): relayer.BlocksScannedError.Inc() - scanBlocks(ctx, ethClient, chainID) + scanBlocks(ctx, ethClient, chainID, wg) return case <-headers: diff --git a/packages/relayer/metrics/metrics.go b/packages/relayer/metrics/metrics.go new file mode 100644 index 00000000000..9367f168d7d --- /dev/null +++ b/packages/relayer/metrics/metrics.go @@ -0,0 +1,34 @@ +package metrics + +import ( + "context" + "fmt" + + echoprom "github.com/labstack/echo-contrib/prometheus" + "github.com/labstack/echo/v4" + "github.com/labstack/gommon/log" + "github.com/taikoxyz/taiko-mono/packages/relayer/cmd/flags" + "github.com/urfave/cli/v2" + "golang.org/x/exp/slog" +) + +// Serve starts the metrics server on the given address, will be closed when the given +// context is cancelled. +func Serve(ctx context.Context, c *cli.Context) error { + // Enable metrics middleware + p := echoprom.NewPrometheus("echo", nil) + e := echo.New() + p.SetMetricsPath(e) + + go func() { + <-ctx.Done() + + if err := e.Shutdown(ctx); err != nil { + log.Error("Failed to close metrics server", "error", err) + } + }() + + slog.Info("Starting metrics server", "port", c.Uint64(flags.MetricsHTTPPort.Name)) + + return e.Start(fmt.Sprintf(":%v", c.Uint64(flags.MetricsHTTPPort.Name))) +} From 9c60fedd94e7f25a1fc1e943ccd205972c064da1 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 10:58:32 -0700 Subject: [PATCH 27/82] handle ecdsa publickey error appropriately --- packages/relayer/.l1indexer.example.env | 21 ++++++++++++++++++ packages/relayer/.l1processor.example.env | 27 +++++++++++++++++++++++ packages/relayer/indexer/indexer_test.go | 4 ++++ packages/relayer/processor/processor.go | 2 +- 4 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 packages/relayer/.l1indexer.example.env create mode 100644 packages/relayer/.l1processor.example.env diff --git a/packages/relayer/.l1indexer.example.env b/packages/relayer/.l1indexer.example.env new file mode 100644 index 00000000000..fa3d5e8b0a0 --- /dev/null +++ b/packages/relayer/.l1indexer.example.env @@ -0,0 +1,21 @@ +HTTP_PORT=4103 +METRICS_HTTP_PORT=6062 +DATABASE_USER=root +DATABASE_PASSWORD=root +DATABASE_NAME=relayer +DATABASE_HOST=localhost:3306 +DATABASE_MAX_IDLE_CONNS=50 +DATABASE_MAX_OPEN_CONNS=3000 +DATABASE_CONN_MAX_LIFETIME=100000 +QUEUE_USER=guest +QUEUE_PASSWORD=guest +QUEUE_HOST=localhost +QUEUE_PORT=5672 +SRC_BRIDGE_ADDRESS=0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE +DEST_BRIDGE_ADDRESS=0x1000777700000000000000000000000000000004 +SRC_TAIKO_ADDRESS=0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82 +SRC_RPC_URL=wss://l1ws.internal.taiko.xyz +DEST_RPC_URL=wss://ws.internal.taiko.xyz +CORS_ORIGINS=* +NUM_GOROUTINES=50 +BLOCK_BATCH_SIZE=100 \ No newline at end of file diff --git a/packages/relayer/.l1processor.example.env b/packages/relayer/.l1processor.example.env new file mode 100644 index 00000000000..859b6666822 --- /dev/null +++ b/packages/relayer/.l1processor.example.env @@ -0,0 +1,27 @@ +PROMETHEUS_HTTP_PORT=6062 +DATABASE_USER=root +DATABASE_PASSWORD=root +DATABASE_NAME=relayer +DATABASE_HOST=localhost:3306 +DATABASE_MAX_IDLE_CONNS=50 +DATABASE_MAX_OPEN_CONNS=3000 +DATABASE_CONN_MAX_LIFETIME=100000 +QUEUE_USER=guest +QUEUE_PASSWORD=guest +QUEUE_HOST=localhost +QUEUE_PORT=5672 +PROCESSOR_PRIVATE_KEY= +DEST_BRIDGE_ADDRESS=0x1000777700000000000000000000000000000004 +SRC_ERC20_VAULT_ADDRESS=0xc6e7DF5E7b4f2A278906862b61205850344D4e7d +DEST_ERC20_VAULT_ADDRESS=0x1000777700000000000000000000000000000002 +DEST_ERC721_VAULT_ADDRESS=0x1000777700000000000000000000000000000008 +DEST_ERC1155_VAULT_ADDRESS=0x1000777700000000000000000000000000000009 +DEST_TAIKO_ADDRESS=0x1000777700000000000000000000000000000001 +SRC_SIGNAL_SERVICE_ADDRESS=0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB +SRC_RPC_URL=wss://l1ws.internal.taiko.xyz +DEST_RPC_URL=wss://ws.internal.taiko.xyz +CONFIRMATIONS_BEFORE_PROCESSING=2 +CORS_ORIGINS=* +NUM_GOROUTINES=50 +BLOCK_BATCH_SIZE=100 +HEADER_SYNC_INTERVAL_IN_SECONDS=2 \ No newline at end of file diff --git a/packages/relayer/indexer/indexer_test.go b/packages/relayer/indexer/indexer_test.go index d8d03557231..af7e631dcae 100644 --- a/packages/relayer/indexer/indexer_test.go +++ b/packages/relayer/indexer/indexer_test.go @@ -1,6 +1,8 @@ package indexer import ( + "sync" + "github.com/ethereum/go-ethereum/ethclient" "github.com/labstack/echo/v4" "github.com/taikoxyz/taiko-mono/packages/relayer" @@ -36,5 +38,7 @@ func newTestService(syncMode SyncMode, watchMode WatchMode) (*Indexer, relayer.B watchMode: watchMode, httpPort: 4102, srv: srv, + + wg: &sync.WaitGroup{}, }, b } diff --git a/packages/relayer/processor/processor.go b/packages/relayer/processor/processor.go index 1fc9c16e1b5..b43bb3531eb 100644 --- a/packages/relayer/processor/processor.go +++ b/packages/relayer/processor/processor.go @@ -190,7 +190,7 @@ func InitFromConfig(ctx context.Context, p *Processor, cfg *Config) error { publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) if !ok { - return err + return errors.New("unable to convert public key") } relayerAddr := crypto.PubkeyToAddress(*publicKeyECDSA) From f24830d2a889fa80b7d47b3faa5c68580301b9f1 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 11:01:26 -0700 Subject: [PATCH 28/82] check http srv error isnt errserverclosed --- packages/relayer/indexer/indexer.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/relayer/indexer/indexer.go b/packages/relayer/indexer/indexer.go index 78acfab9c7c..626f20de3c4 100644 --- a/packages/relayer/indexer/indexer.go +++ b/packages/relayer/indexer/indexer.go @@ -6,6 +6,7 @@ import ( "fmt" "log/slog" "math/big" + nethttp "net/http" "sync" "time" @@ -218,7 +219,7 @@ func (i *Indexer) Close(ctx context.Context) { // nolint: funlen func (i *Indexer) Start() error { go func() { - if err := i.srv.Start(fmt.Sprintf(":%v", i.httpPort)); err != nil { + if err := i.srv.Start(fmt.Sprintf(":%v", i.httpPort)); err != nethttp.ErrServerClosed { slog.Error("http srv start", "error", err.Error()) } }() From 23a48a7965efbb3f3347d14092213016992a8da8 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 11:26:35 -0700 Subject: [PATCH 29/82] add backoff for processor --- go.mod | 2 +- go.sum | 2 ++ packages/relayer/cmd/flags/processor.go | 14 +++++++++++ packages/relayer/indexer/indexer.go | 10 ++++---- packages/relayer/processor/config.go | 6 +++++ packages/relayer/processor/process_message.go | 24 ++++++++++++++++--- packages/relayer/processor/processor.go | 22 +++++++++++++---- 7 files changed, 68 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 722cb1303de..b27f91ab344 100644 --- a/go.mod +++ b/go.mod @@ -43,7 +43,7 @@ require ( github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect - github.com/cenkalti/backoff/v4 v4.2.0 // indirect + github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cloudflare/circl v1.3.3 // indirect github.com/containerd/containerd v1.6.19 // indirect diff --git a/go.sum b/go.sum index e022d54b134..8ecb26fdb91 100644 --- a/go.sum +++ b/go.sum @@ -45,6 +45,8 @@ github.com/buildkite/terminal-to-html/v3 v3.8.0/go.mod h1:j3XxsnYElte/Bo7Pft+U5e github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk= github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= diff --git a/packages/relayer/cmd/flags/processor.go b/packages/relayer/cmd/flags/processor.go index 1b5008cf3be..dd4dcdaa811 100644 --- a/packages/relayer/cmd/flags/processor.go +++ b/packages/relayer/cmd/flags/processor.go @@ -79,6 +79,18 @@ var ( Category: processorCategory, EnvVars: []string{"PROFITABLE_ONLY"}, } + BackOffRetryInterval = &cli.Uint64Flag{ + Name: "backoff.retryInterval", + Usage: "Retry interval in seconds when there is an error", + Category: processorCategory, + Value: 12, + } + BackOffMaxRetrys = &cli.Uint64Flag{ + Name: "backoff.maxRetrys", + Usage: "Max retry times when there is an error", + Category: processorCategory, + Value: 3, + } ) var ProcessorFlags = MergeFlags(CommonFlags, []cli.Flag{ @@ -93,4 +105,6 @@ var ProcessorFlags = MergeFlags(CommonFlags, []cli.Flag{ Confirmations, ConfirmationTimeout, ProfitableOnly, + BackOffRetryInterval, + BackOffMaxRetrys, }) diff --git a/packages/relayer/indexer/indexer.go b/packages/relayer/indexer/indexer.go index 626f20de3c4..d4378c4769f 100644 --- a/packages/relayer/indexer/indexer.go +++ b/packages/relayer/indexer/indexer.go @@ -93,6 +93,8 @@ type Indexer struct { httpPort uint64 wg *sync.WaitGroup + + ctx context.Context } func (i *Indexer) InitFromCli(ctx context.Context, c *cli.Context) error { @@ -224,9 +226,9 @@ func (i *Indexer) Start() error { } }() - ctx := context.Background() + i.ctx = context.Background() - if err := i.queue.Start(ctx, i.queueName()); err != nil { + if err := i.queue.Start(i.ctx, i.queueName()); err != nil { return err } @@ -237,12 +239,12 @@ func (i *Indexer) Start() error { i.wg.Done() }() - if err := i.filter(ctx); err != nil { + if err := i.filter(i.ctx); err != nil { slog.Error("error filtering blocks", "error", err.Error()) } }() - go scanBlocks(ctx, i.srcEthClient, i.srcChainId, i.wg) + go scanBlocks(i.ctx, i.srcEthClient, i.srcChainId, i.wg) return nil } diff --git a/packages/relayer/processor/config.go b/packages/relayer/processor/config.go index 3cc1ee7ff42..3026bc21102 100644 --- a/packages/relayer/processor/config.go +++ b/packages/relayer/processor/config.go @@ -35,6 +35,10 @@ type Config struct { ConfirmationsTimeout uint64 ProfitableOnly bool + // backoff configs + BackoffRetryInterval uint64 + BackOffMaxRetrys uint64 + // db configs DatabaseUsername string DatabasePassword string @@ -91,6 +95,8 @@ func NewConfigFromCliContext(c *cli.Context) (*Config, error) { Confirmations: c.Uint64(flags.Confirmations.Name), ConfirmationsTimeout: c.Uint64(flags.ConfirmationTimeout.Name), ProfitableOnly: c.Bool(flags.ProfitableOnly.Name), + BackoffRetryInterval: c.Uint64(flags.BackOffRetryInterval.Name), + BackOffMaxRetrys: c.Uint64(flags.BackOffMaxRetrys.Name), OpenDBFunc: func() (DB, error) { return db.OpenDBConnection(db.DBConnectionOpts{ Name: c.String(flags.DatabaseUsername.Name), diff --git a/packages/relayer/processor/process_message.go b/packages/relayer/processor/process_message.go index ffc1f0a69ab..9cdccce34a3 100644 --- a/packages/relayer/processor/process_message.go +++ b/packages/relayer/processor/process_message.go @@ -10,6 +10,7 @@ import ( "strings" "time" + "github.com/cenkalti/backoff" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -133,9 +134,26 @@ func (p *Processor) processMessage( return errors.New("message not received") } - tx, err := p.sendProcessMessageCall(ctx, msgBody.Event, encodedSignalProof) - if err != nil { - return errors.Wrap(err, "p.sendProcessMessageCall") + var tx *types.Transaction + + sendTx := func() error { + if ctx.Err() != nil { + return nil + } + + tx, err = p.sendProcessMessageCall(ctx, msgBody.Event, encodedSignalProof) + if err != nil { + return err + } + + return nil + } + + if err := backoff.Retry(sendTx, backoff.WithMaxRetries( + backoff.NewConstantBackOff(p.backOffRetryInterval), + p.backOffMaxRetries), + ); err != nil { + return err } relayer.EventsProcessed.Inc() diff --git a/packages/relayer/processor/processor.go b/packages/relayer/processor/processor.go index b43bb3531eb..e3eac4843ff 100644 --- a/packages/relayer/processor/processor.go +++ b/packages/relayer/processor/processor.go @@ -9,6 +9,7 @@ import ( "log/slog" "math/big" "sync" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -77,6 +78,9 @@ type Processor struct { confTimeoutInSeconds int64 + backOffRetryInterval time.Duration + backOffMaxRetries uint64 + msgCh chan queue.Message wg *sync.WaitGroup @@ -230,6 +234,9 @@ func InitFromConfig(ctx context.Context, p *Processor, cfg *Config) error { p.srcChainId = srcChainId + p.backOffRetryInterval = time.Duration(cfg.BackoffRetryInterval) * time.Second + p.backOffMaxRetries = cfg.BackOffMaxRetrys + return nil } @@ -280,12 +287,19 @@ func (p *Processor) eventLoop(ctx context.Context) { return case msg := <-p.msgCh: if err := p.processMessage(ctx, msg); err != nil { + // only log unexpected errors if !errors.Is(err, errUnprocessable) { slog.Error("err processing message", "err", err.Error()) - } - - if err := p.queue.Nack(ctx, msg); err != nil { - slog.Error("Err nacking message", "err", err.Error()) + // nack all errors even errUnprocessable + if err := p.queue.Nack(ctx, msg); err != nil { + slog.Error("Err nacking message", "err", err.Error()) + } + } else { + // if errUnprocessable, we can Ack it to remove it from + // beign re-added, message should never become processable. + if err := p.queue.Ack(ctx, msg); err != nil { + slog.Error("Err nacking message", "err", err.Error()) + } } } } From b871c1ea78eada6403695dbf1a4ccdf58d7c2536 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 11:27:00 -0700 Subject: [PATCH 30/82] defaults --- packages/relayer/processor/processor_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/relayer/processor/processor_test.go b/packages/relayer/processor/processor_test.go index 3bae15a81dc..d9155aaa5ab 100644 --- a/packages/relayer/processor/processor_test.go +++ b/packages/relayer/processor/processor_test.go @@ -2,6 +2,7 @@ package processor import ( "sync" + "time" "github.com/ethereum/go-ethereum/crypto" "github.com/taikoxyz/taiko-mono/packages/relayer/mock" @@ -33,5 +34,7 @@ func newTestProcessor(profitableOnly bool) *Processor { confTimeoutInSeconds: 900, confirmations: 1, queue: &mock.Queue{}, + backOffRetryInterval: 1 * time.Second, + backOffMaxRetries: 1, } } From 05a2d1fba27ba936b2cc3b20633c019bf66dac4f Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 11:27:34 -0700 Subject: [PATCH 31/82] default ctx --- packages/relayer/indexer/indexer_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/relayer/indexer/indexer_test.go b/packages/relayer/indexer/indexer_test.go index af7e631dcae..da2c8fef529 100644 --- a/packages/relayer/indexer/indexer_test.go +++ b/packages/relayer/indexer/indexer_test.go @@ -1,6 +1,7 @@ package indexer import ( + "context" "sync" "github.com/ethereum/go-ethereum/ethclient" @@ -40,5 +41,7 @@ func newTestService(syncMode SyncMode, watchMode WatchMode) (*Indexer, relayer.B srv: srv, wg: &sync.WaitGroup{}, + + ctx: context.Background(), }, b } From 2b5f4eb0e90ef636fbc2b93081d6d6d49b8fedb4 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 11:33:10 -0700 Subject: [PATCH 32/82] go mod --- go.mod | 1 + go.sum | 2 ++ 2 files changed, 3 insertions(+) diff --git a/go.mod b/go.mod index b27f91ab344..9240a5fcfd5 100644 --- a/go.mod +++ b/go.mod @@ -43,6 +43,7 @@ require ( github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect + github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cloudflare/circl v1.3.3 // indirect diff --git a/go.sum b/go.sum index 8ecb26fdb91..37f862b76a4 100644 --- a/go.sum +++ b/go.sum @@ -43,6 +43,8 @@ github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtyd github.com/buildkite/terminal-to-html/v3 v3.8.0 h1:S7ImMS8W+2yS/9D4ugrXzB95C4AuNaKcaw/eR/95bFU= github.com/buildkite/terminal-to-html/v3 v3.8.0/go.mod h1:j3XxsnYElte/Bo7Pft+U5eQWWbcx3j51uQ8fo43VrjM= github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= From b192cd8f0908cef6ea87a08e0ca9883fdabc5ade Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 11:48:05 -0700 Subject: [PATCH 33/82] handle delivery errors, close channels --- packages/relayer/queue/rabbitmq/queue.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 23420d863d2..3312c2ce744 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -99,7 +99,7 @@ func (r *RabbitMQ) Nack(ctx context.Context, msg queue.Message) error { slog.Info("acknowledging rabbitmq message", "msgId", rmqMsg.MessageId) - return rmqMsg.Nack(false, true) + return rmqMsg.Nack(false, false) } func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, wg *sync.WaitGroup) error { @@ -126,7 +126,9 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, for { select { case <-ctx.Done(): + defer r.Close(ctx) return + case d := <-msgs: if d.Body != nil { slog.Info("rabbitmq message found", "msgId", d.MessageId) @@ -137,8 +139,18 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, } } } else { - if err := d.Ack(false); err != nil { - slog.Error("error acking nil body delivery", "err", err.Error()) + // error with channel if we got a nil body message + // it wont be able to be acknowledged. + // re-establish connection + ch, err := r.conn.Channel() + if err != nil { + slog.Error("error establishing channel", "err", err.Error()) + } + + r.ch = ch + + if err := r.Start(ctx, r.queue.Name); err != nil { + slog.Error("error starting queue", "err", err.Error()) } } } From 346277c5fbeaad7f7f07c62800d694381707902d Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 11:52:59 -0700 Subject: [PATCH 34/82] test --- packages/relayer/processor/process_message_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/relayer/processor/process_message_test.go b/packages/relayer/processor/process_message_test.go index b422bd55b72..b6dae2c8a5c 100644 --- a/packages/relayer/processor/process_message_test.go +++ b/packages/relayer/processor/process_message_test.go @@ -127,7 +127,7 @@ func Test_ProcessMessage_noChainId(t *testing.T) { } err = p.processMessage(context.Background(), msg) - assert.EqualError(t, err, "p.sendProcessMessageCall: bind.NewKeyedTransactorWithChainID: no chain id specified") + assert.EqualError(t, err, "bind.NewKeyedTransactorWithChainID: no chain id specified") } func Test_ProcessMessage(t *testing.T) { From 5e13d610e48352b11a7a6cc1ebf0ec55f33bd279 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 12:45:44 -0700 Subject: [PATCH 35/82] metrics tests --- packages/relayer/cmd/utils/subcommand.go | 4 +- packages/relayer/indexer/http/server_test.go | 13 ---- packages/relayer/metrics/metrics.go | 4 +- packages/relayer/metrics/metrics_test.go | 64 ++++++++++++++++++++ 4 files changed, 69 insertions(+), 16 deletions(-) create mode 100644 packages/relayer/metrics/metrics_test.go diff --git a/packages/relayer/cmd/utils/subcommand.go b/packages/relayer/cmd/utils/subcommand.go index cf2c20cfbf4..b4fa237b775 100644 --- a/packages/relayer/cmd/utils/subcommand.go +++ b/packages/relayer/cmd/utils/subcommand.go @@ -35,7 +35,9 @@ func SubcommandAction(app SubcommandApplication) cli.ActionFunc { return err } - if err := metrics.Serve(ctx, c); err != nil { + _, startMetrics := metrics.Serve(ctx, c) + + if err := startMetrics(); err != nil { slog.Error("Starting metrics server error", "error", err) return err } diff --git a/packages/relayer/indexer/http/server_test.go b/packages/relayer/indexer/http/server_test.go index c58cbb7a291..3fd3d9ba065 100644 --- a/packages/relayer/indexer/http/server_test.go +++ b/packages/relayer/indexer/http/server_test.go @@ -146,19 +146,6 @@ func Test_Root(t *testing.T) { } } -func Test_Metrics(t *testing.T) { - srv := newTestServer("") - - req, _ := http.NewRequest(echo.GET, "/metrics", nil) - rec := httptest.NewRecorder() - - srv.ServeHTTP(rec, req) - - if rec.Code != http.StatusOK { - t.Fatalf("Test_Metrics expected code %v, got %v", http.StatusOK, rec.Code) - } -} - func Test_StartShutdown(t *testing.T) { srv := newTestServer("") diff --git a/packages/relayer/metrics/metrics.go b/packages/relayer/metrics/metrics.go index 9367f168d7d..efb69e26f12 100644 --- a/packages/relayer/metrics/metrics.go +++ b/packages/relayer/metrics/metrics.go @@ -14,7 +14,7 @@ import ( // Serve starts the metrics server on the given address, will be closed when the given // context is cancelled. -func Serve(ctx context.Context, c *cli.Context) error { +func Serve(ctx context.Context, c *cli.Context) (*echo.Echo, func() error) { // Enable metrics middleware p := echoprom.NewPrometheus("echo", nil) e := echo.New() @@ -30,5 +30,5 @@ func Serve(ctx context.Context, c *cli.Context) error { slog.Info("Starting metrics server", "port", c.Uint64(flags.MetricsHTTPPort.Name)) - return e.Start(fmt.Sprintf(":%v", c.Uint64(flags.MetricsHTTPPort.Name))) + return e, func() error { return e.Start(fmt.Sprintf(":%v", c.Uint64(flags.MetricsHTTPPort.Name))) } } diff --git a/packages/relayer/metrics/metrics_test.go b/packages/relayer/metrics/metrics_test.go new file mode 100644 index 00000000000..5c4775e2e99 --- /dev/null +++ b/packages/relayer/metrics/metrics_test.go @@ -0,0 +1,64 @@ +package metrics + +import ( + "context" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/labstack/echo/v4" + "github.com/stretchr/testify/assert" + "github.com/taikoxyz/taiko-mono/packages/relayer/cmd/flags" + "github.com/urfave/cli/v2" +) + +func Test_Metrics(t *testing.T) { + app := cli.NewApp() + app.Flags = []cli.Flag{ + flags.MetricsHTTPPort, + } + + app.Action = func(c *cli.Context) error { + ctx, cancel := context.WithCancel(context.Background()) + + var e *echo.Echo + + var startFunc func() error + + var err error + + go func() { + e, startFunc = Serve(ctx, c) + + err = startFunc() + }() + + for e == nil && err == nil { + time.Sleep(1 * time.Second) + } + + assert.Nil(t, err) + assert.NotNil(t, e) + + req, _ := http.NewRequest(echo.GET, "/metrics", nil) + rec := httptest.NewRecorder() + + e.ServeHTTP(rec, req) + + if rec.Code != http.StatusOK { + t.Fatalf("Test_Metrics expected code %v, got %v", http.StatusOK, rec.Code) + } + + cancel() + + assert.Nil(t, err) + + return nil + } + + assert.Nil(t, app.Run([]string{ + "TestMetrics", + "-" + flags.MetricsHTTPPort.Name, "5019", + })) +} From 1794e8e15b67f4a457996486a638357722faaf27 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 12:53:21 -0700 Subject: [PATCH 36/82] mock chain ids --- packages/relayer/indexer/indexer_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/relayer/indexer/indexer_test.go b/packages/relayer/indexer/indexer_test.go index da2c8fef529..870aa8dbf51 100644 --- a/packages/relayer/indexer/indexer_test.go +++ b/packages/relayer/indexer/indexer_test.go @@ -43,5 +43,8 @@ func newTestService(syncMode SyncMode, watchMode WatchMode) (*Indexer, relayer.B wg: &sync.WaitGroup{}, ctx: context.Background(), + + srcChainId: mock.MockChainID, + destChainId: mock.MockChainID, }, b } From 02b6f9c2035f123f75dd99713b53b0eedae46ac3 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 13:11:50 -0700 Subject: [PATCH 37/82] duplicate IDs --- packages/relayer/processor/processor.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/relayer/processor/processor.go b/packages/relayer/processor/processor.go index e3eac4843ff..16dc6cac760 100644 --- a/packages/relayer/processor/processor.go +++ b/packages/relayer/processor/processor.go @@ -185,11 +185,6 @@ func InitFromConfig(ctx context.Context, p *Processor, cfg *Config) error { return err } - srcChainId, err := srcEthClient.ChainID(context.Background()) - if err != nil { - return err - } - publicKey := cfg.ProcessorPrivateKey.Public() publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) @@ -232,8 +227,6 @@ func InitFromConfig(ctx context.Context, p *Processor, cfg *Config) error { p.mu = &sync.Mutex{} p.rpc = srcRpcClient - p.srcChainId = srcChainId - p.backOffRetryInterval = time.Duration(cfg.BackoffRetryInterval) * time.Second p.backOffMaxRetries = cfg.BackOffMaxRetrys From 2eea9c88b2356da5c477bc95095e749a74035e0e Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 14:08:58 -0700 Subject: [PATCH 38/82] only use ch if valid --- packages/relayer/queue/rabbitmq/queue.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 3312c2ce744..dda4f77178f 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -147,10 +147,11 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, slog.Error("error establishing channel", "err", err.Error()) } - r.ch = ch - - if err := r.Start(ctx, r.queue.Name); err != nil { - slog.Error("error starting queue", "err", err.Error()) + if ch != nil { + r.ch = ch + if err := r.Start(ctx, r.queue.Name); err != nil { + slog.Error("error starting queue", "err", err.Error()) + } } } } From c0491b9ed24fd6f450c8822b66b07e71af85b1a7 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 14:10:36 -0700 Subject: [PATCH 39/82] logs --- packages/relayer/queue/rabbitmq/queue.go | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index dda4f77178f..59628c659f3 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -139,6 +139,7 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, } } } else { + slog.Info("nil rabbitmq message found", "msg", d) // error with channel if we got a nil body message // it wont be able to be acknowledged. // re-establish connection From 473f0276a9bf538cf83eb29a733de4425a6cbac4 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 14:11:47 -0700 Subject: [PATCH 40/82] rm reset conn --- packages/relayer/queue/rabbitmq/queue.go | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 59628c659f3..abc5cf93768 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -142,18 +142,7 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, slog.Info("nil rabbitmq message found", "msg", d) // error with channel if we got a nil body message // it wont be able to be acknowledged. - // re-establish connection - ch, err := r.conn.Channel() - if err != nil { - slog.Error("error establishing channel", "err", err.Error()) - } - - if ch != nil { - r.ch = ch - if err := r.Start(ctx, r.queue.Name); err != nil { - slog.Error("error starting queue", "err", err.Error()) - } - } + // re-establish connection? dunno yet. } } } From 017d79e669925526df42f548a358ca1a78d5226f Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 14:13:34 -0700 Subject: [PATCH 41/82] try a panic here... --- packages/relayer/queue/rabbitmq/queue.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index abc5cf93768..2f9d5c70b72 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -121,6 +121,7 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, return err } + var nilCount int = 0 // wrap internal msg chan with a generic queue go func() { for { @@ -139,6 +140,12 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, } } } else { + nilCount++ + + if nilCount > 5 { + panic("repetitive nilBody delivery") + } + slog.Info("nil rabbitmq message found", "msg", d) // error with channel if we got a nil body message // it wont be able to be acknowledged. From f6835b32ea74427dc1f47e79239cb07e6affa01a Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 14:19:11 -0700 Subject: [PATCH 42/82] more logs --- packages/relayer/indexer/indexer.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/relayer/indexer/indexer.go b/packages/relayer/indexer/indexer.go index d4378c4769f..bc07b737e3e 100644 --- a/packages/relayer/indexer/indexer.go +++ b/packages/relayer/indexer/indexer.go @@ -17,7 +17,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" "github.com/labstack/echo/v4" - "github.com/labstack/gommon/log" "github.com/taikoxyz/taiko-mono/packages/relayer" "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/bridge" "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/taikol1" @@ -337,7 +336,9 @@ func (i *Indexer) filter(ctx context.Context) error { if err != nil { relayer.ErrorEvents.Inc() // log error but always return nil to keep other goroutines active - log.Error(err.Error()) + slog.Error("error handling event", "err", err.Error()) + } else { + slog.Info("handled event successfully") } return nil From 2192c867a860be8cb048937e88cd37202315cdcf Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 14:30:50 -0700 Subject: [PATCH 43/82] Reconnect --- packages/relayer/queue/rabbitmq/queue.go | 33 +++++++++++++++++++----- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 2f9d5c70b72..251011a7063 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -14,11 +14,26 @@ type RabbitMQ struct { conn *amqp.Connection ch *amqp.Channel queue amqp.Queue + opts NewQueueOpts } func NewQueue(opts queue.NewQueueOpts) (*RabbitMQ, error) { slog.Info("dialing rabbitmq connection") + conn, ch, err := connect(opts) + if err != nil { + return nil, err + } + + return &RabbitMQ{ + conn: conn, + ch: ch, + opts: opts, + }, nil +} + +func connect(opts queue.NewQueueOpts) (*amqp.Connection, *amqp.Channel, error) { + conn, err := amqp.Dial( fmt.Sprintf( "amqp://%v:%v@%v:%v/", @@ -28,18 +43,15 @@ func NewQueue(opts queue.NewQueueOpts) (*RabbitMQ, error) { opts.Port, )) if err != nil { - return nil, err + return nil, nil, err } ch, err := conn.Channel() if err != nil { - return nil, err + return nil, nil, err } - return &RabbitMQ{ - conn: conn, - ch: ch, - }, nil + return conn, ch, nil } func (r *RabbitMQ) Start(ctx context.Context, queueName string) error { @@ -80,6 +92,15 @@ func (r *RabbitMQ) Publish(ctx context.Context, msg []byte) error { Body: msg, }) if err != nil { + if err == amqp.ErrClosed { + conn, ch, err := connect(r.opts) + if err != nil { + return err + } + + r.conn = conn + r.ch = ch + } return err } From 8c87e1f4cb1308852ef0514e5ce2b0bf15436c9b Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 14:33:26 -0700 Subject: [PATCH 44/82] typo --- packages/relayer/queue/rabbitmq/queue.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 251011a7063..0f772477c93 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -14,7 +14,7 @@ type RabbitMQ struct { conn *amqp.Connection ch *amqp.Channel queue amqp.Queue - opts NewQueueOpts + opts queue.NewQueueOpts } func NewQueue(opts queue.NewQueueOpts) (*RabbitMQ, error) { From 36e1cfcde58b81dda8e44c741a2759b3a9cd2d86 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 14:33:39 -0700 Subject: [PATCH 45/82] lint --- packages/relayer/queue/rabbitmq/queue.go | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 0f772477c93..944df1baf44 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -33,7 +33,6 @@ func NewQueue(opts queue.NewQueueOpts) (*RabbitMQ, error) { } func connect(opts queue.NewQueueOpts) (*amqp.Connection, *amqp.Channel, error) { - conn, err := amqp.Dial( fmt.Sprintf( "amqp://%v:%v@%v:%v/", From 0487f4582c0228c1bdfb9a86a5e3457e2d623888 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 14:33:56 -0700 Subject: [PATCH 46/82] lint --- packages/relayer/queue/rabbitmq/queue.go | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 944df1baf44..ce78f792527 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -100,6 +100,7 @@ func (r *RabbitMQ) Publish(ctx context.Context, msg []byte) error { r.conn = conn r.ch = ch } + return err } From 2eff29a6d37781e6e2c8cc6e078b4e70b9c96094 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 14:34:13 -0700 Subject: [PATCH 47/82] return lint --- packages/relayer/queue/rabbitmq/queue.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index ce78f792527..998aa23eb16 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -99,9 +99,9 @@ func (r *RabbitMQ) Publish(ctx context.Context, msg []byte) error { r.conn = conn r.ch = ch + } else { + return err } - - return err } return nil From f17b7cb868b64480b8c41e627c656b7a5143d04c Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 14:36:25 -0700 Subject: [PATCH 48/82] try to publish again --- packages/relayer/queue/rabbitmq/queue.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 998aa23eb16..e09913f619e 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -99,6 +99,8 @@ func (r *RabbitMQ) Publish(ctx context.Context, msg []byte) error { r.conn = conn r.ch = ch + + return r.Publish(ctx, msg) } else { return err } From acbdb61bd0179be5b7eb9110e0a10303c8772bc8 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 19:29:16 -0700 Subject: [PATCH 49/82] handle connection closing --- packages/relayer/processor/processor.go | 9 +- packages/relayer/queue/queue.go | 5 ++ packages/relayer/queue/rabbitmq/queue.go | 105 +++++++++++++++-------- 3 files changed, 82 insertions(+), 37 deletions(-) diff --git a/packages/relayer/processor/processor.go b/packages/relayer/processor/processor.go index 16dc6cac760..27d0047c8ef 100644 --- a/packages/relayer/processor/processor.go +++ b/packages/relayer/processor/processor.go @@ -11,6 +11,7 @@ import ( "sync" "time" + "github.com/cenkalti/backoff/v4" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" @@ -255,9 +256,11 @@ func (p *Processor) Start() error { p.wg.Add(1) - if err := p.queue.Subscribe(ctx, p.msgCh, p.wg); err != nil { - return err - } + go func() { + backoff.Retry(func() error { + return p.queue.Subscribe(ctx, p.msgCh, p.wg) + }, backoff.NewConstantBackOff(1*time.Second)) + }() p.wg.Add(1) go p.eventLoop(ctx) diff --git a/packages/relayer/queue/queue.go b/packages/relayer/queue/queue.go index 24d4bbe9fab..4aff7d81c54 100644 --- a/packages/relayer/queue/queue.go +++ b/packages/relayer/queue/queue.go @@ -2,11 +2,16 @@ package queue import ( "context" + "errors" "sync" "github.com/taikoxyz/taiko-mono/packages/relayer/bindings/bridge" ) +var ( + ErrClosed = errors.New("queue connection closed") +) + type Queue interface { Start(ctx context.Context, queueName string) error Close(ctx context.Context) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index e09913f619e..69787960073 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -33,6 +33,7 @@ func NewQueue(opts queue.NewQueueOpts) (*RabbitMQ, error) { } func connect(opts queue.NewQueueOpts) (*amqp.Connection, *amqp.Channel, error) { + slog.Info("connecting to rabbitmq") conn, err := amqp.Dial( fmt.Sprintf( "amqp://%v:%v@%v:%v/", @@ -50,6 +51,8 @@ func connect(opts queue.NewQueueOpts) (*amqp.Connection, *amqp.Channel, error) { return nil, nil, err } + slog.Info("connected to rabbitmq") + return conn, ch, nil } @@ -74,8 +77,20 @@ func (r *RabbitMQ) Start(ctx context.Context, queueName string) error { } func (r *RabbitMQ) Close(ctx context.Context) { - defer r.conn.Close() - defer r.ch.Close() + if err := r.ch.Close(); err != nil { + if err != amqp.ErrClosed { + slog.Info("error closing rabbitmq connection", "err", err.Error()) + } + } + + slog.Info("closed rabbitmq channel") + + if err := r.conn.Close(); err != nil { + if err != amqp.ErrClosed { + slog.Info("error closing rabbitmq connection", "err", err.Error()) + } + } + slog.Info("closed rabbitmq connection" } func (r *RabbitMQ) Publish(ctx context.Context, msg []byte) error { @@ -92,6 +107,7 @@ func (r *RabbitMQ) Publish(ctx context.Context, msg []byte) error { }) if err != nil { if err == amqp.ErrClosed { + slog.Error("amqp channel closed", "err", err.Error()) conn, ch, err := connect(r.opts) if err != nil { return err @@ -114,7 +130,24 @@ func (r *RabbitMQ) Ack(ctx context.Context, msg queue.Message) error { slog.Info("acknowledging rabbitmq message", "msgId", rmqMsg.MessageId) - return rmqMsg.Ack(false) + err := rmqMsg.Ack(false) + if err != nil { + if err == amqp.ErrClosed { + slog.Error("amqp channel closed", "err", err.Error()) + r.Close(ctx) + conn, ch, err := connect(r.opts) + if err != nil { + return err + } + + r.conn = conn + r.ch = ch + + return r.Ack(ctx, msg) + } else { + return err + } + } } func (r *RabbitMQ) Nack(ctx context.Context, msg queue.Message) error { @@ -122,7 +155,23 @@ func (r *RabbitMQ) Nack(ctx context.Context, msg queue.Message) error { slog.Info("acknowledging rabbitmq message", "msgId", rmqMsg.MessageId) - return rmqMsg.Nack(false, false) + err := rmqMsg.Nack(false, false) + if err != nil { + if err == amqp.ErrClosed { + slog.Error("amqp channel closed", "err", err.Error()) + conn, ch, err := connect(r.opts) + if err != nil { + return err + } + + r.conn = conn + r.ch = ch + + return r.Nack(ctx, msg) + } else { + return err + } + } } func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, wg *sync.WaitGroup) error { @@ -130,6 +179,8 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, wg.Done() }() + slog.Info("subscribing to rabbitmq messages", "queue", r.queue.Name) + msgs, err := r.ch.Consume( r.queue.Name, "", @@ -144,39 +195,25 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, return err } - var nilCount int = 0 // wrap internal msg chan with a generic queue - go func() { - for { - select { - case <-ctx.Done(): - defer r.Close(ctx) - return - - case d := <-msgs: - if d.Body != nil { - slog.Info("rabbitmq message found", "msgId", d.MessageId) - { - msgChan <- queue.Message{ - Body: d.Body, - Internal: d, - } - } - } else { - nilCount++ - - if nilCount > 5 { - panic("repetitive nilBody delivery") + for { + select { + case <-ctx.Done(): + defer r.Close(ctx) + return nil + + case d := <-msgs: + if d.Body != nil { + slog.Info("rabbitmq message found", "msgId", d.MessageId) + { + msgChan <- queue.Message{ + Body: d.Body, + Internal: d, } - - slog.Info("nil rabbitmq message found", "msg", d) - // error with channel if we got a nil body message - // it wont be able to be acknowledged. - // re-establish connection? dunno yet. } + } else { + return queue.ErrClosed } } - }() - - return nil + } } From 131be7968003bb5f167cf08a892a7780d25fe5f1 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 19:32:07 -0700 Subject: [PATCH 50/82] lints --- packages/relayer/queue/rabbitmq/queue.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 69787960073..11259cc8099 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -34,6 +34,7 @@ func NewQueue(opts queue.NewQueueOpts) (*RabbitMQ, error) { func connect(opts queue.NewQueueOpts) (*amqp.Connection, *amqp.Channel, error) { slog.Info("connecting to rabbitmq") + conn, err := amqp.Dial( fmt.Sprintf( "amqp://%v:%v@%v:%v/", @@ -90,7 +91,8 @@ func (r *RabbitMQ) Close(ctx context.Context) { slog.Info("error closing rabbitmq connection", "err", err.Error()) } } - slog.Info("closed rabbitmq connection" + + slog.Info("closed rabbitmq connection") } func (r *RabbitMQ) Publish(ctx context.Context, msg []byte) error { @@ -108,6 +110,7 @@ func (r *RabbitMQ) Publish(ctx context.Context, msg []byte) error { if err != nil { if err == amqp.ErrClosed { slog.Error("amqp channel closed", "err", err.Error()) + conn, ch, err := connect(r.opts) if err != nil { return err @@ -134,7 +137,9 @@ func (r *RabbitMQ) Ack(ctx context.Context, msg queue.Message) error { if err != nil { if err == amqp.ErrClosed { slog.Error("amqp channel closed", "err", err.Error()) + r.Close(ctx) + conn, ch, err := connect(r.opts) if err != nil { return err @@ -148,6 +153,8 @@ func (r *RabbitMQ) Ack(ctx context.Context, msg queue.Message) error { return err } } + + return nil } func (r *RabbitMQ) Nack(ctx context.Context, msg queue.Message) error { @@ -159,6 +166,7 @@ func (r *RabbitMQ) Nack(ctx context.Context, msg queue.Message) error { if err != nil { if err == amqp.ErrClosed { slog.Error("amqp channel closed", "err", err.Error()) + conn, ch, err := connect(r.opts) if err != nil { return err @@ -172,6 +180,8 @@ func (r *RabbitMQ) Nack(ctx context.Context, msg queue.Message) error { return err } } + + return nil } func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, wg *sync.WaitGroup) error { @@ -199,7 +209,7 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, for { select { case <-ctx.Done(): - defer r.Close(ctx) + r.Close(ctx) return nil case d := <-msgs: From 31f67a64d83a6b6c36545b052642656978cf0055 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 19:44:17 -0700 Subject: [PATCH 51/82] notify cancel --- packages/relayer/queue/rabbitmq/queue.go | 66 +++++++++++++++++++----- 1 file changed, 52 insertions(+), 14 deletions(-) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 11259cc8099..4b6e805dee7 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -15,46 +15,80 @@ type RabbitMQ struct { ch *amqp.Channel queue amqp.Queue opts queue.NewQueueOpts + + connErrCh chan *amqp.Error + + chErrCh chan *amqp.Error + + notifyCtx context.Context + cancel context.CancelFunc } func NewQueue(opts queue.NewQueueOpts) (*RabbitMQ, error) { slog.Info("dialing rabbitmq connection") - conn, ch, err := connect(opts) + r := &RabbitMQ{ + opts: opts, + } + + err := r.connect() if err != nil { return nil, err } - return &RabbitMQ{ - conn: conn, - ch: ch, - opts: opts, - }, nil + return r, nil } -func connect(opts queue.NewQueueOpts) (*amqp.Connection, *amqp.Channel, error) { +func (r *RabbitMQ) connect() error { slog.Info("connecting to rabbitmq") + if r.cancel != nil { + r.cancel() + } + + r.notifyCtx, r.cancel = context.WithCancel(context.Background()) + conn, err := amqp.Dial( fmt.Sprintf( "amqp://%v:%v@%v:%v/", - opts.Username, - opts.Password, - opts.Host, - opts.Port, + r.opts.Username, + r.opts.Password, + r.opts.Host, + r.opts.Port, )) if err != nil { - return nil, nil, err + return err } ch, err := conn.Channel() if err != nil { - return nil, nil, err + return err } + r.conn = conn + r.ch = ch + + r.connErrCh = r.conn.NotifyClose(make(chan *amqp.Error)) + + r.chErrCh = r.ch.NotifyClose(make(chan *amqp.Error)) + + go func() { + for { + select { + case <-r.notifyCtx.Done(): + slog.Info("notifyCtx cancelled") + return + case err := <-r.connErrCh: + slog.Error("rabbitmq notify close connection", "err", err.Error()) + case err := <-r.chErrCh: + slog.Error("rabbitmq notify close channel", "err", err.Error()) + } + } + }() + slog.Info("connected to rabbitmq") - return conn, ch, nil + return nil } func (r *RabbitMQ) Start(ctx context.Context, queueName string) error { @@ -78,6 +112,10 @@ func (r *RabbitMQ) Start(ctx context.Context, queueName string) error { } func (r *RabbitMQ) Close(ctx context.Context) { + if r.cancel != nil { + r.cancel() + } + if err := r.ch.Close(); err != nil { if err != amqp.ErrClosed { slog.Info("error closing rabbitmq connection", "err", err.Error()) From 016748fcf3a74ab58208d376f0b58f75b75c5b04 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 19:47:45 -0700 Subject: [PATCH 52/82] fix connect --- packages/relayer/queue/rabbitmq/queue.go | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 4b6e805dee7..2f65d18e8f0 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -149,14 +149,11 @@ func (r *RabbitMQ) Publish(ctx context.Context, msg []byte) error { if err == amqp.ErrClosed { slog.Error("amqp channel closed", "err", err.Error()) - conn, ch, err := connect(r.opts) + err := r.connect() if err != nil { return err } - r.conn = conn - r.ch = ch - return r.Publish(ctx, msg) } else { return err @@ -178,14 +175,11 @@ func (r *RabbitMQ) Ack(ctx context.Context, msg queue.Message) error { r.Close(ctx) - conn, ch, err := connect(r.opts) + err := r.connect() if err != nil { return err } - r.conn = conn - r.ch = ch - return r.Ack(ctx, msg) } else { return err @@ -205,14 +199,11 @@ func (r *RabbitMQ) Nack(ctx context.Context, msg queue.Message) error { if err == amqp.ErrClosed { slog.Error("amqp channel closed", "err", err.Error()) - conn, ch, err := connect(r.opts) + err := r.connect() if err != nil { return err } - r.conn = conn - r.ch = ch - return r.Nack(ctx, msg) } else { return err From 2694a748a4ee5dcf972418c88cd3daec8a665313 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 19:50:10 -0700 Subject: [PATCH 53/82] err check --- packages/relayer/processor/processor.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/relayer/processor/processor.go b/packages/relayer/processor/processor.go index 27d0047c8ef..83eec69ff99 100644 --- a/packages/relayer/processor/processor.go +++ b/packages/relayer/processor/processor.go @@ -257,9 +257,11 @@ func (p *Processor) Start() error { p.wg.Add(1) go func() { - backoff.Retry(func() error { + if err := backoff.Retry(func() error { return p.queue.Subscribe(ctx, p.msgCh, p.wg) - }, backoff.NewConstantBackOff(1*time.Second)) + }, backoff.NewConstantBackOff(1*time.Second)); err != nil { + slog.Error("rabbitmq subscribe backoff retry error", "err", err.Error()) + } }() p.wg.Add(1) From f76357d00cc9a9d7eddaa8c79cdeb09b5bb126bd Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Fri, 1 Sep 2023 19:55:52 -0700 Subject: [PATCH 54/82] handle reconnect --- packages/relayer/processor/processor.go | 2 -- packages/relayer/queue/rabbitmq/queue.go | 45 ++++++++---------------- 2 files changed, 15 insertions(+), 32 deletions(-) diff --git a/packages/relayer/processor/processor.go b/packages/relayer/processor/processor.go index 83eec69ff99..532acc458f6 100644 --- a/packages/relayer/processor/processor.go +++ b/packages/relayer/processor/processor.go @@ -254,8 +254,6 @@ func (p *Processor) Start() error { return err } - p.wg.Add(1) - go func() { if err := backoff.Retry(func() error { return p.queue.Subscribe(ctx, p.msgCh, p.wg) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 2f65d18e8f0..aaf7a6446dd 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -19,9 +19,6 @@ type RabbitMQ struct { connErrCh chan *amqp.Error chErrCh chan *amqp.Error - - notifyCtx context.Context - cancel context.CancelFunc } func NewQueue(opts queue.NewQueueOpts) (*RabbitMQ, error) { @@ -42,12 +39,6 @@ func NewQueue(opts queue.NewQueueOpts) (*RabbitMQ, error) { func (r *RabbitMQ) connect() error { slog.Info("connecting to rabbitmq") - if r.cancel != nil { - r.cancel() - } - - r.notifyCtx, r.cancel = context.WithCancel(context.Background()) - conn, err := amqp.Dial( fmt.Sprintf( "amqp://%v:%v@%v:%v/", @@ -72,20 +63,6 @@ func (r *RabbitMQ) connect() error { r.chErrCh = r.ch.NotifyClose(make(chan *amqp.Error)) - go func() { - for { - select { - case <-r.notifyCtx.Done(): - slog.Info("notifyCtx cancelled") - return - case err := <-r.connErrCh: - slog.Error("rabbitmq notify close connection", "err", err.Error()) - case err := <-r.chErrCh: - slog.Error("rabbitmq notify close channel", "err", err.Error()) - } - } - }() - slog.Info("connected to rabbitmq") return nil @@ -112,10 +89,6 @@ func (r *RabbitMQ) Start(ctx context.Context, queueName string) error { } func (r *RabbitMQ) Close(ctx context.Context) { - if r.cancel != nil { - r.cancel() - } - if err := r.ch.Close(); err != nil { if err != amqp.ErrClosed { slog.Info("error closing rabbitmq connection", "err", err.Error()) @@ -214,6 +187,8 @@ func (r *RabbitMQ) Nack(ctx context.Context, msg queue.Message) error { } func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, wg *sync.WaitGroup) error { + wg.Add(1) + defer func() { wg.Done() }() @@ -231,16 +206,26 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, ) if err != nil { - return err + if err == amqp.ErrClosed { + if err := r.connect(); err != nil { + slog.Error("error reconnecting to channel during subscribe", "err", err.Error()) + } + } else { + return err + } } - // wrap internal msg chan with a generic queue for { select { case <-ctx.Done(): r.Close(ctx) return nil - + case err := <-r.connErrCh: + slog.Error("rabbitmq notify close connection", "err", err.Error()) + return queue.ErrClosed + case err := <-r.chErrCh: + slog.Error("rabbitmq notify close channel", "err", err.Error()) + return queue.ErrClosed case d := <-msgs: if d.Body != nil { slog.Info("rabbitmq message found", "msgId", d.MessageId) From 33437e7e2818511172feb4aabe7a45768aee9f1d Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sat, 2 Sep 2023 00:55:50 -0700 Subject: [PATCH 55/82] dont panic on scanning block, use backoff retry indefinitely --- packages/relayer/indexer/indexer.go | 9 ++++++++- packages/relayer/indexer/scan_blocks.go | 13 +++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/relayer/indexer/indexer.go b/packages/relayer/indexer/indexer.go index bc07b737e3e..28156d011c2 100644 --- a/packages/relayer/indexer/indexer.go +++ b/packages/relayer/indexer/indexer.go @@ -10,6 +10,7 @@ import ( "sync" "time" + "github.com/cenkalti/backoff/v4" "github.com/cyberhorsey/errors" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -243,7 +244,13 @@ func (i *Indexer) Start() error { } }() - go scanBlocks(i.ctx, i.srcEthClient, i.srcChainId, i.wg) + go func() { + if err := backoff.Retry(func() error { + return scanBlocks(i.ctx, i.srcEthClient, i.srcChainId, i.wg) + }, backoff.NewConstantBackOff(5*time.Second)); err != nil { + slog.Error("scan blocks backoff retry", "error", err) + } + }() return nil } diff --git a/packages/relayer/indexer/scan_blocks.go b/packages/relayer/indexer/scan_blocks.go index 4c667bf4864..3c331d3362a 100644 --- a/packages/relayer/indexer/scan_blocks.go +++ b/packages/relayer/indexer/scan_blocks.go @@ -9,7 +9,7 @@ import ( "github.com/taikoxyz/taiko-mono/packages/relayer" ) -func scanBlocks(ctx context.Context, ethClient ethClient, chainID *big.Int, wg *sync.WaitGroup) { +func scanBlocks(ctx context.Context, ethClient ethClient, chainID *big.Int, wg *sync.WaitGroup) error { wg.Add(1) defer func() { @@ -20,19 +20,16 @@ func scanBlocks(ctx context.Context, ethClient ethClient, chainID *big.Int, wg * sub, err := ethClient.SubscribeNewHead(ctx, headers) if err != nil { - panic(err) + return err } for { select { case <-ctx.Done(): - return - case <-sub.Err(): + return nil + case err := <-sub.Err(): relayer.BlocksScannedError.Inc() - - scanBlocks(ctx, ethClient, chainID, wg) - - return + return err case <-headers: relayer.BlocksScanned.Inc() } From 67da8e6135ee2f277fdf19b7964e5218867d64dc Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sat, 2 Sep 2023 17:07:19 -0700 Subject: [PATCH 56/82] additional logs --- packages/relayer/processor/processor.go | 2 +- packages/relayer/queue/rabbitmq/queue.go | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/relayer/processor/processor.go b/packages/relayer/processor/processor.go index 532acc458f6..864cbca91d8 100644 --- a/packages/relayer/processor/processor.go +++ b/packages/relayer/processor/processor.go @@ -238,7 +238,6 @@ func (p *Processor) Name() string { return "processor" } -// TODO func (p *Processor) Close(ctx context.Context) { p.cancel() @@ -256,6 +255,7 @@ func (p *Processor) Start() error { go func() { if err := backoff.Retry(func() error { + slog.Info("attempting backoff queue subscription") return p.queue.Subscribe(ctx, p.msgCh, p.wg) }, backoff.NewConstantBackOff(1*time.Second)); err != nil { slog.Error("rabbitmq subscribe backoff retry error", "err", err.Error()) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index aaf7a6446dd..739f175589a 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -159,13 +159,15 @@ func (r *RabbitMQ) Ack(ctx context.Context, msg queue.Message) error { } } + slog.Info("acknowledged rabbitmq message", "msgId", rmqMsg.MessageId) + return nil } func (r *RabbitMQ) Nack(ctx context.Context, msg queue.Message) error { rmqMsg := msg.Internal.(amqp.Delivery) - slog.Info("acknowledging rabbitmq message", "msgId", rmqMsg.MessageId) + slog.Info("negatively acknowledging rabbitmq message", "msgId", rmqMsg.MessageId) err := rmqMsg.Nack(false, false) if err != nil { @@ -183,6 +185,8 @@ func (r *RabbitMQ) Nack(ctx context.Context, msg queue.Message) error { } } + slog.Info("negatively acknowledged rabbitmq message", "msgId", rmqMsg.MessageId) + return nil } @@ -209,6 +213,7 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, if err == amqp.ErrClosed { if err := r.connect(); err != nil { slog.Error("error reconnecting to channel during subscribe", "err", err.Error()) + return err } } else { return err @@ -218,7 +223,9 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, for { select { case <-ctx.Done(): + slog.Info("rabbitmq context closed") r.Close(ctx) + return nil case err := <-r.connErrCh: slog.Error("rabbitmq notify close connection", "err", err.Error()) @@ -236,6 +243,7 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, } } } else { + slog.Info("nil body message, queue is closed") return queue.ErrClosed } } From c5a4968ea84334cf2b1b2cbae25cfb1f74c69cc1 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sat, 2 Sep 2023 17:09:50 -0700 Subject: [PATCH 57/82] correct ack logs --- packages/relayer/processor/process_message.go | 2 +- packages/relayer/processor/processor.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/relayer/processor/process_message.go b/packages/relayer/processor/process_message.go index 9cdccce34a3..2bd333a02ef 100644 --- a/packages/relayer/processor/process_message.go +++ b/packages/relayer/processor/process_message.go @@ -193,7 +193,7 @@ func (p *Processor) processMessage( // update message status if err := p.eventRepo.UpdateStatus(ctx, msgBody.ID, relayer.EventStatus(messageStatus)); err != nil { - return errors.Wrap(err, "s.eventRepo.UpdateStatus") + return errors.Wrap(err, fmt.Sprintf("p.eventRepo.UpdateStatus, id: %v", msgBody.ID)) } if err := p.queue.Ack(ctx, msg); err != nil { diff --git a/packages/relayer/processor/processor.go b/packages/relayer/processor/processor.go index 864cbca91d8..5aec9048cf6 100644 --- a/packages/relayer/processor/processor.go +++ b/packages/relayer/processor/processor.go @@ -294,7 +294,7 @@ func (p *Processor) eventLoop(ctx context.Context) { // if errUnprocessable, we can Ack it to remove it from // beign re-added, message should never become processable. if err := p.queue.Ack(ctx, msg); err != nil { - slog.Error("Err nacking message", "err", err.Error()) + slog.Error("Err acking message", "err", err.Error()) } } } From 338d3bd407c98c71bdb75792b01e4b3aa40ff69d Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sat, 2 Sep 2023 21:35:20 -0700 Subject: [PATCH 58/82] use a ticker to make sure deliveries get processed --- packages/relayer/queue/rabbitmq/queue.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 739f175589a..bebc36c0ca0 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -5,6 +5,7 @@ import ( "fmt" "log/slog" "sync" + "time" amqp "github.com/rabbitmq/amqp091-go" "github.com/taikoxyz/taiko-mono/packages/relayer/queue" @@ -193,6 +194,10 @@ func (r *RabbitMQ) Nack(ctx context.Context, msg queue.Message) error { func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, wg *sync.WaitGroup) error { wg.Add(1) + defer func() { + r.Close(ctx) + }() + defer func() { wg.Done() }() @@ -220,6 +225,10 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, } } + t := time.NewTicker(5 * time.Second) + + var lastDelivery time.Time = time.Now() + for { select { case <-ctx.Done(): @@ -234,6 +243,8 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, slog.Error("rabbitmq notify close channel", "err", err.Error()) return queue.ErrClosed case d := <-msgs: + lastDelivery = time.Now() + if d.Body != nil { slog.Info("rabbitmq message found", "msgId", d.MessageId) { @@ -246,6 +257,14 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, slog.Info("nil body message, queue is closed") return queue.ErrClosed } + case <-t.C: + if time.Since(lastDelivery) > (5 * time.Minute) { + // we havent had a delivery for 5 message. sometimes, rabbitmq queues + // can falter and the connection doesnt notify its closed. lets return an error + // and backoff will retry + slog.Info("five minutes passed since delivery found, reconnecting to rabbitmq") + return queue.ErrClosed + } } } } From 5470818faf9636e534595e1b6dfb0bc8c7b74e31 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sat, 2 Sep 2023 23:07:45 -0700 Subject: [PATCH 59/82] notify for queue --- go.mod | 2 +- go.sum | 2 ++ packages/relayer/indexer/indexer.go | 4 +++ packages/relayer/mock/queue.go | 4 +++ packages/relayer/queue/queue.go | 1 + packages/relayer/queue/rabbitmq/queue.go | 43 +++++++++++++++++++----- 6 files changed, 47 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 9240a5fcfd5..e6ab665cd6b 100644 --- a/go.mod +++ b/go.mod @@ -72,7 +72,7 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/go-cmp v0.5.9 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/google/uuid v1.3.1 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/gorilla/websocket v1.4.2 // indirect github.com/iancoleman/strcase v0.2.0 // indirect diff --git a/go.sum b/go.sum index 37f862b76a4..e096b2967b9 100644 --- a/go.sum +++ b/go.sum @@ -201,6 +201,8 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= diff --git a/packages/relayer/indexer/indexer.go b/packages/relayer/indexer/indexer.go index 28156d011c2..23add9a3c59 100644 --- a/packages/relayer/indexer/indexer.go +++ b/packages/relayer/indexer/indexer.go @@ -252,6 +252,10 @@ func (i *Indexer) Start() error { } }() + go func() { + i.queue.Notify(i.ctx, i.wg) + }() + return nil } diff --git a/packages/relayer/mock/queue.go b/packages/relayer/mock/queue.go index 0d21cf31e54..4e775cf0817 100644 --- a/packages/relayer/mock/queue.go +++ b/packages/relayer/mock/queue.go @@ -18,6 +18,10 @@ func (r *Queue) Close(ctx context.Context) { } +func (r *Queue) Notify(ctx context.Context, wg *sync.WaitGroup) error { + return nil +} + func (r *Queue) Publish(ctx context.Context, msg []byte) error { return nil } diff --git a/packages/relayer/queue/queue.go b/packages/relayer/queue/queue.go index 4aff7d81c54..6dba516f6ea 100644 --- a/packages/relayer/queue/queue.go +++ b/packages/relayer/queue/queue.go @@ -16,6 +16,7 @@ type Queue interface { Start(ctx context.Context, queueName string) error Close(ctx context.Context) Publish(ctx context.Context, msg []byte) error + Notify(ctx context.Context, wg *sync.WaitGroup) error Subscribe(ctx context.Context, msgs chan<- Message, wg *sync.WaitGroup) error Ack(ctx context.Context, msg Message) error Nack(ctx context.Context, msg Message) error diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index bebc36c0ca0..23acb5dde8d 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -20,6 +20,8 @@ type RabbitMQ struct { connErrCh chan *amqp.Error chErrCh chan *amqp.Error + + notifyReturnCh chan amqp.Return } func NewQueue(opts queue.NewQueueOpts) (*RabbitMQ, error) { @@ -113,7 +115,7 @@ func (r *RabbitMQ) Publish(ctx context.Context, msg []byte) error { err := r.ch.PublishWithContext(ctx, "", r.queue.Name, - false, + true, false, amqp.Publishing{ ContentType: "text/plain", @@ -191,6 +193,38 @@ func (r *RabbitMQ) Nack(ctx context.Context, msg queue.Message) error { return nil } +// Notify should be called by publishers who wish to be notified of subscription errors. +func (r *RabbitMQ) Notify(ctx context.Context, wg *sync.WaitGroup) error { + wg.Add(1) + + defer func() { + wg.Done() + }() + + for { + select { + case <-ctx.Done(): + slog.Info("rabbitmq context closed") + + return nil + case err := <-r.connErrCh: + slog.Error("rabbitmq notify close connection", "err", err.Error()) + return queue.ErrClosed + case err := <-r.chErrCh: + slog.Error("rabbitmq notify close channel", "err", err.Error()) + return queue.ErrClosed + case returnMsg := <-r.notifyReturnCh: + slog.Error("rabbitmq notify return", "id", returnMsg.MessageId, "err", returnMsg.ReplyText) + slog.Info("rabbitmq attempting republish of returned msg", "id", returnMsg.MessageId) + + if err := r.Publish(ctx, returnMsg.Body); err != nil { + slog.Error("error publishing msg", "err", err.Error()) + } + } + } +} + +// Subscribe should be called by consumers. func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, wg *sync.WaitGroup) error { wg.Add(1) @@ -233,15 +267,8 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, select { case <-ctx.Done(): slog.Info("rabbitmq context closed") - r.Close(ctx) return nil - case err := <-r.connErrCh: - slog.Error("rabbitmq notify close connection", "err", err.Error()) - return queue.ErrClosed - case err := <-r.chErrCh: - slog.Error("rabbitmq notify close channel", "err", err.Error()) - return queue.ErrClosed case d := <-msgs: lastDelivery = time.Now() From 5cb135923c720cf6e1259cc8044a183bb50e1eb0 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sat, 2 Sep 2023 23:19:08 -0700 Subject: [PATCH 60/82] inspect queue every tick --- packages/relayer/indexer/indexer.go | 6 +++++- packages/relayer/queue/rabbitmq/queue.go | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/relayer/indexer/indexer.go b/packages/relayer/indexer/indexer.go index 23add9a3c59..025050e3361 100644 --- a/packages/relayer/indexer/indexer.go +++ b/packages/relayer/indexer/indexer.go @@ -253,7 +253,11 @@ func (i *Indexer) Start() error { }() go func() { - i.queue.Notify(i.ctx, i.wg) + if err := backoff.Retry(func() error { + return i.queue.Notify(i.ctx, i.wg) + }, backoff.NewConstantBackOff(5*time.Second)); err != nil { + slog.Error("queue notify backoff retry", "error", err) + } }() return nil diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 23acb5dde8d..53e2d220672 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -285,6 +285,21 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, return queue.ErrClosed } case <-t.C: + // inspect queue, check messages every tick. + q, err := r.ch.QueueDeclarePassive( + r.queue.Name, + false, + false, + false, + false, + nil, + ) + if err != nil { + return err + } + + slog.Info("rabbitmq queue info", "name", q.Name, "msgs", q.Messages) + if time.Since(lastDelivery) > (5 * time.Minute) { // we havent had a delivery for 5 message. sometimes, rabbitmq queues // can falter and the connection doesnt notify its closed. lets return an error From fd49fc146192041dc74290aadf225d9b3685852c Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sat, 2 Sep 2023 23:40:15 -0700 Subject: [PATCH 61/82] need new msgs ch after connecting --- packages/relayer/queue/rabbitmq/queue.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 53e2d220672..adab22d9118 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -201,6 +201,8 @@ func (r *RabbitMQ) Notify(ctx context.Context, wg *sync.WaitGroup) error { wg.Done() }() + slog.Info("rabbitmq notify running") + for { select { case <-ctx.Done(): @@ -254,6 +256,19 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, slog.Error("error reconnecting to channel during subscribe", "err", err.Error()) return err } + + msgs, err = r.ch.Consume( + r.queue.Name, + "", + false, // disable auto-acknowledge until after processing + false, + false, + false, + nil, + ) + if err != nil { + return err + } } else { return err } From 5401a6ec1ff3375a6fd45786ed310f3a445c2542 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sat, 2 Sep 2023 23:41:07 -0700 Subject: [PATCH 62/82] notifiers back in subscribe --- packages/relayer/queue/rabbitmq/queue.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index adab22d9118..829dcf0d206 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -284,6 +284,12 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, slog.Info("rabbitmq context closed") return nil + case err := <-r.connErrCh: + slog.Error("rabbitmq notify close connection", "err", err.Error()) + return queue.ErrClosed + case err := <-r.chErrCh: + slog.Error("rabbitmq notify close channel", "err", err.Error()) + return queue.ErrClosed case d := <-msgs: lastDelivery = time.Now() From 14f1f0a6238da52639b5b4b482b5313900513155 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sat, 2 Sep 2023 23:42:15 -0700 Subject: [PATCH 63/82] log --- packages/relayer/queue/rabbitmq/queue.go | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 829dcf0d206..f49be3d41f2 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -252,6 +252,7 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, if err != nil { if err == amqp.ErrClosed { + slog.Info("cant subscribe to rabbitmq, channel closed. attempting reconnection") if err := r.connect(); err != nil { slog.Error("error reconnecting to channel during subscribe", "err", err.Error()) return err From eebd0aec2bb20ab803a278e55f973aad92c65d3f Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sat, 2 Sep 2023 23:47:21 -0700 Subject: [PATCH 64/82] . --- packages/relayer/queue/rabbitmq/queue.go | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index f49be3d41f2..a56d317215c 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -253,6 +253,7 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, if err != nil { if err == amqp.ErrClosed { slog.Info("cant subscribe to rabbitmq, channel closed. attempting reconnection") + if err := r.connect(); err != nil { slog.Error("error reconnecting to channel during subscribe", "err", err.Error()) return err From a7418b69d8c5f1f2672a59af8a4499af18e1e05c Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sun, 3 Sep 2023 00:02:20 -0700 Subject: [PATCH 65/82] Add quick heartbeat --- packages/relayer/queue/rabbitmq/queue.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index a56d317215c..a493bf1e0eb 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -42,14 +42,16 @@ func NewQueue(opts queue.NewQueueOpts) (*RabbitMQ, error) { func (r *RabbitMQ) connect() error { slog.Info("connecting to rabbitmq") - conn, err := amqp.Dial( + conn, err := amqp.DialConfig( fmt.Sprintf( "amqp://%v:%v@%v:%v/", r.opts.Username, r.opts.Password, r.opts.Host, r.opts.Port, - )) + ), amqp.Config{ + Heartbeat: 1 * time.Second, + }) if err != nil { return err } @@ -76,7 +78,7 @@ func (r *RabbitMQ) Start(ctx context.Context, queueName string) error { q, err := r.ch.QueueDeclare( queueName, - false, + true, false, false, false, @@ -311,7 +313,7 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, // inspect queue, check messages every tick. q, err := r.ch.QueueDeclarePassive( r.queue.Name, - false, + true, false, false, false, From 350ea25a5298af312830e28bad95d04e2ac8abac Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sun, 3 Sep 2023 00:21:06 -0700 Subject: [PATCH 66/82] Add a message id --- packages/relayer/queue/rabbitmq/queue.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index a493bf1e0eb..d479d0c8bd6 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -7,6 +7,7 @@ import ( "sync" "time" + "github.com/google/uuid" amqp "github.com/rabbitmq/amqp091-go" "github.com/taikoxyz/taiko-mono/packages/relayer/queue" ) @@ -122,6 +123,7 @@ func (r *RabbitMQ) Publish(ctx context.Context, msg []byte) error { amqp.Publishing{ ContentType: "text/plain", Body: msg, + MessageId: uuid.New().String(), }) if err != nil { if err == amqp.ErrClosed { From 6fc2d1981b617347d7feb19a35e6decb390f128a Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sun, 3 Sep 2023 12:11:43 -0700 Subject: [PATCH 67/82] more logs + a subscription specific ctx to restart the subscription --- packages/relayer/processor/processor.go | 7 ++++++- packages/relayer/queue/rabbitmq/queue.go | 21 ++++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/packages/relayer/processor/processor.go b/packages/relayer/processor/processor.go index 5aec9048cf6..2ce898d61d9 100644 --- a/packages/relayer/processor/processor.go +++ b/packages/relayer/processor/processor.go @@ -256,7 +256,12 @@ func (p *Processor) Start() error { go func() { if err := backoff.Retry(func() error { slog.Info("attempting backoff queue subscription") - return p.queue.Subscribe(ctx, p.msgCh, p.wg) + if err := p.queue.Subscribe(ctx, p.msgCh, p.wg); err != nil { + slog.Info("processor queue subscription error", "err", err.Error()) + return err + } + + return nil }, backoff.NewConstantBackOff(1*time.Second)); err != nil { slog.Error("rabbitmq subscribe backoff retry error", "err", err.Error()) } diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index d479d0c8bd6..c65b429c32a 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -23,6 +23,9 @@ type RabbitMQ struct { chErrCh chan *amqp.Error notifyReturnCh chan amqp.Return + + subscriptionCtx context.Context + subscriptionCancel context.CancelFunc } func NewQueue(opts queue.NewQueueOpts) (*RabbitMQ, error) { @@ -43,6 +46,10 @@ func NewQueue(opts queue.NewQueueOpts) (*RabbitMQ, error) { func (r *RabbitMQ) connect() error { slog.Info("connecting to rabbitmq") + if r.subscriptionCancel != nil { + r.subscriptionCancel() + } + conn, err := amqp.DialConfig( fmt.Sprintf( "amqp://%v:%v@%v:%v/", @@ -69,6 +76,8 @@ func (r *RabbitMQ) connect() error { r.chErrCh = r.ch.NotifyClose(make(chan *amqp.Error)) + r.subscriptionCtx, r.subscriptionCancel = context.WithCancel(context.Background()) + slog.Info("connected to rabbitmq") return nil @@ -157,11 +166,13 @@ func (r *RabbitMQ) Ack(ctx context.Context, msg queue.Message) error { err := r.connect() if err != nil { + slog.Error("error reconnecting to rabbitmq", "err", err.Error()) return err } return r.Ack(ctx, msg) } else { + slog.Error("error acknowledging rabbitmq message", "err", err.Error()) return err } } @@ -181,13 +192,17 @@ func (r *RabbitMQ) Nack(ctx context.Context, msg queue.Message) error { if err == amqp.ErrClosed { slog.Error("amqp channel closed", "err", err.Error()) + r.Close(ctx) + err := r.connect() if err != nil { + slog.Error("error reconnecting to rabbitmq", "err", err.Error()) return err } return r.Nack(ctx, msg) } else { + slog.Error("error negatively acknowledging rabbitmq message", "err", err.Error()) return err } } @@ -286,8 +301,11 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, for { select { + case <-r.subscriptionCtx.Done(): + slog.Info("rabbitmq subscription ctx cancelled") + return queue.ErrClosed case <-ctx.Done(): - slog.Info("rabbitmq context closed") + slog.Info("rabbitmq context cancelled") return nil case err := <-r.connErrCh: @@ -312,6 +330,7 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, return queue.ErrClosed } case <-t.C: + slog.Info("rabbitmq queue subscribe ticker") // inspect queue, check messages every tick. q, err := r.ch.QueueDeclarePassive( r.queue.Name, From 9426c479a488c14e813dd756804856973fd5493e Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sun, 3 Sep 2023 12:25:25 -0700 Subject: [PATCH 68/82] dont ack/nack in a loop, delivery cant be delivered on same channel, will be picked up again in subscription --- packages/relayer/queue/rabbitmq/queue.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index c65b429c32a..3636863ca68 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -170,7 +170,7 @@ func (r *RabbitMQ) Ack(ctx context.Context, msg queue.Message) error { return err } - return r.Ack(ctx, msg) + return err } else { slog.Error("error acknowledging rabbitmq message", "err", err.Error()) return err @@ -200,7 +200,7 @@ func (r *RabbitMQ) Nack(ctx context.Context, msg queue.Message) error { return err } - return r.Nack(ctx, msg) + return err } else { slog.Error("error negatively acknowledging rabbitmq message", "err", err.Error()) return err From 696426ab3b26f49edffd02efdac5093717491fd6 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sun, 3 Sep 2023 13:17:05 -0700 Subject: [PATCH 69/82] error => info? --- packages/relayer/queue/rabbitmq/queue.go | 32 ++++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 3636863ca68..a9a20e55055 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -72,9 +72,9 @@ func (r *RabbitMQ) connect() error { r.conn = conn r.ch = ch - r.connErrCh = r.conn.NotifyClose(make(chan *amqp.Error)) + r.connErrCh = r.conn.NotifyClose(make(chan *amqp.Error, 1)) - r.chErrCh = r.ch.NotifyClose(make(chan *amqp.Error)) + r.chErrCh = r.ch.NotifyClose(make(chan *amqp.Error, 1)) r.subscriptionCtx, r.subscriptionCancel = context.WithCancel(context.Background()) @@ -136,7 +136,7 @@ func (r *RabbitMQ) Publish(ctx context.Context, msg []byte) error { }) if err != nil { if err == amqp.ErrClosed { - slog.Error("amqp channel closed", "err", err.Error()) + slog.Info("amqp channel closed", "err", err.Error()) err := r.connect() if err != nil { @@ -160,19 +160,19 @@ func (r *RabbitMQ) Ack(ctx context.Context, msg queue.Message) error { err := rmqMsg.Ack(false) if err != nil { if err == amqp.ErrClosed { - slog.Error("amqp channel closed", "err", err.Error()) + slog.Info("amqp channel closed", "err", err.Error()) r.Close(ctx) err := r.connect() if err != nil { - slog.Error("error reconnecting to rabbitmq", "err", err.Error()) + slog.Info("error reconnecting to rabbitmq", "err", err.Error()) return err } return err } else { - slog.Error("error acknowledging rabbitmq message", "err", err.Error()) + slog.Info("error acknowledging rabbitmq message", "err", err.Error()) return err } } @@ -190,19 +190,19 @@ func (r *RabbitMQ) Nack(ctx context.Context, msg queue.Message) error { err := rmqMsg.Nack(false, false) if err != nil { if err == amqp.ErrClosed { - slog.Error("amqp channel closed", "err", err.Error()) + slog.Info("amqp channel closed", "err", err.Error()) r.Close(ctx) err := r.connect() if err != nil { - slog.Error("error reconnecting to rabbitmq", "err", err.Error()) + slog.Info("error reconnecting to rabbitmq", "err", err.Error()) return err } return err } else { - slog.Error("error negatively acknowledging rabbitmq message", "err", err.Error()) + slog.Info("error negatively acknowledging rabbitmq message", "err", err.Error()) return err } } @@ -229,17 +229,17 @@ func (r *RabbitMQ) Notify(ctx context.Context, wg *sync.WaitGroup) error { return nil case err := <-r.connErrCh: - slog.Error("rabbitmq notify close connection", "err", err.Error()) + slog.Info("rabbitmq notify close connection", "err", err.Error()) return queue.ErrClosed case err := <-r.chErrCh: - slog.Error("rabbitmq notify close channel", "err", err.Error()) + slog.Info("rabbitmq notify close channel", "err", err.Error()) return queue.ErrClosed case returnMsg := <-r.notifyReturnCh: - slog.Error("rabbitmq notify return", "id", returnMsg.MessageId, "err", returnMsg.ReplyText) + slog.Info("rabbitmq notify return", "id", returnMsg.MessageId, "err", returnMsg.ReplyText) slog.Info("rabbitmq attempting republish of returned msg", "id", returnMsg.MessageId) if err := r.Publish(ctx, returnMsg.Body); err != nil { - slog.Error("error publishing msg", "err", err.Error()) + slog.Info("error publishing msg", "err", err.Error()) } } } @@ -274,7 +274,7 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, slog.Info("cant subscribe to rabbitmq, channel closed. attempting reconnection") if err := r.connect(); err != nil { - slog.Error("error reconnecting to channel during subscribe", "err", err.Error()) + slog.Info("error reconnecting to channel during subscribe", "err", err.Error()) return err } @@ -309,10 +309,10 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, return nil case err := <-r.connErrCh: - slog.Error("rabbitmq notify close connection", "err", err.Error()) + slog.Info("rabbitmq notify close connection", "err", err.Error()) return queue.ErrClosed case err := <-r.chErrCh: - slog.Error("rabbitmq notify close channel", "err", err.Error()) + slog.Info("rabbitmq notify close channel", "err", err.Error()) return queue.ErrClosed case d := <-msgs: lastDelivery = time.Now() From 1e52ad18bd314adbfcc9154338bd47845e29321e Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sun, 3 Sep 2023 13:19:23 -0700 Subject: [PATCH 70/82] log... --- packages/relayer/queue/rabbitmq/queue.go | 31 +++++++++++++----------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index a9a20e55055..987a2cc7cb6 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -136,7 +136,7 @@ func (r *RabbitMQ) Publish(ctx context.Context, msg []byte) error { }) if err != nil { if err == amqp.ErrClosed { - slog.Info("amqp channel closed", "err", err.Error()) + slog.Error("amqp channel closed", "err", err.Error()) err := r.connect() if err != nil { @@ -158,21 +158,24 @@ func (r *RabbitMQ) Ack(ctx context.Context, msg queue.Message) error { slog.Info("acknowledging rabbitmq message", "msgId", rmqMsg.MessageId) err := rmqMsg.Ack(false) + + slog.Info("attempted acknowledge rabbitmq message", "err", err.Error()) + if err != nil { if err == amqp.ErrClosed { - slog.Info("amqp channel closed", "err", err.Error()) + slog.Error("amqp channel closed", "err", err.Error()) r.Close(ctx) err := r.connect() if err != nil { - slog.Info("error reconnecting to rabbitmq", "err", err.Error()) + slog.Error("error reconnecting to rabbitmq", "err", err.Error()) return err } return err } else { - slog.Info("error acknowledging rabbitmq message", "err", err.Error()) + slog.Error("error acknowledging rabbitmq message", "err", err.Error()) return err } } @@ -190,19 +193,19 @@ func (r *RabbitMQ) Nack(ctx context.Context, msg queue.Message) error { err := rmqMsg.Nack(false, false) if err != nil { if err == amqp.ErrClosed { - slog.Info("amqp channel closed", "err", err.Error()) + slog.Error("amqp channel closed", "err", err.Error()) r.Close(ctx) err := r.connect() if err != nil { - slog.Info("error reconnecting to rabbitmq", "err", err.Error()) + slog.Error("error reconnecting to rabbitmq", "err", err.Error()) return err } return err } else { - slog.Info("error negatively acknowledging rabbitmq message", "err", err.Error()) + slog.Error("error negatively acknowledging rabbitmq message", "err", err.Error()) return err } } @@ -229,17 +232,17 @@ func (r *RabbitMQ) Notify(ctx context.Context, wg *sync.WaitGroup) error { return nil case err := <-r.connErrCh: - slog.Info("rabbitmq notify close connection", "err", err.Error()) + slog.Error("rabbitmq notify close connection", "err", err.Error()) return queue.ErrClosed case err := <-r.chErrCh: - slog.Info("rabbitmq notify close channel", "err", err.Error()) + slog.Error("rabbitmq notify close channel", "err", err.Error()) return queue.ErrClosed case returnMsg := <-r.notifyReturnCh: - slog.Info("rabbitmq notify return", "id", returnMsg.MessageId, "err", returnMsg.ReplyText) + slog.Error("rabbitmq notify return", "id", returnMsg.MessageId, "err", returnMsg.ReplyText) slog.Info("rabbitmq attempting republish of returned msg", "id", returnMsg.MessageId) if err := r.Publish(ctx, returnMsg.Body); err != nil { - slog.Info("error publishing msg", "err", err.Error()) + slog.Error("error publishing msg", "err", err.Error()) } } } @@ -274,7 +277,7 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, slog.Info("cant subscribe to rabbitmq, channel closed. attempting reconnection") if err := r.connect(); err != nil { - slog.Info("error reconnecting to channel during subscribe", "err", err.Error()) + slog.Error("error reconnecting to channel during subscribe", "err", err.Error()) return err } @@ -309,10 +312,10 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, return nil case err := <-r.connErrCh: - slog.Info("rabbitmq notify close connection", "err", err.Error()) + slog.Error("rabbitmq notify close connection", "err", err.Error()) return queue.ErrClosed case err := <-r.chErrCh: - slog.Info("rabbitmq notify close channel", "err", err.Error()) + slog.Error("rabbitmq notify close channel", "err", err.Error()) return queue.ErrClosed case d := <-msgs: lastDelivery = time.Now() From d6834f89c4a167da6ee7c540ac617c39e5214114 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sun, 3 Sep 2023 13:25:22 -0700 Subject: [PATCH 71/82] check delivery channel --- packages/relayer/queue/rabbitmq/queue.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 987a2cc7cb6..488ff8fb235 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -317,7 +317,11 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, case err := <-r.chErrCh: slog.Error("rabbitmq notify close channel", "err", err.Error()) return queue.ErrClosed - case d := <-msgs: + case d, ok := <-msgs: + if !ok { + return queue.ErrClosed + } + lastDelivery = time.Now() if d.Body != nil { From 37c6ff9346470e8ac32e811e3b56d6e6cef996f0 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sun, 3 Sep 2023 13:29:56 -0700 Subject: [PATCH 72/82] oops --- packages/relayer/queue/rabbitmq/queue.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 488ff8fb235..2ef83b28325 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -159,7 +159,7 @@ func (r *RabbitMQ) Ack(ctx context.Context, msg queue.Message) error { err := rmqMsg.Ack(false) - slog.Info("attempted acknowledge rabbitmq message", "err", err.Error()) + slog.Info("attempted acknowledge rabbitmq message") if err != nil { if err == amqp.ErrClosed { @@ -319,6 +319,7 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, return queue.ErrClosed case d, ok := <-msgs: if !ok { + slog.Info("rabbitmq msg channel was closed") return queue.ErrClosed } From 40ab3f237f4150d9a4a96e81e0b13b14dcca8331 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sun, 3 Sep 2023 13:44:03 -0700 Subject: [PATCH 73/82] buffer the msgs chan --- packages/relayer/processor/processor.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/relayer/processor/processor.go b/packages/relayer/processor/processor.go index 2ce898d61d9..05fddc27e44 100644 --- a/packages/relayer/processor/processor.go +++ b/packages/relayer/processor/processor.go @@ -31,6 +31,10 @@ import ( "github.com/taikoxyz/taiko-mono/packages/relayer/repo" ) +var ( + chBufferSize = 1024 +) + type DB interface { DB() (*sql.DB, error) GormDB() *gorm.DB @@ -223,7 +227,7 @@ func InitFromConfig(ctx context.Context, p *Processor, cfg *Config) error { p.srcSignalServiceAddress = cfg.SrcSignalServiceAddress - p.msgCh = make(chan queue.Message) + p.msgCh = make(chan queue.Message, chBufferSize) p.wg = &sync.WaitGroup{} p.mu = &sync.Mutex{} p.rpc = srcRpcClient From 3ba7f2989b2eee8115c884ccc1db0f0533750333 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sun, 3 Sep 2023 20:29:00 -0700 Subject: [PATCH 74/82] Done close on channel/conn being closed --- packages/relayer/queue/rabbitmq/queue.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 2ef83b28325..9d2690780ac 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -252,10 +252,6 @@ func (r *RabbitMQ) Notify(ctx context.Context, wg *sync.WaitGroup) error { func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, wg *sync.WaitGroup) error { wg.Add(1) - defer func() { - r.Close(ctx) - }() - defer func() { wg.Done() }() @@ -305,17 +301,28 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, for { select { case <-r.subscriptionCtx.Done(): + defer r.Close(ctx) + slog.Info("rabbitmq subscription ctx cancelled") + return queue.ErrClosed case <-ctx.Done(): + defer r.Close(ctx) + slog.Info("rabbitmq context cancelled") return nil case err := <-r.connErrCh: + defer r.Close(ctx) + slog.Error("rabbitmq notify close connection", "err", err.Error()) + return queue.ErrClosed case err := <-r.chErrCh: + defer r.Close(ctx) + slog.Error("rabbitmq notify close channel", "err", err.Error()) + return queue.ErrClosed case d, ok := <-msgs: if !ok { @@ -358,7 +365,10 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, // we havent had a delivery for 5 message. sometimes, rabbitmq queues // can falter and the connection doesnt notify its closed. lets return an error // and backoff will retry + defer r.Close(ctx) + slog.Info("five minutes passed since delivery found, reconnecting to rabbitmq") + return queue.ErrClosed } } From cc1d75d1a2489c58c1b537bb0e1d9b454fb53369 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sun, 3 Sep 2023 21:14:34 -0700 Subject: [PATCH 75/82] Dont reconnect on ack/nacks --- packages/relayer/queue/rabbitmq/queue.go | 40 +++--------------------- 1 file changed, 4 insertions(+), 36 deletions(-) diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 9d2690780ac..26390a969f0 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -162,22 +162,8 @@ func (r *RabbitMQ) Ack(ctx context.Context, msg queue.Message) error { slog.Info("attempted acknowledge rabbitmq message") if err != nil { - if err == amqp.ErrClosed { - slog.Error("amqp channel closed", "err", err.Error()) - - r.Close(ctx) - - err := r.connect() - if err != nil { - slog.Error("error reconnecting to rabbitmq", "err", err.Error()) - return err - } - - return err - } else { - slog.Error("error acknowledging rabbitmq message", "err", err.Error()) - return err - } + slog.Error("error acknowledging rabbitmq message", "err", err.Error()) + return err } slog.Info("acknowledged rabbitmq message", "msgId", rmqMsg.MessageId) @@ -192,22 +178,8 @@ func (r *RabbitMQ) Nack(ctx context.Context, msg queue.Message) error { err := rmqMsg.Nack(false, false) if err != nil { - if err == amqp.ErrClosed { - slog.Error("amqp channel closed", "err", err.Error()) - - r.Close(ctx) - - err := r.connect() - if err != nil { - slog.Error("error reconnecting to rabbitmq", "err", err.Error()) - return err - } - - return err - } else { - slog.Error("error negatively acknowledging rabbitmq message", "err", err.Error()) - return err - } + slog.Error("error negatively acknowledging rabbitmq message", "err", err.Error()) + return err } slog.Info("negatively acknowledged rabbitmq message", "msgId", rmqMsg.MessageId) @@ -313,14 +285,10 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, return nil case err := <-r.connErrCh: - defer r.Close(ctx) - slog.Error("rabbitmq notify close connection", "err", err.Error()) return queue.ErrClosed case err := <-r.chErrCh: - defer r.Close(ctx) - slog.Error("rabbitmq notify close channel", "err", err.Error()) return queue.ErrClosed From 03ab07c6e2eaf78344d25e2019bcd817dc737b19 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sun, 3 Sep 2023 22:01:46 -0700 Subject: [PATCH 76/82] Try this... --- packages/relayer/processor/process_message.go | 4 -- packages/relayer/processor/processor.go | 31 ++++++------ packages/relayer/queue/rabbitmq/queue.go | 48 ++++--------------- 3 files changed, 25 insertions(+), 58 deletions(-) diff --git a/packages/relayer/processor/process_message.go b/packages/relayer/processor/process_message.go index 2bd333a02ef..5332f789700 100644 --- a/packages/relayer/processor/process_message.go +++ b/packages/relayer/processor/process_message.go @@ -196,10 +196,6 @@ func (p *Processor) processMessage( return errors.Wrap(err, fmt.Sprintf("p.eventRepo.UpdateStatus, id: %v", msgBody.ID)) } - if err := p.queue.Ack(ctx, msg); err != nil { - return errors.Wrap(err, "p.queue.Ack") - } - return nil } diff --git a/packages/relayer/processor/processor.go b/packages/relayer/processor/processor.go index 05fddc27e44..07c1d2f61da 100644 --- a/packages/relayer/processor/processor.go +++ b/packages/relayer/processor/processor.go @@ -31,10 +31,6 @@ import ( "github.com/taikoxyz/taiko-mono/packages/relayer/repo" ) -var ( - chBufferSize = 1024 -) - type DB interface { DB() (*sql.DB, error) GormDB() *gorm.DB @@ -227,7 +223,7 @@ func InitFromConfig(ctx context.Context, p *Processor, cfg *Config) error { p.srcSignalServiceAddress = cfg.SrcSignalServiceAddress - p.msgCh = make(chan queue.Message, chBufferSize) + p.msgCh = make(chan queue.Message) p.wg = &sync.WaitGroup{} p.mu = &sync.Mutex{} p.rpc = srcRpcClient @@ -291,20 +287,23 @@ func (p *Processor) eventLoop(ctx context.Context) { case <-ctx.Done(): return case msg := <-p.msgCh: - if err := p.processMessage(ctx, msg); err != nil { - // only log unexpected errors - if !errors.Is(err, errUnprocessable) { - slog.Error("err processing message", "err", err.Error()) - // nack all errors even errUnprocessable - if err := p.queue.Nack(ctx, msg); err != nil { - slog.Error("Err nacking message", "err", err.Error()) - } - } else { - // if errUnprocessable, we can Ack it to remove it from - // beign re-added, message should never become processable. + err := p.processMessage(ctx, msg) + + if err != nil { + slog.Error("err processing message", "err", err.Error()) + + if errors.Is(err, errUnprocessable) { if err := p.queue.Ack(ctx, msg); err != nil { slog.Error("Err acking message", "err", err.Error()) } + } else { + if err := p.queue.Nack(ctx, msg); err != nil { + slog.Error("Err nacking message", "err", err.Error()) + } + } + } else { + if err := p.queue.Ack(ctx, msg); err != nil { + slog.Error("Err acking message", "err", err.Error()) } } } diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index 26390a969f0..d4963ced787 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -162,7 +162,10 @@ func (r *RabbitMQ) Ack(ctx context.Context, msg queue.Message) error { slog.Info("attempted acknowledge rabbitmq message") if err != nil { + r.Close(ctx) + slog.Error("error acknowledging rabbitmq message", "err", err.Error()) + return err } @@ -178,7 +181,10 @@ func (r *RabbitMQ) Nack(ctx context.Context, msg queue.Message) error { err := rmqMsg.Nack(false, false) if err != nil { + r.Close(ctx) + slog.Error("error negatively acknowledging rabbitmq message", "err", err.Error()) + return err } @@ -266,10 +272,6 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, } } - t := time.NewTicker(5 * time.Second) - - var lastDelivery time.Time = time.Now() - for { select { case <-r.subscriptionCtx.Done(): @@ -298,45 +300,15 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, return queue.ErrClosed } - lastDelivery = time.Now() - if d.Body != nil { slog.Info("rabbitmq message found", "msgId", d.MessageId) - { - msgChan <- queue.Message{ - Body: d.Body, - Internal: d, - } + + msgChan <- queue.Message{ + Body: d.Body, + Internal: d, } } else { slog.Info("nil body message, queue is closed") - return queue.ErrClosed - } - case <-t.C: - slog.Info("rabbitmq queue subscribe ticker") - // inspect queue, check messages every tick. - q, err := r.ch.QueueDeclarePassive( - r.queue.Name, - true, - false, - false, - false, - nil, - ) - if err != nil { - return err - } - - slog.Info("rabbitmq queue info", "name", q.Name, "msgs", q.Messages) - - if time.Since(lastDelivery) > (5 * time.Minute) { - // we havent had a delivery for 5 message. sometimes, rabbitmq queues - // can falter and the connection doesnt notify its closed. lets return an error - // and backoff will retry - defer r.Close(ctx) - - slog.Info("five minutes passed since delivery found, reconnecting to rabbitmq") - return queue.ErrClosed } } From 7b1a1a1fa1d88b4e94d0b090ce1bb413daaa7648 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Sun, 3 Sep 2023 22:03:44 -0700 Subject: [PATCH 77/82] rm buffer, add some logs --- packages/relayer/processor/processor.go | 2 +- packages/relayer/queue/rabbitmq/queue.go | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/relayer/processor/processor.go b/packages/relayer/processor/processor.go index 07c1d2f61da..53d4dcc4b5d 100644 --- a/packages/relayer/processor/processor.go +++ b/packages/relayer/processor/processor.go @@ -257,7 +257,7 @@ func (p *Processor) Start() error { if err := backoff.Retry(func() error { slog.Info("attempting backoff queue subscription") if err := p.queue.Subscribe(ctx, p.msgCh, p.wg); err != nil { - slog.Info("processor queue subscription error", "err", err.Error()) + slog.Error("processor queue subscription error", "err", err.Error()) return err } diff --git a/packages/relayer/queue/rabbitmq/queue.go b/packages/relayer/queue/rabbitmq/queue.go index d4963ced787..36a01ce92da 100644 --- a/packages/relayer/queue/rabbitmq/queue.go +++ b/packages/relayer/queue/rabbitmq/queue.go @@ -162,10 +162,7 @@ func (r *RabbitMQ) Ack(ctx context.Context, msg queue.Message) error { slog.Info("attempted acknowledge rabbitmq message") if err != nil { - r.Close(ctx) - slog.Error("error acknowledging rabbitmq message", "err", err.Error()) - return err } @@ -181,10 +178,7 @@ func (r *RabbitMQ) Nack(ctx context.Context, msg queue.Message) error { err := rmqMsg.Nack(false, false) if err != nil { - r.Close(ctx) - slog.Error("error negatively acknowledging rabbitmq message", "err", err.Error()) - return err } @@ -296,7 +290,7 @@ func (r *RabbitMQ) Subscribe(ctx context.Context, msgChan chan<- queue.Message, return queue.ErrClosed case d, ok := <-msgs: if !ok { - slog.Info("rabbitmq msg channel was closed") + slog.Error("rabbitmq msg channel was closed") return queue.ErrClosed } From b450d05749342b8d07b7ea0f9041852f48c72034 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Tue, 5 Sep 2023 08:48:26 -0700 Subject: [PATCH 78/82] add timeouts --- packages/relayer/cmd/flags/common.go | 8 +++++++ packages/relayer/indexer/config.go | 2 ++ packages/relayer/indexer/handle_event.go | 9 +++++++- packages/relayer/indexer/indexer.go | 4 ++++ packages/relayer/processor/config.go | 12 ++++++----- packages/relayer/processor/process_message.go | 21 +++++++++++++++---- packages/relayer/processor/processor.go | 2 ++ 7 files changed, 48 insertions(+), 10 deletions(-) diff --git a/packages/relayer/cmd/flags/common.go b/packages/relayer/cmd/flags/common.go index 23147f95760..b98443d4702 100644 --- a/packages/relayer/cmd/flags/common.go +++ b/packages/relayer/cmd/flags/common.go @@ -119,6 +119,13 @@ var ( Value: 6061, EnvVars: []string{"METRICS_HTTP_PORT"}, } + ETHClientTimeout = &cli.Uint64Flag{ + Name: "ethClientTimeout", + Usage: "Timeout for eth client and contract binding calls", + Category: commonCategory, + Value: 10, + EnvVars: []string{"ETH_CLIENT_TIMEOUT"}, + } ) // optional @@ -150,6 +157,7 @@ var CommonFlags = []cli.Flag{ DatabaseConnMaxLifetime, DatabaseMaxOpenConns, MetricsHTTPPort, + ETHClientTimeout, } // MergeFlags merges the given flag slices. diff --git a/packages/relayer/indexer/config.go b/packages/relayer/indexer/config.go index aa564a3ec35..95add0a934f 100644 --- a/packages/relayer/indexer/config.go +++ b/packages/relayer/indexer/config.go @@ -35,6 +35,7 @@ type Config struct { // rpc configs SrcRPCUrl string DestRPCUrl string + ETHClientTimeout uint64 CORSOrigins []string BlockBatchSize uint64 NumGoroutines uint64 @@ -72,6 +73,7 @@ func NewConfigFromCliContext(c *cli.Context) (*Config, error) { WatchMode: WatchMode(c.String(flags.WatchMode.Name)), SyncMode: SyncMode(c.String(flags.SyncMode.Name)), HTTPPort: c.Uint64(flags.HTTPPort.Name), + ETHClientTimeout: c.Uint64(flags.ETHClientTimeout.Name), OpenDBFunc: func() (DB, error) { return db.OpenDBConnection(db.DBConnectionOpts{ Name: c.String(flags.DatabaseUsername.Name), diff --git a/packages/relayer/indexer/handle_event.go b/packages/relayer/indexer/handle_event.go index bfff8dcf47b..d5f580ac479 100644 --- a/packages/relayer/indexer/handle_event.go +++ b/packages/relayer/indexer/handle_event.go @@ -7,6 +7,7 @@ import ( "log/slog" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" "github.com/taikoxyz/taiko-mono/packages/relayer" @@ -95,7 +96,13 @@ func (i *Indexer) eventStatusFromMsgHash( ) (relayer.EventStatus, error) { var eventStatus relayer.EventStatus - messageStatus, err := i.destBridge.GetMessageStatus(nil, signal) + ctx, cancel := context.WithTimeout(ctx, i.ethClientTimeout) + + defer cancel() + + messageStatus, err := i.destBridge.GetMessageStatus(&bind.CallOpts{ + Context: ctx, + }, signal) if err != nil { return 0, errors.Wrap(err, "svc.destBridge.GetMessageStatus") } diff --git a/packages/relayer/indexer/indexer.go b/packages/relayer/indexer/indexer.go index 025050e3361..eb789a91713 100644 --- a/packages/relayer/indexer/indexer.go +++ b/packages/relayer/indexer/indexer.go @@ -92,6 +92,8 @@ type Indexer struct { srv *http.Server httpPort uint64 + ethClientTimeout time.Duration + wg *sync.WaitGroup ctx context.Context @@ -202,6 +204,8 @@ func InitFromConfig(ctx context.Context, i *Indexer, cfg *Config) (err error) { i.wg = &sync.WaitGroup{} + i.ethClientTimeout = time.Duration(cfg.ETHClientTimeout) * time.Second + return nil } diff --git a/packages/relayer/processor/config.go b/packages/relayer/processor/config.go index 3026bc21102..a7edc96f152 100644 --- a/packages/relayer/processor/config.go +++ b/packages/relayer/processor/config.go @@ -53,11 +53,12 @@ type Config struct { QueueHost string QueuePort uint64 // rpc configs - SrcRPCUrl string - DestRPCUrl string - CORSOrigins []string - OpenQueueFunc func() (queue.Queue, error) - OpenDBFunc func() (DB, error) + SrcRPCUrl string + DestRPCUrl string + ETHClientTimeout uint64 + CORSOrigins []string + OpenQueueFunc func() (queue.Queue, error) + OpenDBFunc func() (DB, error) } // NewConfigFromCliContext creates a new config instance from command line flags. @@ -97,6 +98,7 @@ func NewConfigFromCliContext(c *cli.Context) (*Config, error) { ProfitableOnly: c.Bool(flags.ProfitableOnly.Name), BackoffRetryInterval: c.Uint64(flags.BackOffRetryInterval.Name), BackOffMaxRetrys: c.Uint64(flags.BackOffMaxRetrys.Name), + ETHClientTimeout: c.Uint64(flags.ETHClientTimeout.Name), OpenDBFunc: func() (DB, error) { return db.OpenDBConnection(db.DBConnectionOpts{ Name: c.String(flags.DatabaseUsername.Name), diff --git a/packages/relayer/processor/process_message.go b/packages/relayer/processor/process_message.go index 5332f789700..de96df964d5 100644 --- a/packages/relayer/processor/process_message.go +++ b/packages/relayer/processor/process_message.go @@ -33,7 +33,13 @@ func (p *Processor) eventStatusFromMsgHash( ) (relayer.EventStatus, error) { var eventStatus relayer.EventStatus - messageStatus, err := p.destBridge.GetMessageStatus(nil, signal) + ctx, cancel := context.WithTimeout(ctx, 5*time.Second) + + defer cancel() + + messageStatus, err := p.destBridge.GetMessageStatus(&bind.CallOpts{ + Context: ctx, + }, signal) if err != nil { return 0, errors.Wrap(err, "svc.destBridge.GetMessageStatus") } @@ -303,19 +309,26 @@ func (p *Processor) needsContractDeployment( chainID := canonicalToken.ChainID() addr := canonicalToken.Address() + ctx, cancel := context.WithTimeout(ctx, p.ethClientTimeout) + defer cancel() + + opts := &bind.CallOpts{ + Context: ctx, + } + if eventType == relayer.EventTypeSendERC20 && event.Message.DestChainId.Cmp(chainID) != 0 { // determine whether the canonical token is bridged or not on this chain - bridgedAddress, err = p.destERC20Vault.CanonicalToBridged(nil, chainID, addr) + bridgedAddress, err = p.destERC20Vault.CanonicalToBridged(opts, chainID, addr) } if eventType == relayer.EventTypeSendERC721 && event.Message.DestChainId.Cmp(chainID) != 0 { // determine whether the canonical token is bridged or not on this chain - bridgedAddress, err = p.destERC721Vault.CanonicalToBridged(nil, chainID, addr) + bridgedAddress, err = p.destERC721Vault.CanonicalToBridged(opts, chainID, addr) } if eventType == relayer.EventTypeSendERC1155 && event.Message.DestChainId.Cmp(chainID) != 0 { // determine whether the canonical token is bridged or not on this chain - bridgedAddress, err = p.destERC1155Vault.CanonicalToBridged(nil, chainID, addr) + bridgedAddress, err = p.destERC1155Vault.CanonicalToBridged(opts, chainID, addr) } if err != nil { diff --git a/packages/relayer/processor/processor.go b/packages/relayer/processor/processor.go index 53d4dcc4b5d..f9e2c2d2646 100644 --- a/packages/relayer/processor/processor.go +++ b/packages/relayer/processor/processor.go @@ -81,6 +81,7 @@ type Processor struct { backOffRetryInterval time.Duration backOffMaxRetries uint64 + ethClientTimeout time.Duration msgCh chan queue.Message @@ -230,6 +231,7 @@ func InitFromConfig(ctx context.Context, p *Processor, cfg *Config) error { p.backOffRetryInterval = time.Duration(cfg.BackoffRetryInterval) * time.Second p.backOffMaxRetries = cfg.BackOffMaxRetrys + p.ethClientTimeout = time.Duration(cfg.ETHClientTimeout) * time.Second return nil } From 3ec57ae47b5c897a28629380a30624c9167653ae Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Tue, 5 Sep 2023 08:49:01 -0700 Subject: [PATCH 79/82] timeouts in tests --- packages/relayer/indexer/indexer_test.go | 3 +++ packages/relayer/processor/processor_test.go | 1 + 2 files changed, 4 insertions(+) diff --git a/packages/relayer/indexer/indexer_test.go b/packages/relayer/indexer/indexer_test.go index 870aa8dbf51..14778603e00 100644 --- a/packages/relayer/indexer/indexer_test.go +++ b/packages/relayer/indexer/indexer_test.go @@ -3,6 +3,7 @@ package indexer import ( "context" "sync" + "time" "github.com/ethereum/go-ethereum/ethclient" "github.com/labstack/echo/v4" @@ -46,5 +47,7 @@ func newTestService(syncMode SyncMode, watchMode WatchMode) (*Indexer, relayer.B srcChainId: mock.MockChainID, destChainId: mock.MockChainID, + + ethClientTimeout: 10 * time.Second, }, b } diff --git a/packages/relayer/processor/processor_test.go b/packages/relayer/processor/processor_test.go index d9155aaa5ab..8c11790646c 100644 --- a/packages/relayer/processor/processor_test.go +++ b/packages/relayer/processor/processor_test.go @@ -36,5 +36,6 @@ func newTestProcessor(profitableOnly bool) *Processor { queue: &mock.Queue{}, backOffRetryInterval: 1 * time.Second, backOffMaxRetries: 1, + ethClientTimeout: 10 * time.Second, } } From c05e13b404786e46a469bc7ed93c814be98dd1bb Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Tue, 5 Sep 2023 08:53:08 -0700 Subject: [PATCH 80/82] dynamic env file via env var --- packages/relayer/cmd/main.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/relayer/cmd/main.go b/packages/relayer/cmd/main.go index 81e7f3c20c2..adb674a3f72 100644 --- a/packages/relayer/cmd/main.go +++ b/packages/relayer/cmd/main.go @@ -19,7 +19,13 @@ func main() { log.SetOutput(os.Stdout) // attempt to load a .env file to overwrite CLI flags, but allow it to not // exist. - _ = godotenv.Load(".env") + + envFile := os.Getenv("RELAYER_ENV_FILE") + if envFile == "" { + envFile = ".env" + } + + _ = godotenv.Load(envFile) app.Name = "Taiko Relayer" app.Usage = "The taiko relayer softwares command line interface" From ab8efbbdafa4c1bd7895b8872457732017b26118 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Tue, 5 Sep 2023 08:54:10 -0700 Subject: [PATCH 81/82] use ethclient timeout --- packages/relayer/processor/process_message.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/relayer/processor/process_message.go b/packages/relayer/processor/process_message.go index de96df964d5..48a322cd6c6 100644 --- a/packages/relayer/processor/process_message.go +++ b/packages/relayer/processor/process_message.go @@ -33,7 +33,7 @@ func (p *Processor) eventStatusFromMsgHash( ) (relayer.EventStatus, error) { var eventStatus relayer.EventStatus - ctx, cancel := context.WithTimeout(ctx, 5*time.Second) + ctx, cancel := context.WithTimeout(ctx, p.ethClientTimeout) defer cancel() From 67a07bc1b02a337f1042d3a59075fb93755c2664 Mon Sep 17 00:00:00 2001 From: Jeffery Walsh Date: Tue, 5 Sep 2023 09:01:31 -0700 Subject: [PATCH 82/82] readme --- packages/relayer/README.md | 82 +++++++++++++++----------------------- 1 file changed, 32 insertions(+), 50 deletions(-) diff --git a/packages/relayer/README.md b/packages/relayer/README.md index 4fe88c69486..8481e4e2574 100644 --- a/packages/relayer/README.md +++ b/packages/relayer/README.md @@ -5,68 +5,50 @@ A relayer for the Bridge to watch and sync event between Layer 1 and Taiko Layer 2. -## Running the app +## Build the source -run `cp .default.env .env`, and add your own private key as `RELAYER_ECDSA_KEY` in `.env`. You need to be running a MySQL instance, and replace all the `MYSQL_` env vars with yours. +Building the `taiko-client` binary requires a Go compiler. Once installed, run: -Run `go run cmd/main.go --help` to see a list of possible configuration flags, or `go run cmd/main.go` to run with defaults, which will process messages from L1 to L2, and from L2 to L1, and start indexing blocks from 0. - -## Project structure - -### bin - -Executable binary, built it with `go build cmd/main.go {options}`. - -### cli - -Command line interface execution folder, intended to instantiate all app dependencies and start them. - -### cmd - -Entry point to the application. There are possible flag configurations for the app. Run `go run cmd/main.go -h` to see possible options, or `go run cmd/main.go` to run it with sensible defaults. - -### contracts - -Autogenerated smart contract bindings with `abigen`. Use `./abigen.sh` to generate the bindings. - -### encoding - -Encoding helpers for packing abi structs or converting types. - -### indexer - -A block indexing service that watches for events happening in batches. - -### message - -A message processor that can act on a specific event and attempt to process them via `bridge.processMessage` call. - -### migrations - -Contains database migrations. They are created and ran with the `goose` binary. - -Install goose: `go install github.com/pressly/goose/v3/cmd/goose@latest` +```sh +make build +``` -Then: -`cd migrations` +## Configuration -`GOOSE_DRIVER=mysql GOOSE_DBSTRING="username:password@/dbname" goose up` +To run an indexer: +run `cp .l1processor.example.env .l1processor.env`, and replace the variables as needed in `.l1processor.env`. You need to be running a MySQL instance and a RabbitMQ instance, and replace all the `MYSQL_` env vars with yours. -To run down migrations you can use: +RabbitMQ can be installed with `./scripts/install-rabbitmq.sh`. -`GOOSE_DRIVER=mysql GOOSE_DBSTRING="username:password@/dbname" goose down` +## Usage -### mock +Review all available sub-commands: -Mocked structs for testing. +```sh +bin/relayer --help +``` -### proof +Review each sub-command's command line flags: -Proof generator, uses `eth_getProof` call under the hood. +```sh +bin/relayer --help +``` -### repo +## Project structure -Database repositories implementing domain Repository interfaces with a concrete MySQL implementation. +| Path | Description | +| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | +| `bindings/` | [Go contract bindings](https://geth.ethereum.org/docs/dapp/native-bindings) for Taiko smart contracts, and few related utility functions | +| `cmd/` | Main executable for this project | +| `db/` | Database interfaces and connection methods. | +| `encoding/` | Encoding helper utility functions for interacting with smart contract functions | +| `indexer/` | Indexer sub-command | +| `metrics/` | Metrics related | +| `migrations/` | Database migrations | +| `mock/` | Mocks for testing | +| `proof/` | Merkle proof generation service | +| `queue/` | Queue related interfaces and types, with implementations in subfolders | +| `repo/` | Database repository interaction layer | ## API Doc