From bf3be056b4e65c637b93f03f627beb9c8bdde8b0 Mon Sep 17 00:00:00 2001 From: agodnic Date: Thu, 15 Jun 2023 21:42:46 -0300 Subject: [PATCH] Add support for Sui in the `tx-tracker` service (#416) ### Description This pull request modifies the `tx-tracker` service to support the Sui blockchain. In particular, this will make the Sui sender addresses available for the Wormhole Scan UI. --- .../tx-tracker-backfiller-job.yaml | 4 ++ deploy/tx-tracker/tx-tracker-service.yaml | 4 ++ tx-tracker/chains/sui.go | 59 +++++++++++++++++++ tx-tracker/chains/tx.go | 7 +++ tx-tracker/config/structs.go | 2 + 5 files changed, 76 insertions(+) create mode 100644 tx-tracker/chains/sui.go diff --git a/deploy/tx-tracker-backfiller/tx-tracker-backfiller-job.yaml b/deploy/tx-tracker-backfiller/tx-tracker-backfiller-job.yaml index e13574ee..9a628d4c 100644 --- a/deploy/tx-tracker-backfiller/tx-tracker-backfiller-job.yaml +++ b/deploy/tx-tracker-backfiller/tx-tracker-backfiller-job.yaml @@ -67,6 +67,10 @@ spec: value: {{ .SOLANA_BASE_URL }} - name: SOLANA_REQUESTS_PER_MINUTE value: "{{ .SOLANA_REQUESTS_PER_MINUTE }}" + - name: SUI_BASE_URL + value: {{ .SUI_BASE_URL }} + - name: SUI_REQUESTS_PER_MINUTE + value: "{{ .SUI_REQUESTS_PER_MINUTE }}" - name: NUM_WORKERS value: "100" - name: BULK_SIZE diff --git a/deploy/tx-tracker/tx-tracker-service.yaml b/deploy/tx-tracker/tx-tracker-service.yaml index 8c36d932..6b65b4fe 100644 --- a/deploy/tx-tracker/tx-tracker-service.yaml +++ b/deploy/tx-tracker/tx-tracker-service.yaml @@ -93,6 +93,10 @@ spec: value: {{ .SOLANA_BASE_URL }} - name: SOLANA_REQUESTS_PER_MINUTE value: "{{ .SOLANA_REQUESTS_PER_MINUTE }}" + - name: SUI_BASE_URL + value: {{ .SUI_BASE_URL }} + - name: SUI_REQUESTS_PER_MINUTE + value: "{{ .SUI_REQUESTS_PER_MINUTE }}" resources: limits: memory: {{ .RESOURCES_LIMITS_MEMORY }} diff --git a/tx-tracker/chains/sui.go b/tx-tracker/chains/sui.go new file mode 100644 index 00000000..896d83c9 --- /dev/null +++ b/tx-tracker/chains/sui.go @@ -0,0 +1,59 @@ +package chains + +import ( + "context" + "fmt" + "time" + + "github.com/ethereum/go-ethereum/rpc" + "github.com/wormhole-foundation/wormhole-explorer/txtracker/config" +) + +type suiGetTransactionBlockResponse struct { + Digest string `json:"digest"` + TimestampMs int64 `json:"timestampMs,string"` + Transaction struct { + Data struct { + Sender string `json:"sender"` + } `json:"data"` + } `json:"transaction"` +} + +type suiGetTransactionBlockOpts struct { + ShowInput bool `json:"showInput"` + ShowRawInput bool `json:"showRawInput"` + ShowEffects bool `json:"showEffects"` + ShowEvents bool `json:"showEvents"` + ShowObjectChanges bool `json:"showObjectChanges"` + ShowBalanceChanges bool `json:"showBalanceChanges"` +} + +func fetchSuiTx( + ctx context.Context, + cfg *config.RpcProviderSettings, + txHash string, +) (*TxDetail, error) { + + // Initialize RPC client + client, err := rpc.DialContext(ctx, cfg.SuiBaseUrl) + if err != nil { + return nil, fmt.Errorf("failed to initialize RPC client: %w", err) + } + defer client.Close() + + // Query transaction data + var reply suiGetTransactionBlockResponse + opts := suiGetTransactionBlockOpts{ShowInput: true} + err = client.CallContext(ctx, &reply, "sui_getTransactionBlock", txHash, opts) + if err != nil { + return nil, fmt.Errorf("failed to get tx by hash: %w", err) + } + + // Populate the response struct and return + txDetail := TxDetail{ + NativeTxHash: reply.Digest, + From: reply.Transaction.Data.Sender, + Timestamp: time.UnixMilli(reply.TimestampMs), + } + return &txDetail, nil +} diff --git a/tx-tracker/chains/tx.go b/tx-tracker/chains/tx.go index b685eb9c..d1bfc30a 100644 --- a/tx-tracker/chains/tx.go +++ b/tx-tracker/chains/tx.go @@ -39,6 +39,7 @@ var tickers = struct { optimism *time.Ticker polygon *time.Ticker solana *time.Ticker + sui *time.Ticker }{} func Initialize(cfg *config.RpcProviderSettings) { @@ -52,6 +53,9 @@ func Initialize(cfg *config.RpcProviderSettings) { return time.Duration(roundedUp) } + // this adapter sends 1 request per txHash + tickers.sui = time.NewTicker(f(cfg.SuiRequestsPerMinute)) + // these adapters send 2 requests per txHash tickers.arbitrum = time.NewTicker(f(cfg.ArbitrumRequestsPerMinute / 2)) tickers.avalanche = time.NewTicker(f(cfg.AvalancheRequestsPerMinute / 2)) @@ -119,6 +123,9 @@ func FetchTx( return fetchEthTx(ctx, txHash, cfg.AvalancheBaseUrl) } rateLimiter = *tickers.avalanche + case vaa.ChainIDSui: + fetchFunc = fetchSuiTx + rateLimiter = *tickers.sui default: return nil, ErrChainNotSupported } diff --git a/tx-tracker/config/structs.go b/tx-tracker/config/structs.go index 98b04330..d4f1aaba 100644 --- a/tx-tracker/config/structs.go +++ b/tx-tracker/config/structs.go @@ -77,6 +77,8 @@ type RpcProviderSettings struct { PolygonRequestsPerMinute uint16 `split_words:"true" required:"true"` SolanaBaseUrl string `split_words:"true" required:"true"` SolanaRequestsPerMinute uint16 `split_words:"true" required:"true"` + SuiBaseUrl string `split_words:"true" required:"true"` + SuiRequestsPerMinute uint16 `split_words:"true" required:"true"` } func LoadFromEnv[T any]() (*T, error) {