From 3f303fd15a3ba86679137a8af72c92511885f250 Mon Sep 17 00:00:00 2001 From: CyrusVorwald <90732384+CyrusVorwald@users.noreply.github.com> Date: Wed, 6 Nov 2024 19:54:34 -0500 Subject: [PATCH 1/9] feat: stacks integration --- .../stacks/abi/centralized-connection.abi | 457 +++++++++++ .../chains/stacks/abi/xcall-proxy-abi.json | 733 ++++++++++++++++++ relayer/chains/stacks/client.go | 621 +++++++++++++++ relayer/chains/stacks/client_test.go | 205 +++++ relayer/chains/stacks/event_parse.go | 142 ++++ relayer/chains/stacks/event_parse_test.go | 311 ++++++++ relayer/chains/stacks/events.go | 41 + relayer/chains/stacks/interfaces/client.go | 32 + relayer/chains/stacks/keys.go | 168 ++++ relayer/chains/stacks/keys_test.go | 138 ++++ relayer/chains/stacks/listener.go | 93 +++ relayer/chains/stacks/listener_test.go | 336 ++++++++ relayer/chains/stacks/mocks/client_mock.go | 101 +++ relayer/chains/stacks/mocks/kms_mock.go | 30 + relayer/chains/stacks/provider.go | 258 ++++++ relayer/chains/stacks/query.go | 166 ++++ relayer/chains/stacks/route.go | 123 +++ relayer/chains/stacks/stacks_test.go | 82 ++ test/chains/stacks/remotenet.go | 650 ++++++++++++++++ 19 files changed, 4687 insertions(+) create mode 100644 relayer/chains/stacks/abi/centralized-connection.abi create mode 100644 relayer/chains/stacks/abi/xcall-proxy-abi.json create mode 100644 relayer/chains/stacks/client.go create mode 100644 relayer/chains/stacks/client_test.go create mode 100644 relayer/chains/stacks/event_parse.go create mode 100644 relayer/chains/stacks/event_parse_test.go create mode 100644 relayer/chains/stacks/events.go create mode 100644 relayer/chains/stacks/interfaces/client.go create mode 100644 relayer/chains/stacks/keys.go create mode 100644 relayer/chains/stacks/keys_test.go create mode 100644 relayer/chains/stacks/listener.go create mode 100644 relayer/chains/stacks/listener_test.go create mode 100644 relayer/chains/stacks/mocks/client_mock.go create mode 100644 relayer/chains/stacks/mocks/kms_mock.go create mode 100644 relayer/chains/stacks/provider.go create mode 100644 relayer/chains/stacks/query.go create mode 100644 relayer/chains/stacks/route.go create mode 100644 relayer/chains/stacks/stacks_test.go create mode 100644 test/chains/stacks/remotenet.go diff --git a/relayer/chains/stacks/abi/centralized-connection.abi b/relayer/chains/stacks/abi/centralized-connection.abi new file mode 100644 index 00000000..b97898ae --- /dev/null +++ b/relayer/chains/stacks/abi/centralized-connection.abi @@ -0,0 +1,457 @@ +{ + "maps": [ + { + "key": { + "tuple": [ + { + "name": "network-id", + "type": { + "string-ascii": { + "length": 128 + } + } + } + ] + }, + "name": "message-fees", + "value": "uint128" + }, + { + "key": { + "tuple": [ + { + "name": "conn-sn", + "type": "int128" + }, + { + "name": "network-id", + "type": { + "string-ascii": { + "length": 128 + } + } + } + ] + }, + "name": "receipts", + "value": "bool" + }, + { + "key": { + "tuple": [ + { + "name": "network-id", + "type": { + "string-ascii": { + "length": 128 + } + } + } + ] + }, + "name": "response-fees", + "value": "uint128" + } + ], + "epoch": "Epoch30", + "functions": [ + { + "args": [ + { + "name": "to", + "type": { + "string-ascii": { + "length": 128 + } + } + }, + { + "name": "sn", + "type": "int128" + }, + { + "name": "msg", + "type": { + "buffer": { + "length": 2048 + } + } + } + ], + "name": "emit-message-event", + "access": "private", + "outputs": { + "type": { + "tuple": [ + { + "name": "event", + "type": { + "string-ascii": { + "length": 7 + } + } + }, + { + "name": "msg", + "type": { + "buffer": { + "length": 2048 + } + } + }, + { + "name": "sn", + "type": "int128" + }, + { + "name": "to", + "type": { + "string-ascii": { + "length": 128 + } + } + } + ] + } + } + }, + { + "args": [], + "name": "is-admin", + "access": "private", + "outputs": { + "type": "bool" + } + }, + { + "args": [], + "name": "is-xcall", + "access": "private", + "outputs": { + "type": "bool" + } + }, + { + "args": [], + "name": "claim-fees", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "bool", + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "xcall-contract", + "type": "principal" + }, + { + "name": "admin-address", + "type": "principal" + } + ], + "name": "initialize", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "bool", + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "src-network-id", + "type": { + "string-ascii": { + "length": 128 + } + } + }, + { + "name": "conn-sn-in", + "type": "int128" + }, + { + "name": "msg", + "type": { + "buffer": { + "length": 2048 + } + } + }, + { + "name": "implementation", + "type": "trait_reference" + } + ], + "name": "recv-message", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "bool", + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "to", + "type": { + "string-ascii": { + "length": 128 + } + } + }, + { + "name": "svc", + "type": { + "string-ascii": { + "length": 128 + } + } + }, + { + "name": "sn", + "type": "int128" + }, + { + "name": "msg", + "type": { + "buffer": { + "length": 2048 + } + } + }, + { + "name": "implementation", + "type": "trait_reference" + } + ], + "name": "send-message", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "int128", + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "new-admin", + "type": "principal" + } + ], + "name": "set-admin", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "bool", + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "network-id", + "type": { + "string-ascii": { + "length": 128 + } + } + }, + { + "name": "message-fee", + "type": "uint128" + }, + { + "name": "response-fee", + "type": "uint128" + } + ], + "name": "set-fee", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "bool", + "error": "uint128" + } + } + } + }, + { + "args": [], + "name": "get-admin", + "access": "read_only", + "outputs": { + "type": { + "response": { + "ok": "principal", + "error": "none" + } + } + } + }, + { + "args": [], + "name": "get-conn-sn", + "access": "read_only", + "outputs": { + "type": { + "response": { + "ok": "int128", + "error": "none" + } + } + } + }, + { + "args": [ + { + "name": "to", + "type": { + "string-ascii": { + "length": 128 + } + } + }, + { + "name": "response", + "type": "bool" + } + ], + "name": "get-fee", + "access": "read_only", + "outputs": { + "type": { + "response": { + "ok": "uint128", + "error": "none" + } + } + } + }, + { + "args": [ + { + "name": "src-network", + "type": { + "string-ascii": { + "length": 128 + } + } + }, + { + "name": "conn-sn-in", + "type": "int128" + } + ], + "name": "get-receipt", + "access": "read_only", + "outputs": { + "type": { + "response": { + "ok": "bool", + "error": "none" + } + } + } + }, + { + "args": [], + "name": "get-xcall", + "access": "read_only", + "outputs": { + "type": { + "response": { + "ok": { + "optional": "principal" + }, + "error": "none" + } + } + } + } + ], + "variables": [ + { + "name": "ERR_DUPLICATE_MESSAGE", + "type": { + "response": { + "ok": "none", + "error": "uint128" + } + }, + "access": "constant" + }, + { + "name": "ERR_INVALID_FEE", + "type": { + "response": { + "ok": "none", + "error": "uint128" + } + }, + "access": "constant" + }, + { + "name": "ERR_UNAUTHORIZED", + "type": { + "response": { + "ok": "none", + "error": "uint128" + } + }, + "access": "constant" + }, + { + "name": "ERR_XCALL_NOT_SET", + "type": { + "response": { + "ok": "none", + "error": "uint128" + } + }, + "access": "constant" + }, + { + "name": "admin", + "type": "principal", + "access": "variable" + }, + { + "name": "conn-sn", + "type": "int128", + "access": "variable" + }, + { + "name": "xcall", + "type": { + "optional": "principal" + }, + "access": "variable" + } + ], + "clarity_version": "Clarity2", + "fungible_tokens": [], + "non_fungible_tokens": [] + } \ No newline at end of file diff --git a/relayer/chains/stacks/abi/xcall-proxy-abi.json b/relayer/chains/stacks/abi/xcall-proxy-abi.json new file mode 100644 index 00000000..4da39712 --- /dev/null +++ b/relayer/chains/stacks/abi/xcall-proxy-abi.json @@ -0,0 +1,733 @@ +{ + "maps": [ + { + "key": { + "string-ascii": { + "length": 16 + } + }, + "name": "data-storage", + "value": { + "buffer": { + "length": 2048 + } + } + } + ], + "epoch": "Epoch30", + "functions": [ + { + "args": [ + { + "name": "req-id", + "type": "uint128" + }, + { + "name": "data", + "type": { + "buffer": { + "length": 2048 + } + } + }, + { + "name": "receiver", + "type": "trait_reference" + }, + { + "name": "common", + "type": "trait_reference" + }, + { + "name": "implementation", + "type": "trait_reference" + } + ], + "name": "execute-call", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "bool", + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "sn", + "type": "uint128" + }, + { + "name": "receiver", + "type": "trait_reference" + }, + { + "name": "common", + "type": "trait_reference" + }, + { + "name": "implementation", + "type": "trait_reference" + } + ], + "name": "execute-rollback", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "bool", + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "net", + "type": { + "string-ascii": { + "length": 128 + } + } + }, + { + "name": "rollback", + "type": "bool" + }, + { + "name": "sources", + "type": { + "optional": { + "list": { + "type": { + "string-ascii": { + "length": 128 + } + }, + "length": 10 + } + } + } + }, + { + "name": "implementation", + "type": "trait_reference" + } + ], + "name": "get-fee", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "uint128", + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "implementation", + "type": "trait_reference" + } + ], + "name": "get-network-address", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": { + "string-ascii": { + "length": 128 + } + }, + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "implementation", + "type": "trait_reference" + } + ], + "name": "get-network-id", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": { + "string-ascii": { + "length": 128 + } + }, + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "implementation", + "type": "trait_reference" + } + ], + "name": "get-protocol-fee", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "uint128", + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "sn", + "type": "uint128" + }, + { + "name": "implementation", + "type": "trait_reference" + } + ], + "name": "handle-error", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "bool", + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "source-network", + "type": { + "string-ascii": { + "length": 128 + } + } + }, + { + "name": "message", + "type": { + "buffer": { + "length": 2048 + } + } + }, + { + "name": "implementation", + "type": "trait_reference" + } + ], + "name": "handle-message", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "bool", + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "to", + "type": { + "string-ascii": { + "length": 128 + } + } + }, + { + "name": "data", + "type": { + "buffer": { + "length": 2048 + } + } + }, + { + "name": "implementation", + "type": "trait_reference" + } + ], + "name": "send-call", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "uint128", + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "to", + "type": { + "string-ascii": { + "length": 128 + } + } + }, + { + "name": "data", + "type": { + "buffer": { + "length": 2048 + } + } + }, + { + "name": "rollback", + "type": { + "optional": { + "buffer": { + "length": 1024 + } + } + } + }, + { + "name": "sources", + "type": { + "optional": { + "list": { + "type": { + "string-ascii": { + "length": 128 + } + }, + "length": 10 + } + } + } + }, + { + "name": "destinations", + "type": { + "optional": { + "list": { + "type": { + "string-ascii": { + "length": 128 + } + }, + "length": 10 + } + } + } + }, + { + "name": "implementation", + "type": "trait_reference" + } + ], + "name": "send-call-message", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "uint128", + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "new-admin", + "type": "principal" + }, + { + "name": "implementation", + "type": "trait_reference" + } + ], + "name": "set-admin", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "bool", + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "new-owner", + "type": "principal" + } + ], + "name": "set-contract-owner", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "bool", + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "key", + "type": { + "string-ascii": { + "length": 16 + } + } + }, + { + "name": "value", + "type": { + "buffer": { + "length": 2048 + } + } + } + ], + "name": "set-data", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "bool", + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "nid", + "type": { + "string-ascii": { + "length": 128 + } + } + }, + { + "name": "connection", + "type": { + "string-ascii": { + "length": 128 + } + } + }, + { + "name": "implementation", + "type": "trait_reference" + } + ], + "name": "set-default-connection", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "bool", + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "fee", + "type": "uint128" + }, + { + "name": "implementation", + "type": "trait_reference" + } + ], + "name": "set-protocol-fee", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "bool", + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "handler", + "type": "principal" + }, + { + "name": "implementation", + "type": "trait_reference" + } + ], + "name": "set-protocol-fee-handler", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "bool", + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "nid", + "type": { + "string-ascii": { + "length": 128 + } + } + }, + { + "name": "protocols", + "type": { + "list": { + "type": { + "string-ascii": { + "length": 128 + } + }, + "length": 10 + } + } + }, + { + "name": "implementation", + "type": "trait_reference" + } + ], + "name": "set-trusted-protocols", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "bool", + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "new-implementation", + "type": "trait_reference" + }, + { + "name": "new-proxy", + "type": { + "optional": "principal" + } + } + ], + "name": "upgrade", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "bool", + "error": "uint128" + } + } + } + }, + { + "args": [ + { + "name": "sn", + "type": "uint128" + }, + { + "name": "implementation", + "type": "trait_reference" + } + ], + "name": "verify-success", + "access": "public", + "outputs": { + "type": { + "response": { + "ok": "bool", + "error": "uint128" + } + } + } + }, + { + "args": [], + "name": "get-contract-owner", + "access": "read_only", + "outputs": { + "type": "principal" + } + }, + { + "args": [], + "name": "get-current-implementation", + "access": "read_only", + "outputs": { + "type": { + "response": { + "ok": "principal", + "error": "none" + } + } + } + }, + { + "args": [], + "name": "get-current-proxy", + "access": "read_only", + "outputs": { + "type": { + "response": { + "ok": { + "optional": "principal" + }, + "error": "none" + } + } + } + }, + { + "args": [ + { + "name": "key", + "type": { + "string-ascii": { + "length": 16 + } + } + } + ], + "name": "get-data", + "access": "read_only", + "outputs": { + "type": { + "optional": { + "buffer": { + "length": 2048 + } + } + } + } + }, + { + "args": [ + { + "name": "who", + "type": "principal" + } + ], + "name": "is-contract-owner", + "access": "read_only", + "outputs": { + "type": "bool" + } + }, + { + "args": [ + { + "name": "implementation", + "type": "principal" + } + ], + "name": "is-current-implementation", + "access": "read_only", + "outputs": { + "type": { + "response": { + "ok": "bool", + "error": "none" + } + } + } + } + ], + "variables": [ + { + "name": "CONTRACT_NAME", + "type": { + "string-ascii": { + "length": 11 + } + }, + "access": "constant" + }, + { + "name": "err-not-current-implementation", + "type": { + "response": { + "ok": "none", + "error": "uint128" + } + }, + "access": "constant" + }, + { + "name": "err-not-owner", + "type": { + "response": { + "ok": "none", + "error": "uint128" + } + }, + "access": "constant" + }, + { + "name": "contract-owner", + "type": "principal", + "access": "variable" + }, + { + "name": "current-logic-implementation", + "type": "principal", + "access": "variable" + }, + { + "name": "current-proxy", + "type": { + "optional": "principal" + }, + "access": "variable" + } + ], + "clarity_version": "Clarity2", + "fungible_tokens": [], + "non_fungible_tokens": [] + } \ No newline at end of file diff --git a/relayer/chains/stacks/client.go b/relayer/chains/stacks/client.go new file mode 100644 index 00000000..628eacdb --- /dev/null +++ b/relayer/chains/stacks/client.go @@ -0,0 +1,621 @@ +package stacks + +import ( + "context" + "encoding/hex" + "encoding/json" + "fmt" + "math/big" + "os" + "strings" + "sync" + "time" + + "github.com/gorilla/websocket" + "github.com/icon-project/centralized-relay/relayer/chains/stacks/interfaces" + "github.com/icon-project/stacks-go-sdk/pkg/abi" + "github.com/icon-project/stacks-go-sdk/pkg/clarity" + rpcClient "github.com/icon-project/stacks-go-sdk/pkg/rpc_client" + "github.com/icon-project/stacks-go-sdk/pkg/stacks" + blockchainApiClient "github.com/icon-project/stacks-go-sdk/pkg/stacks_blockchain_api_client" + "github.com/icon-project/stacks-go-sdk/pkg/transaction" + + "go.uber.org/zap" +) + +var _ interfaces.IClient = (*Client)(nil) + +type Client struct { + apiClient blockchainApiClient.APIClient + rpcApiClient rpcClient.APIClient + log *zap.Logger + mtx sync.Mutex + wsConn *websocket.Conn + idCursor int64 + pendingRequests map[int64]chan *json.RawMessage + network *stacks.StacksNetwork + xCallProxyABI *abi.ABI +} + +func NewClient(logger *zap.Logger, network *stacks.StacksNetwork, xcallAbiPath string) (*Client, error) { + cfg := blockchainApiClient.NewConfiguration() + cfg.Servers = blockchainApiClient.ServerConfigurations{ + { + URL: network.CoreAPIURL, + }, + } + + apiClient := blockchainApiClient.NewAPIClient(cfg) + + rpcCfg := rpcClient.NewConfiguration() + rpcCfg.Servers = rpcClient.ServerConfigurations{ + { + URL: network.CoreAPIURL, + }, + } + rpcApiClient := rpcClient.NewAPIClient(rpcCfg) + + xCallProxyABIBytes, err := os.ReadFile(xcallAbiPath) + if err != nil { + return nil, fmt.Errorf("failed to read xcall-proxy ABI: %w", err) + } + + var xCallProxyABI abi.ABI + if err := json.Unmarshal(xCallProxyABIBytes, &xCallProxyABI); err != nil { + return nil, fmt.Errorf("failed to parse xcall-proxy ABI: %w", err) + } + + return &Client{ + apiClient: *apiClient, + rpcApiClient: *rpcApiClient, + log: logger, + pendingRequests: make(map[int64]chan *json.RawMessage), + network: network, + xCallProxyABI: &xCallProxyABI, + }, nil +} + +func (c *Client) Log() *zap.Logger { + return c.log +} + +func (c *Client) GetAccountBalance(ctx context.Context, address string) (*big.Int, error) { + principal := blockchainApiClient.GetFilteredEventsAddressParameter{ + String: &address, + } + + resp, _, err := c.apiClient.AccountsAPI.GetAccountBalance(ctx, principal).Execute() + if err != nil { + return nil, err + } + + balanceStr := resp.Stx.Balance + balance, ok := new(big.Int).SetString(balanceStr, 10) + if !ok { + return nil, fmt.Errorf("failed to parse balance: %s", balanceStr) + } + + return balance, nil +} + +func (c *Client) GetAccountNonce(ctx context.Context, address string) (uint64, error) { + principal := blockchainApiClient.GetFilteredEventsAddressParameter{ + String: &address, + } + + resp, _, err := c.apiClient.AccountsAPI.GetAccountNonces(ctx, principal).Execute() + if err != nil { + return 0, err + } + + return uint64(resp.PossibleNextNonce), nil +} + +func (c *Client) GetTransactionById(ctx context.Context, id string) (*blockchainApiClient.GetTransactionById200Response, error) { + response, httpResponse, err := c.apiClient.TransactionsAPI.GetTransactionById(ctx, id).Execute() + if err != nil { + return nil, fmt.Errorf("failed to get transaction by ID: %w", err) + } + + if httpResponse.StatusCode != 200 { + return nil, fmt.Errorf("non-200 response: %d", httpResponse.StatusCode) + } + + return response, nil +} + +func (c *Client) GetBlockByHeightOrHash(ctx context.Context, height uint64) (*blockchainApiClient.GetBlocks200ResponseResultsInner, error) { + heightOrHash := blockchainApiClient.GetBlockHeightOrHashParameter{ + Uint64: &height, + } + + resp, _, err := c.apiClient.BlocksAPI.GetBlock(ctx, heightOrHash).Execute() + if err != nil { + return nil, err + } + return resp, nil +} + +func (c *Client) GetLatestBlock(ctx context.Context) (*blockchainApiClient.GetBlocks200ResponseResultsInner, error) { + resp, _, err := c.apiClient.BlocksAPI.GetBlocks(ctx).Limit(1).Execute() + if err != nil { + return nil, err + } + return &resp.Results[0], nil +} + +func (c *Client) CallReadOnlyFunction(ctx context.Context, contractAddress string, contractName string, functionName string, functionArgs []string) (*string, error) { + fa := rpcClient.NewReadOnlyFunctionArgsschema( + "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM", + functionArgs, + ) + + resp, _, err := c.rpcApiClient.SmartContractsAPI.CallReadOnlyFunction(ctx, contractAddress, contractName, functionName).ReadOnlyFunctionArgsschema(*fa).Execute() + if err != nil { + return nil, err + } + + return resp.Result, nil +} + +func (c *Client) MakeContractCall( + ctx context.Context, + contractAddress string, + contractName string, + functionName string, + args []clarity.ClarityValue, + senderAddress string, + senderKey []byte, +) (*transaction.ContractCallTransaction, error) { + tx, err := transaction.MakeContractCall( + contractAddress, + contractName, + functionName, + args, + *c.network, + senderAddress, + senderKey, + nil, + nil, + ) + if err != nil { + return nil, fmt.Errorf("failed to create contract call transaction: %w", err) + } + + return tx, nil +} + +func (c *Client) BroadcastTransaction(ctx context.Context, tx transaction.StacksTransaction) (string, error) { + txID, err := transaction.BroadcastTransaction(tx, c.network) + if err != nil { + return "", fmt.Errorf("failed to broadcast transaction: %w", err) + } + + return txID, nil +} + +func (c *Client) GetCurrentImplementation(ctx context.Context, contractAddress string) (clarity.ClarityValue, error) { + functionName := "get-current-implementation" + + result, err := c.CallReadOnlyFunction(ctx, contractAddress, "xcall-proxy", functionName, []string{}) + if err != nil { + return nil, fmt.Errorf("failed to get current implementation: %w", err) + } + + fmt.Printf("result: %v", result) + + byteResult, err := hex.DecodeString(strings.TrimPrefix(*result, "0x")) + if err != nil { + return nil, fmt.Errorf("failed to hex decode current implementation: %w", err) + } + + impl, err := clarity.DeserializeClarityValue(byteResult) + if err != nil { + return nil, fmt.Errorf("unexpected type for implementation principal") + } + + return impl, nil +} + +func (c *Client) SetAdmin(ctx context.Context, contractAddress string, newAdmin string, currentImplementation clarity.ClarityValue, senderAddress string, senderKey []byte) (string, error) { + functionName := "set-admin" + + newAdminPrincipal, err := clarity.StringToPrincipal(newAdmin) + if err != nil { + return "", fmt.Errorf("invalid new admin address: %w", err) + } + + currentImplementation_, err := clarity.StringToPrincipal("ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH.xcall-impl") + if err != nil { + return "", fmt.Errorf("invalid new admin address: %w", err) + } + + args := []clarity.ClarityValue{newAdminPrincipal, currentImplementation_} + + tx, err := c.MakeContractCall( + ctx, + contractAddress, + "xcall-proxy", + functionName, + args, + senderAddress, + senderKey, + ) + if err != nil { + return "", fmt.Errorf("failed to create contract call transaction: %w", err) + } + + txID, err := c.BroadcastTransaction(ctx, tx) + if err != nil { + return "", fmt.Errorf("failed to broadcast transaction: %w", err) + } + + if txID == "" { + return "", fmt.Errorf("got empty transaction ID after broadcasting") + } + + return txID, nil +} + +func (c *Client) GetReceipt(ctx context.Context, contractAddress string, srcNetwork string, connSnIn *big.Int) (bool, error) { + srcNetworkArg, err := clarity.NewStringASCII(srcNetwork) + if err != nil { + return false, fmt.Errorf("failed to create srcNetwork argument: %w", err) + } + encodedSrcNetwork, err := srcNetworkArg.Serialize() + if err != nil { + return false, fmt.Errorf("failed to serialize srcNetwork argument: %w", err) + } + hexEncodedSrcNetwork := hex.EncodeToString(encodedSrcNetwork) + + connSnInArg, err := clarity.NewInt(connSnIn) + if err != nil { + return false, fmt.Errorf("failed to create connSnIn argument: %w", err) + } + encodedConnSnIn, err := connSnInArg.Serialize() + if err != nil { + return false, fmt.Errorf("failed to serialize connSnIn argument: %w", err) + } + hexEncodedConnSnInArg := hex.EncodeToString(encodedConnSnIn) + + result, err := c.CallReadOnlyFunction( + ctx, + contractAddress, + "centralized-connection", + "get-receipt", + []string{hexEncodedSrcNetwork, hexEncodedConnSnInArg}, + ) + if err != nil { + return false, fmt.Errorf("failed to call get-receipt: %w", err) + } + + var response struct { + Ok bool `json:"ok"` + } + if err := json.Unmarshal([]byte(*result), &response); err != nil { + return false, fmt.Errorf("failed to parse get-receipt response: %w", err) + } + + return response.Ok, nil +} + +func (c *Client) ClaimFee(ctx context.Context, contractAddress string, senderAddress string, senderKey []byte) (string, error) { + args := []clarity.ClarityValue{} + tx, err := c.MakeContractCall( + ctx, + contractAddress, + "centralized-connection", + "claim-fees", + args, + senderAddress, + senderKey, + ) + if err != nil { + return "", fmt.Errorf("failed to create claim-fees transaction: %w", err) + } + + txID, err := c.BroadcastTransaction(ctx, tx) + if err != nil { + return "", fmt.Errorf("failed to broadcast claim-fees transaction: %w", err) + } + + return txID, nil +} + +func (c *Client) SetFee(ctx context.Context, contractAddress string, networkID string, messageFee *big.Int, responseFee *big.Int, senderAddress string, senderKey []byte) (string, error) { + networkIDArg, err := clarity.NewStringASCII(networkID) + if err != nil { + return "", fmt.Errorf("failed to create networkID argument: %w", err) + } + + messageFeeArg, err := clarity.NewUInt(messageFee.String()) + if err != nil { + return "", fmt.Errorf("failed to create messageFee argument: %w", err) + } + + responseFeeArg, err := clarity.NewUInt(responseFee.String()) + if err != nil { + return "", fmt.Errorf("failed to create responseFee argument: %w", err) + } + + args := []clarity.ClarityValue{networkIDArg, messageFeeArg, responseFeeArg} + tx, err := c.MakeContractCall( + ctx, + contractAddress, + "centralized-connection", + "set-fee", + args, + senderAddress, + senderKey, + ) + if err != nil { + return "", fmt.Errorf("failed to create set-fee transaction: %w", err) + } + + txID, err := c.BroadcastTransaction(ctx, tx) + if err != nil { + return "", fmt.Errorf("failed to broadcast set-fee transaction: %w", err) + } + + return txID, nil +} + +func (c *Client) GetFee(ctx context.Context, contractAddress string, networkID string, responseFee bool) (uint64, error) { + networkIDArg, err := clarity.NewStringASCII(networkID) + if err != nil { + return 0, fmt.Errorf("failed to create networkID argument: %w", err) + } + encodedNetworkID, err := networkIDArg.Serialize() + if err != nil { + return 0, fmt.Errorf("failed to serialize networkID argument: %w", err) + } + hexEncodedNetworkID := hex.EncodeToString(encodedNetworkID) + + responseFeeArg := clarity.NewBool(responseFee) + encodedResponseFee, err := responseFeeArg.Serialize() + if err != nil { + return 0, fmt.Errorf("failed to serialize responseFee argument: %w", err) + } + hexEncodedResponseFee := hex.EncodeToString(encodedResponseFee) + + result, err := c.CallReadOnlyFunction( + ctx, + contractAddress, + "centralized-connection", + "get-fee", + []string{hexEncodedNetworkID, hexEncodedResponseFee}, + ) + if err != nil { + return 0, fmt.Errorf("failed to call get-fee: %w", err) + } + + var response struct { + Ok uint64 `json:"ok"` + } + if err := json.Unmarshal([]byte(*result), &response); err != nil { + return 0, fmt.Errorf("failed to parse get-fee response: %w", err) + } + + return response.Ok, nil +} + +func (c *Client) SendCallMessage(ctx context.Context, contractAddress string, args []clarity.ClarityValue, senderAddress string, senderKey []byte) (string, error) { + tx, err := c.MakeContractCall( + ctx, + contractAddress, + "xcall-proxy", + "send-call-message", + args, + senderAddress, + senderKey, + ) + if err != nil { + return "", err + } + + txID, err := c.BroadcastTransaction(ctx, tx) + if err != nil { + return "", err + } + + return txID, nil +} + +func (c *Client) ExecuteCall(ctx context.Context, contractAddress string, args []clarity.ClarityValue, senderAddress string, senderKey []byte) (string, error) { + tx, err := c.MakeContractCall( + ctx, + contractAddress, + "xcall-proxy", + "execute-call", + args, + senderAddress, + senderKey, + ) + if err != nil { + return "", err + } + + txID, err := c.BroadcastTransaction(ctx, tx) + if err != nil { + return "", err + } + + return txID, nil +} + +func (c *Client) ExecuteRollback(ctx context.Context, contractAddress string, args []clarity.ClarityValue, senderAddress string, senderKey []byte) (string, error) { + tx, err := c.MakeContractCall( + ctx, + contractAddress, + "xcall-proxy", + "execute-rollback", + args, + senderAddress, + senderKey, + ) + if err != nil { + return "", err + } + + txID, err := c.BroadcastTransaction(ctx, tx) + if err != nil { + return "", err + } + + return txID, nil +} + +func (c *Client) SubscribeToEvents(ctx context.Context, eventTypes []string, callback interfaces.EventCallback) error { + wsURL, _ := c.apiClient.GetConfig().Servers.URL(0, make(map[string]string)) + + if strings.HasPrefix(wsURL, "http://") { + wsURL = strings.Replace(wsURL, "http://", "ws://", 1) + } else if strings.HasPrefix(wsURL, "https://") { + wsURL = strings.Replace(wsURL, "https://", "wss://", 1) + } + if !strings.HasSuffix(wsURL, "/") { + wsURL += "/" + } + wsURL += "extended/v1/ws" + + var err error + c.wsConn, _, err = websocket.DefaultDialer.Dial(wsURL, nil) + if err != nil { + return err + } + + go c.listenToMessages(ctx, callback) + + for _, eventType := range eventTypes { + if err := c.subscribe(eventType); err != nil { + return err + } + } + + return nil +} + +func (c *Client) sendRPCRequest(method string, params interface{}) (int64, error) { + c.mtx.Lock() + defer c.mtx.Unlock() + + c.idCursor++ + id := c.idCursor + + request := map[string]interface{}{ + "jsonrpc": "2.0", + "id": id, + "method": method, + "params": params, + } + + message, err := json.Marshal(request) + if err != nil { + return 0, err + } + + c.pendingRequests[id] = make(chan *json.RawMessage, 1) + + err = c.wsConn.WriteMessage(websocket.TextMessage, message) + if err != nil { + delete(c.pendingRequests, id) + return 0, err + } + + return id, nil +} + +func (c *Client) subscribe(eventType string) error { + params := map[string]interface{}{ + "event": eventType, + } + id, err := c.sendRPCRequest("subscribe", params) + if err != nil { + return err + } + + responseChan := c.pendingRequests[id] + select { + case response := <-responseChan: + var resp struct { + Jsonrpc string `json:"jsonrpc"` + Id int64 `json:"id"` + Result map[string]interface{} `json:"result"` + Error map[string]interface{} `json:"error"` + } + err = json.Unmarshal(*response, &resp) + if err != nil { + return err + } + if resp.Error != nil { + return fmt.Errorf("subscription error: %v", resp.Error) + } + return nil + case <-time.After(5 * time.Second): + return fmt.Errorf("subscription timeout") + } +} + +func (c *Client) listenToMessages(ctx context.Context, callback interfaces.EventCallback) { + defer c.wsConn.Close() + for { + select { + case <-ctx.Done(): + return + default: + _, message, err := c.wsConn.ReadMessage() + if err != nil { + c.log.Error("WebSocket read error", zap.Error(err)) + return + } + + var parsedMessage map[string]interface{} + if err := json.Unmarshal(message, &parsedMessage); err != nil { + c.log.Error("Failed to parse message", zap.Error(err)) + continue + } + + c.handleMessage(parsedMessage, callback) + } + } +} + +func (c *Client) handleMessage(message map[string]interface{}, callback interfaces.EventCallback) { + if idVal, ok := message["id"]; ok { + idFloat, ok := idVal.(float64) + if !ok { + c.log.Error("Invalid id in response") + return + } + id := int64(idFloat) + + c.mtx.Lock() + responseChan, ok := c.pendingRequests[id] + c.mtx.Unlock() + if !ok { + c.log.Error("Received response for unknown request id", zap.Int64("id", id)) + return + } + + rawMessage, err := json.Marshal(message) + if err != nil { + c.log.Error("Failed to marshal message", zap.Error(err)) + return + } + responseChan <- (*json.RawMessage)(&rawMessage) + + c.mtx.Lock() + delete(c.pendingRequests, id) + c.mtx.Unlock() + } else { + if method, ok := message["method"]; ok { + methodStr, _ := method.(string) + params := message["params"] + if err := callback(methodStr, params); err != nil { + c.log.Error("Callback error", zap.Error(err)) + } + } else { + c.log.Error("Unknown message format", zap.Any("message", message)) + } + } +} diff --git a/relayer/chains/stacks/client_test.go b/relayer/chains/stacks/client_test.go new file mode 100644 index 00000000..b9a62d36 --- /dev/null +++ b/relayer/chains/stacks/client_test.go @@ -0,0 +1,205 @@ +package stacks_test + +import ( + "context" + "encoding/hex" + "path/filepath" + "strings" + "testing" + + "github.com/icon-project/centralized-relay/relayer/chains/stacks" + "github.com/icon-project/stacks-go-sdk/pkg/clarity" + "github.com/icon-project/stacks-go-sdk/pkg/crypto" + stacksSdk "github.com/icon-project/stacks-go-sdk/pkg/stacks" + "github.com/stretchr/testify/assert" + "go.uber.org/zap" +) + +func TestClient_GetAccountBalance(t *testing.T) { + ctx := context.Background() + logger, _ := zap.NewDevelopment() + network := stacksSdk.NewStacksTestnet() + xcallAbiPath := filepath.Join("abi", "xcall-proxy-abi.json") + client, err := stacks.NewClient(logger, network, xcallAbiPath) + if err != nil { + t.Fatalf("Failed to create client: %v", err) + } + + address := "ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH" + balance, err := client.GetAccountBalance(ctx, address) + if err != nil { + t.Fatalf("Failed to get account balance: %v", err) + } + + t.Logf("Balance for address %s: %s", address, balance.String()) +} + +func TestClient_GetAccountNonce(t *testing.T) { + ctx := context.Background() + logger, _ := zap.NewDevelopment() + network := stacksSdk.NewStacksTestnet() + xcallAbiPath := filepath.Join("abi", "xcall-proxy-abi.json") + client, err := stacks.NewClient(logger, network, xcallAbiPath) + if err != nil { + t.Fatalf("Failed to create client: %v", err) + } + + address := "ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH" + nonce, err := client.GetAccountNonce(ctx, address) + if err != nil { + t.Fatalf("Failed to get account nonce: %v", err) + } + + t.Logf("Nonce for address %s: %d", address, nonce) +} + +func TestClient_GetBlockByHeightOrHash(t *testing.T) { + ctx := context.Background() + logger, _ := zap.NewDevelopment() + network := stacksSdk.NewStacksTestnet() + xcallAbiPath := filepath.Join("abi", "xcall-proxy-abi.json") + client, err := stacks.NewClient(logger, network, xcallAbiPath) + if err != nil { + t.Fatalf("Failed to create client: %v", err) + } + + block, err := client.GetLatestBlock(ctx) + if err != nil { + t.Fatalf("Failed to get latest blocks: %v", err) + } + if block == nil { + t.Fatalf("No blocks found") + } + + blockHeight := block.Height + + block, err = client.GetBlockByHeightOrHash(ctx, uint64(blockHeight)) + if err != nil { + t.Fatalf("Failed to get block by height: %v", err) + } + + t.Logf("Block at height %d: %+v", blockHeight, block) +} + +func TestClient_GetLatestBlock(t *testing.T) { + ctx := context.Background() + logger, _ := zap.NewDevelopment() + network := stacksSdk.NewStacksTestnet() + xcallAbiPath := filepath.Join("abi", "xcall-proxy-abi.json") + client, err := stacks.NewClient(logger, network, xcallAbiPath) + if err != nil { + t.Fatalf("Failed to create client: %v", err) + } + + block, err := client.GetLatestBlock(ctx) + if err != nil { + t.Fatalf("Failed to get latest blocks: %v", err) + } + + t.Logf("Latest block: %+v", block) +} + +func TestClient_CallReadOnlyFunction(t *testing.T) { + ctx := context.Background() + logger, _ := zap.NewDevelopment() + network := stacksSdk.NewStacksTestnet() + xcallAbiPath := filepath.Join("abi", "xcall-proxy-abi.json") + client, err := stacks.NewClient(logger, network, xcallAbiPath) + if err != nil { + t.Fatalf("Failed to create client: %v", err) + } + + contractAddress := "ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH" + contractName := "xcall-proxy" + functionName := "get-current-implementation" + + functionArgs := []string{} + + result, err := client.CallReadOnlyFunction(ctx, contractAddress, contractName, functionName, functionArgs) + if err != nil { + t.Fatalf("Failed to call read-only function: %v", err) + } + + t.Logf("Result of calling %s::%s: %s", contractName, functionName, *result) + + decodedResult, err := hex.DecodeString(strings.TrimPrefix(*result, "0x")) + assert.NoError(t, err, "Failed to decode hex string") + + cv, err := clarity.DeserializeClarityValue(decodedResult) + assert.NoError(t, err, "Failed to deserialize clarity value") + resp, ok := cv.(*clarity.ResponseOk) + assert.True(t, ok, "Expected result to be ResponseOk") + + principalType := resp.Value.Type() + assert.Equal(t, principalType, clarity.ClarityTypeStandardPrincipal) +} + +func TestClient_GetCurrentImplementation(t *testing.T) { + ctx := context.Background() + logger, _ := zap.NewDevelopment() + network := stacksSdk.NewStacksTestnet() + xcallAbiPath := filepath.Join("abi", "xcall-proxy-abi.json") + client, err := stacks.NewClient(logger, network, xcallAbiPath) + assert.NoError(t, err, "Failed to create client") + + contractAddress := "ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH" + + impl, err := client.GetCurrentImplementation(ctx, contractAddress) + assert.NoError(t, err, "Failed to get current implementation") + assert.NotEmpty(t, impl, "Implementation address should not be empty") + + t.Logf("Current implementation: %s", impl) +} + +func TestClient_SetAdmin(t *testing.T) { + ctx := context.Background() + logger, _ := zap.NewDevelopment() + network := stacksSdk.NewStacksTestnet() + xcallAbiPath := filepath.Join("abi", "xcall-proxy-abi.json") + client, err := stacks.NewClient(logger, network, xcallAbiPath) + assert.NoError(t, err, "Failed to create client") + + contractAddress := "ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH.xcall-proxy" + newAdmin := "ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH" + + currentImplementation, _ := client.GetCurrentImplementation(ctx, contractAddress) + senderAddress := "ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH" + mnemonic := "vapor unhappy gather snap project ball gain puzzle comic error avocado bounce letter anxiety wheel provide canyon promote sniff improve figure daughter mansion baby" + senderKey, err := crypto.DeriveStxPrivateKey(mnemonic, 0) + if err != nil { + t.Fatalf("Failed to derive sender key: %v", err) + } + + txID, err := client.SetAdmin(ctx, contractAddress, newAdmin, currentImplementation, senderAddress, senderKey) + assert.NoError(t, err, "Failed to set admin") + assert.NotEmpty(t, txID, "Transaction ID should not be empty") + + t.Logf("SetAdmin transaction ID: %s", txID) +} + +// func TestClient_SubscribeToEvents(t *testing.T) { +// ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) +// defer cancel() + +// logger, _ := zap.NewDevelopment() +// client, err := stacks.NewClient("https://api.testnet.hiro.so", logger) +// if err != nil { +// t.Fatalf("Failed to create client: %v", err) +// } + +// var wg sync.WaitGroup +// wg.Add(1) + +// callback := func(eventType string, data interface{}) error { +// t.Logf("Received event: %s, Data: %+v", eventType, data) +// wg.Done() +// return nil +// } + +// err = client.SubscribeToEvents(ctx, []string{"block"}, callback) +// if err != nil { +// t.Fatalf("Failed to subscribe to events: %v", err) +// } + +// wg.Wait() +// } diff --git a/relayer/chains/stacks/event_parse.go b/relayer/chains/stacks/event_parse.go new file mode 100644 index 00000000..c0bb1a4a --- /dev/null +++ b/relayer/chains/stacks/event_parse.go @@ -0,0 +1,142 @@ +package stacks + +import ( + "encoding/json" + "fmt" + "math/big" + + "github.com/icon-project/centralized-relay/relayer/events" + providerTypes "github.com/icon-project/centralized-relay/relayer/types" + "go.uber.org/zap" +) + +type EmitMessageEvent struct { + TargetNetwork string `json:"targetNetwork"` + Sn string `json:"sn"` + Msg string `json:"msg"` +} + +type CallMessageEvent struct { + ReqID string `json:"req_id"` + Sn string `json:"sn"` + Data string `json:"data"` +} + +type RollbackMessageEvent struct { + Sn string `json:"sn"` +} + +func (p *Provider) getRelayMessageFromEvent(eventType string, data interface{}) (*providerTypes.Message, error) { + switch eventType { + case EmitMessage: + return p.parseEmitMessageEvent(data) + case CallMessage: + return p.parseCallMessageEvent(data) + case RollbackMessage: + return p.parseRollbackMessageEvent(data) + default: + return nil, fmt.Errorf("unknown event type: %s", eventType) + } +} + +func (p *Provider) parseEmitMessageEvent(data interface{}) (*providerTypes.Message, error) { + var emitMsg EmitMessageEvent + + dataBytes, err := json.Marshal(data) + if err != nil { + p.log.Error("Failed to marshal EmitMessageEvent data", zap.Error(err)) + return nil, fmt.Errorf("failed to marshal EmitMessageEvent data: %w", err) + } + + if err := json.Unmarshal(dataBytes, &emitMsg); err != nil { + p.log.Error("Failed to unmarshal EmitMessageEvent", zap.Error(err)) + return nil, fmt.Errorf("failed to unmarshal EmitMessageEvent: %w", err) + } + + sn, ok := new(big.Int).SetString(emitMsg.Sn, 10) + if !ok { + p.log.Error("Invalid Sn in EmitMessageEvent", zap.String("Sn", emitMsg.Sn)) + return nil, fmt.Errorf("invalid Sn in EmitMessageEvent: %s", emitMsg.Sn) + } + + msg := &providerTypes.Message{ + Dst: emitMsg.TargetNetwork, + Src: p.NID(), + Sn: sn, + MessageHeight: 0, + EventType: events.EmitMessage, + Data: []byte(emitMsg.Msg), + } + + return msg, nil +} + +func (p *Provider) parseCallMessageEvent(data interface{}) (*providerTypes.Message, error) { + var callMsg CallMessageEvent + + dataBytes, err := json.Marshal(data) + if err != nil { + p.log.Error("Failed to marshal CallMessageEvent data", zap.Error(err)) + return nil, fmt.Errorf("failed to marshal CallMessageEvent data: %w", err) + } + + if err := json.Unmarshal(dataBytes, &callMsg); err != nil { + p.log.Error("Failed to unmarshal CallMessageEvent", zap.Error(err)) + return nil, fmt.Errorf("failed to unmarshal CallMessageEvent: %w", err) + } + + sn, ok := new(big.Int).SetString(callMsg.Sn, 10) + if !ok { + p.log.Error("Invalid Sn in CallMessageEvent", zap.String("Sn", callMsg.Sn)) + return nil, fmt.Errorf("invalid Sn in CallMessageEvent: %s", callMsg.Sn) + } + + reqID, ok := new(big.Int).SetString(callMsg.ReqID, 10) + if !ok { + p.log.Error("Invalid ReqID in CallMessageEvent", zap.String("ReqID", callMsg.ReqID)) + return nil, fmt.Errorf("invalid ReqID in CallMessageEvent: %s", callMsg.ReqID) + } + + msg := &providerTypes.Message{ + Dst: p.NID(), + Src: p.NID(), + Sn: sn, + MessageHeight: 0, + EventType: events.CallMessage, + Data: []byte(callMsg.Data), + ReqID: reqID, + } + + return msg, nil +} + +func (p *Provider) parseRollbackMessageEvent(data interface{}) (*providerTypes.Message, error) { + var rollbackMsg RollbackMessageEvent + + dataBytes, err := json.Marshal(data) + if err != nil { + p.log.Error("Failed to marshal RollbackMessageEvent data", zap.Error(err)) + return nil, fmt.Errorf("failed to marshal RollbackMessageEvent data: %w", err) + } + + if err := json.Unmarshal(dataBytes, &rollbackMsg); err != nil { + p.log.Error("Failed to unmarshal RollbackMessageEvent", zap.Error(err)) + return nil, fmt.Errorf("failed to unmarshal RollbackMessageEvent: %w", err) + } + + sn, ok := new(big.Int).SetString(rollbackMsg.Sn, 10) + if !ok { + p.log.Error("Invalid Sn in RollbackMessageEvent", zap.String("Sn", rollbackMsg.Sn)) + return nil, fmt.Errorf("invalid Sn in RollbackMessageEvent: %s", rollbackMsg.Sn) + } + + msg := &providerTypes.Message{ + Dst: p.NID(), + Src: p.NID(), + Sn: sn, + MessageHeight: 0, + EventType: events.RollbackMessage, + } + + return msg, nil +} diff --git a/relayer/chains/stacks/event_parse_test.go b/relayer/chains/stacks/event_parse_test.go new file mode 100644 index 00000000..78ab0269 --- /dev/null +++ b/relayer/chains/stacks/event_parse_test.go @@ -0,0 +1,311 @@ +package stacks + +import ( + "context" + "math/big" + "testing" + + "github.com/stretchr/testify/assert" + "go.uber.org/zap" + + "github.com/icon-project/centralized-relay/relayer/events" + "github.com/icon-project/centralized-relay/relayer/provider" + providerTypes "github.com/icon-project/centralized-relay/relayer/types" +) + +func getTestLogger() *zap.Logger { + logger, _ := zap.NewDevelopment() + return logger +} + +func TestParseEmitMessageEvent(t *testing.T) { + logger := getTestLogger() + nid := "stacks" + + cfg := &Config{ + CommonConfig: provider.CommonConfig{ + RPCUrl: "https://stacks-node-api.example.com", + Contracts: providerTypes.ContractConfigMap{ + "XcallContract": "ST000000000000000000002AMW42H", + "ConnectionContract": "ST000000000000000000002AMW42H", + }, + NID: nid, + }, + } + + p, err := cfg.NewProvider(context.Background(), logger, "/tmp/relayer", false, nid) + assert.NoError(t, err, "Expected no error during provider initialization") + assert.NotNil(t, p, "Expected Provider to be initialized") + + providerConcrete, ok := p.(*Provider) + assert.True(t, ok, "Expected ChainProvider to be of type *Provider") + + tests := []struct { + name string + eventData interface{} + expectedMsg *providerTypes.Message + wantErr bool + }{ + { + name: "Valid EmitMessageEvent", + eventData: EmitMessageEvent{ + TargetNetwork: "stacks_testnet", + Sn: "12345", + Msg: "Hello, Stacks!", + }, + expectedMsg: &providerTypes.Message{ + Dst: "stacks_testnet", + Src: "stacks", + Sn: big.NewInt(12345), + MessageHeight: 0, // To be set based on block information + EventType: events.EmitMessage, + Data: []byte("Hello, Stacks!"), + }, + wantErr: false, + }, + { + name: "Invalid Sn in EmitMessageEvent", + eventData: map[string]interface{}{ + "targetNetwork": "stacks_testnet", + "sn": "not_a_number", + "msg": "Hello, Stacks!", + }, + expectedMsg: nil, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + msg, err := providerConcrete.getRelayMessageFromEvent("message_event", tt.eventData) + if tt.wantErr { + assert.Error(t, err, "Expected an error") + assert.Nil(t, msg, "Expected Message to be nil") + } else { + assert.NoError(t, err, "Expected no error") + assert.NotNil(t, msg, "Expected a Message object") + + assert.Equal(t, tt.expectedMsg.Dst, msg.Dst, "Dst should match") + assert.Equal(t, tt.expectedMsg.Src, msg.Src, "Src should match") + assert.Equal(t, tt.expectedMsg.Sn, msg.Sn, "Sn should match") + assert.Equal(t, tt.expectedMsg.EventType, msg.EventType, "EventType should match") + assert.Equal(t, tt.expectedMsg.Data, msg.Data, "Data should match") + } + }) + } +} + +func TestParseCallMessageEvent(t *testing.T) { + logger := getTestLogger() + nid := "stacks" + + cfg := &Config{ + CommonConfig: provider.CommonConfig{ + RPCUrl: "https://stacks-node-api.example.com", + Contracts: providerTypes.ContractConfigMap{ + "XcallContract": "ST000000000000000000002AMW42H", + "ConnectionContract": "ST000000000000000000002AMW42H", + }, + NID: nid, + }, + } + + p, err := cfg.NewProvider(context.Background(), logger, "/tmp/relayer", false, nid) + assert.NoError(t, err, "Expected no error during provider initialization") + assert.NotNil(t, p, "Expected Provider to be initialized") + + providerConcrete, ok := p.(*Provider) + assert.True(t, ok, "Expected ChainProvider to be of type *Provider") + + tests := []struct { + name string + eventData interface{} + expectedMsg *providerTypes.Message + wantErr bool + }{ + { + name: "Valid CallMessageEvent", + eventData: CallMessageEvent{ + ReqID: "67890", + Sn: "54321", + Data: "0xabcdef", + }, + expectedMsg: &providerTypes.Message{ + Dst: "stacks", + Src: "stacks", + Sn: big.NewInt(54321), + MessageHeight: 0, // To be set based on block information + EventType: events.CallMessage, + Data: []byte("0xabcdef"), + ReqID: big.NewInt(67890), + }, + wantErr: false, + }, + { + name: "Invalid Sn in CallMessageEvent", + eventData: map[string]interface{}{ + "req_id": "invalid_req_id", + "sn": "invalid_sn", + "data": "0xabcdef", + }, + expectedMsg: nil, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + msg, err := providerConcrete.getRelayMessageFromEvent("call_message_event", tt.eventData) + if tt.wantErr { + assert.Error(t, err, "Expected an error") + assert.Nil(t, msg, "Expected Message to be nil") + } else { + assert.NoError(t, err, "Expected no error") + assert.NotNil(t, msg, "Expected a Message object") + + assert.Equal(t, tt.expectedMsg.Dst, msg.Dst, "Dst should match") + assert.Equal(t, tt.expectedMsg.Src, msg.Src, "Src should match") + assert.Equal(t, tt.expectedMsg.Sn, msg.Sn, "Sn should match") + assert.Equal(t, tt.expectedMsg.ReqID, msg.ReqID, "ReqID should match") + assert.Equal(t, tt.expectedMsg.EventType, msg.EventType, "EventType should match") + assert.Equal(t, tt.expectedMsg.Data, msg.Data, "Data should match") + } + }) + } +} + +func TestParseRollbackMessageEvent(t *testing.T) { + logger := getTestLogger() + nid := "stacks" + + cfg := &Config{ + CommonConfig: provider.CommonConfig{ + RPCUrl: "https://stacks-node-api.example.com", + Contracts: providerTypes.ContractConfigMap{ + "XcallContract": "ST000000000000000000002AMW42H", + "ConnectionContract": "ST000000000000000000002AMW42H", + }, + NID: nid, + }, + } + + p, err := cfg.NewProvider(context.Background(), logger, "/tmp/relayer", false, nid) + assert.NoError(t, err, "Expected no error during provider initialization") + assert.NotNil(t, p, "Expected Provider to be initialized") + + providerConcrete, ok := p.(*Provider) + assert.True(t, ok, "Expected ChainProvider to be of type *Provider") + + tests := []struct { + name string + eventData interface{} + expectedMsg *providerTypes.Message + wantErr bool + }{ + { + name: "Valid RollbackMessageEvent", + eventData: RollbackMessageEvent{ + Sn: "112233", + }, + expectedMsg: &providerTypes.Message{ + Dst: "stacks", + Src: "stacks", + Sn: big.NewInt(112233), + MessageHeight: 0, + EventType: events.RollbackMessage, + Data: nil, + }, + wantErr: false, + }, + { + name: "Invalid Sn in RollbackMessageEvent", + eventData: map[string]interface{}{ + "sn": "invalid_sn", + }, + expectedMsg: nil, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + msg, err := providerConcrete.getRelayMessageFromEvent("rollback_message_event", tt.eventData) + if tt.wantErr { + assert.Error(t, err, "Expected an error") + assert.Nil(t, msg, "Expected Message to be nil") + } else { + assert.NoError(t, err, "Expected no error") + assert.NotNil(t, msg, "Expected a Message object") + + assert.Equal(t, tt.expectedMsg.Dst, msg.Dst, "Dst should match") + assert.Equal(t, tt.expectedMsg.Src, msg.Src, "Src should match") + assert.Equal(t, tt.expectedMsg.Sn, msg.Sn, "Sn should match") + assert.Equal(t, tt.expectedMsg.EventType, msg.EventType, "EventType should match") + assert.Nil(t, msg.Data, "Data should be nil for RollbackMessageEvent") + } + }) + } +} + +func TestGetRelayMessageFromEvent_UnknownEvent(t *testing.T) { + logger := getTestLogger() + nid := "stacks" + + cfg := &Config{ + CommonConfig: provider.CommonConfig{ + RPCUrl: "https://stacks-node-api.example.com", + Contracts: providerTypes.ContractConfigMap{ + "XcallContract": "ST000000000000000000002AMW42H", + "ConnectionContract": "ST000000000000000000002AMW42H", + }, + NID: nid, + }, + } + + p, err := cfg.NewProvider(context.Background(), logger, "/tmp/relayer", false, nid) + assert.NoError(t, err, "Expected no error during provider initialization") + assert.NotNil(t, p, "Expected Provider to be initialized") + + providerConcrete, ok := p.(*Provider) + assert.True(t, ok, "Expected ChainProvider to be of type *Provider") + + tests := []struct { + name string + eventType string + eventData interface{} + expectedMsg *providerTypes.Message + wantErr bool + }{ + { + name: "Unknown Event Type", + eventType: "unknown_event", + eventData: map[string]interface{}{ + "some_field": "some_value", + }, + expectedMsg: nil, + wantErr: true, + }, + { + name: "Empty Event Type", + eventType: "", + eventData: map[string]interface{}{ + "another_field": "another_value", + }, + expectedMsg: nil, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + msg, err := providerConcrete.getRelayMessageFromEvent(tt.eventType, tt.eventData) + if tt.wantErr { + assert.Error(t, err, "Expected an error") + assert.Nil(t, msg, "Expected Message to be nil") + } else { + assert.NoError(t, err, "Expected no error") + assert.NotNil(t, msg, "Expected a Message object") + } + }) + } +} diff --git a/relayer/chains/stacks/events.go b/relayer/chains/stacks/events.go new file mode 100644 index 00000000..275662f6 --- /dev/null +++ b/relayer/chains/stacks/events.go @@ -0,0 +1,41 @@ +package stacks + +import ( + "github.com/icon-project/centralized-relay/relayer/events" + providerTypes "github.com/icon-project/centralized-relay/relayer/types" +) + +const ( + EmitMessage = "message_event" + CallMessage = "call_message_event" + RollbackMessage = "rollback_message_event" +) + +func (c *Config) eventMap() map[string]providerTypes.EventMap { + eventMap := make(map[string]providerTypes.EventMap, len(c.Contracts)) + for contractName, addr := range c.Contracts { + event := providerTypes.EventMap{ContractName: contractName, Address: addr} + sig := make(map[string]string) + switch contractName { + case providerTypes.XcallContract: + sig[CallMessage] = events.CallMessage + sig[RollbackMessage] = events.RollbackMessage + case providerTypes.ConnectionContract: + sig[EmitMessage] = events.EmitMessage + } + event.SigType = sig + eventMap[addr] = event + } + return eventMap +} + +func (p *Provider) GetAddressByEventType(eventType string) string { + for _, contract := range p.contracts { + for _, name := range contract.SigType { + if name == eventType { + return contract.Address + } + } + } + return "" +} diff --git a/relayer/chains/stacks/interfaces/client.go b/relayer/chains/stacks/interfaces/client.go new file mode 100644 index 00000000..6d29cdd5 --- /dev/null +++ b/relayer/chains/stacks/interfaces/client.go @@ -0,0 +1,32 @@ +package interfaces + +import ( + "context" + "math/big" + + "github.com/icon-project/stacks-go-sdk/pkg/clarity" + blockchainApiClient "github.com/icon-project/stacks-go-sdk/pkg/stacks_blockchain_api_client" + "go.uber.org/zap" +) + +type IClient interface { + GetAccountBalance(ctx context.Context, address string) (*big.Int, error) + GetAccountNonce(ctx context.Context, address string) (uint64, error) + GetTransactionById(ctx context.Context, id string) (*blockchainApiClient.GetTransactionById200Response, error) + GetBlockByHeightOrHash(ctx context.Context, height uint64) (*blockchainApiClient.GetBlocks200ResponseResultsInner, error) + GetCurrentImplementation(ctx context.Context, contractAddress string) (clarity.ClarityValue, error) + SetAdmin(ctx context.Context, contractAddress string, newAdmin string, currentImplementation clarity.ClarityValue, senderAddress string, senderKey []byte) (string, error) + GetReceipt(ctx context.Context, contractAddress string, srcNetwork string, connSnIn *big.Int) (bool, error) + ClaimFee(ctx context.Context, contractAddress string, senderAddress string, senderKey []byte) (string, error) + SetFee(ctx context.Context, contractAddress string, networkID string, messageFee *big.Int, responseFee *big.Int, senderAddress string, senderKey []byte) (string, error) + GetFee(ctx context.Context, contractAddress string, networkID string, responseFee bool) (uint64, error) + SendCallMessage(ctx context.Context, contractAddress string, args []clarity.ClarityValue, senderAddress string, senderKey []byte) (string, error) + ExecuteCall(ctx context.Context, contractAddress string, args []clarity.ClarityValue, senderAddress string, senderKey []byte) (string, error) + ExecuteRollback(ctx context.Context, contractAddress string, args []clarity.ClarityValue, senderAddress string, senderKey []byte) (string, error) + GetLatestBlock(ctx context.Context) (*blockchainApiClient.GetBlocks200ResponseResultsInner, error) + CallReadOnlyFunction(ctx context.Context, contractAddress string, contractName string, functionName string, functionArgs []string) (*string, error) + SubscribeToEvents(ctx context.Context, eventTypes []string, callback EventCallback) error + Log() *zap.Logger +} + +type EventCallback func(eventType string, data interface{}) error diff --git a/relayer/chains/stacks/keys.go b/relayer/chains/stacks/keys.go new file mode 100644 index 00000000..0328e0e4 --- /dev/null +++ b/relayer/chains/stacks/keys.go @@ -0,0 +1,168 @@ +package stacks + +import ( + "context" + "fmt" + "os" + "path/filepath" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/icon-project/stacks-go-sdk/pkg/crypto" + "github.com/icon-project/stacks-go-sdk/pkg/stacks" + "go.uber.org/zap" +) + +func (p *Provider) RestoreKeystore(ctx context.Context) error { + keystorePath := p.keystorePath(p.cfg.Address) + + encryptedKey, err := os.ReadFile(keystorePath) + if err != nil { + p.log.Error("Failed to read keystore file", zap.String("path", keystorePath), zap.Error(err)) + return fmt.Errorf("failed to read keystore file: %w", err) + } + + privateKey, err := p.kms.Decrypt(ctx, encryptedKey) + if err != nil { + p.log.Error("Failed to decrypt keystore", zap.Error(err)) + return fmt.Errorf("failed to decrypt keystore: %w", err) + } + + p.privateKey = privateKey + + p.log.Info("Keystore restored successfully", zap.String("address", p.cfg.Address)) + return nil +} + +func (p *Provider) NewKeystore(passphrase string) (string, error) { + newKey, err := btcec.NewPrivateKey() + if err != nil { + p.log.Error("Failed to generate new private key", zap.Error(err)) + return "", fmt.Errorf("failed to generate new private key: %w", err) + } + privateKeyBytes := newKey.Serialize() + + network, err := MapNIDToChainID(p.cfg.NID) + if err != nil { + p.log.Error("Chain id not found. Check the NID config", zap.Error(err)) + return "", fmt.Errorf("chain id not found: %w", err) + } + + address, err := crypto.GetAddressFromPrivateKey(privateKeyBytes, network) + if err != nil { + p.log.Error("Failed to derive address from private key", zap.Error(err)) + return "", fmt.Errorf("failed to derive address: %w", err) + } + + encryptedKey, err := p.kms.Encrypt(context.Background(), privateKeyBytes) + if err != nil { + p.log.Error("Failed to encrypt private key", zap.Error(err)) + return "", fmt.Errorf("failed to encrypt private key: %w", err) + } + + encryptedPass, err := p.kms.Encrypt(context.Background(), []byte(passphrase)) + if err != nil { + p.log.Error("Failed to encrypt passphrase", zap.Error(err)) + return "", fmt.Errorf("failed to encrypt passphrase: %w", err) + } + + keystorePath := p.keystorePath(address) + passPath := keystorePath + ".pass" + + if err := os.MkdirAll(filepath.Dir(keystorePath), 0700); err != nil { + p.log.Error("Failed to create keystore directory", zap.Error(err)) + return "", fmt.Errorf("failed to create keystore directory: %w", err) + } + + if err := os.WriteFile(keystorePath, encryptedKey, 0600); err != nil { + p.log.Error("Failed to write keystore file", zap.String("path", keystorePath), zap.Error(err)) + return "", fmt.Errorf("failed to write keystore file: %w", err) + } + + if err := os.WriteFile(passPath, encryptedPass, 0600); err != nil { + p.log.Error("Failed to write passphrase file", zap.String("path", passPath), zap.Error(err)) + return "", fmt.Errorf("failed to write passphrase file: %w", err) + } + + p.privateKey = privateKeyBytes + p.cfg.Address = address + + p.log.Info("New keystore created successfully", zap.String("address", address)) + return address, nil +} + +func (p *Provider) ImportKeystore(ctx context.Context, keyPath, passphrase string) (string, error) { + encryptedKey, err := os.ReadFile(keyPath) + if err != nil { + p.log.Error("Failed to read imported keystore file", zap.String("path", keyPath), zap.Error(err)) + return "", fmt.Errorf("failed to read imported keystore file: %w", err) + } + + privateKey, err := p.kms.Decrypt(ctx, encryptedKey) + if err != nil { + p.log.Error("Failed to decrypt imported keystore", zap.Error(err)) + return "", fmt.Errorf("failed to decrypt imported keystore: %w", err) + } + + network, err := MapNIDToChainID(p.cfg.NID) + if err != nil { + p.log.Error("Chain id not found. Check the NID config", zap.Error(err)) + return "", fmt.Errorf("chain id not found: %w", err) + } + + address, err := crypto.GetAddressFromPrivateKey(privateKey, network) + if err != nil { + p.log.Error("Failed to derive address from imported private key", zap.Error(err)) + return "", fmt.Errorf("failed to derive address: %w", err) + } + + encryptedStoredKey, err := p.kms.Encrypt(ctx, privateKey) + if err != nil { + p.log.Error("Failed to encrypt imported private key for storage", zap.Error(err)) + return "", fmt.Errorf("failed to encrypt imported private key: %w", err) + } + + encryptedPass, err := p.kms.Encrypt(ctx, []byte(passphrase)) + if err != nil { + p.log.Error("Failed to encrypt passphrase", zap.Error(err)) + return "", fmt.Errorf("failed to encrypt passphrase: %w", err) + } + + destKeystorePath := p.keystorePath(address) + destPassPath := destKeystorePath + ".pass" + + if err := os.MkdirAll(filepath.Dir(destKeystorePath), 0700); err != nil { + p.log.Error("Failed to create keystore directory", zap.Error(err)) + return "", fmt.Errorf("failed to create keystore directory: %w", err) + } + + if err := os.WriteFile(destKeystorePath, encryptedStoredKey, 0600); err != nil { + p.log.Error("Failed to write imported keystore file", zap.String("path", destKeystorePath), zap.Error(err)) + return "", fmt.Errorf("failed to write imported keystore file: %w", err) + } + + if err := os.WriteFile(destPassPath, encryptedPass, 0600); err != nil { + p.log.Error("Failed to write imported passphrase file", zap.String("path", destPassPath), zap.Error(err)) + return "", fmt.Errorf("failed to write imported passphrase file: %w", err) + } + + p.privateKey = privateKey + p.cfg.Address = address + + p.log.Info("Keystore imported successfully", zap.String("address", address)) + return address, nil +} + +func (p *Provider) keystorePath(addr string) string { + return filepath.Join(p.cfg.HomeDir, "keystore", p.NID(), addr) +} + +func MapNIDToChainID(nid string) (stacks.ChainID, error) { + switch nid { + case "stacks": + return stacks.ChainIDMainnet, nil + case "stacks_testnet": + return stacks.ChainIDTestnet, nil + default: + return 0, fmt.Errorf("unsupported NID: %s", nid) + } +} diff --git a/relayer/chains/stacks/keys_test.go b/relayer/chains/stacks/keys_test.go new file mode 100644 index 00000000..f9bf013e --- /dev/null +++ b/relayer/chains/stacks/keys_test.go @@ -0,0 +1,138 @@ +package stacks + +import ( + "context" + "errors" + "os" + "path/filepath" + "testing" + + "github.com/icon-project/centralized-relay/relayer/chains/stacks/mocks" + "github.com/icon-project/centralized-relay/relayer/provider" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "go.uber.org/zap" +) + +func TestRestoreKeystore_Success(t *testing.T) { + tempDir, err := os.MkdirTemp("", "keystore_test") + assert.NoError(t, err) + defer os.RemoveAll(tempDir) + + encryptedKey := []byte("encrypted_private_key") + address := "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM" + nid := "stacks" + keystorePath := filepath.Join(tempDir, "keystore", nid, address) + + err = os.MkdirAll(filepath.Dir(keystorePath), 0700) + assert.NoError(t, err) + + err = os.WriteFile(keystorePath, encryptedKey, 0600) + assert.NoError(t, err) + + mockKMS := new(mocks.MockKMS) + decryptedKey := []byte("decrypted_private_key") + mockKMS.On("Decrypt", mock.Anything, encryptedKey).Return(decryptedKey, nil) + + logger, _ := zap.NewDevelopment() + defer logger.Sync() + + cfg := &Config{ + CommonConfig: provider.CommonConfig{ + HomeDir: tempDir, + NID: nid, + Address: address, + }, + } + + provider := &Provider{ + cfg: cfg, + log: logger, + kms: mockKMS, + privateKey: nil, + } + + err = provider.RestoreKeystore(context.Background()) + assert.NoError(t, err) + + assert.Equal(t, decryptedKey, provider.privateKey) + mockKMS.AssertExpectations(t) +} + +func TestRestoreKeystore_ReadFileError(t *testing.T) { + tempDir, err := os.MkdirTemp("", "keystore_test") + assert.NoError(t, err) + defer os.RemoveAll(tempDir) + + address := "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM" + nid := "stacks" + mockKMS := new(mocks.MockKMS) + + logger, _ := zap.NewDevelopment() + defer logger.Sync() + + cfg := &Config{ + CommonConfig: provider.CommonConfig{ + HomeDir: tempDir, + NID: nid, + Address: address, + }, + } + + provider := &Provider{ + cfg: cfg, + log: logger, + kms: mockKMS, + privateKey: nil, + } + + err = provider.RestoreKeystore(context.Background()) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to read keystore file") + + mockKMS.AssertNotCalled(t, "Decrypt", mock.Anything, mock.Anything) +} + +func TestRestoreKeystore_DecryptError(t *testing.T) { + tempDir, err := os.MkdirTemp("", "keystore_test") + assert.NoError(t, err) + defer os.RemoveAll(tempDir) + + encryptedKey := []byte("encrypted_private_key") + address := "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM" + nid := "stacks" + keystorePath := filepath.Join(tempDir, "keystore", nid, address) + + err = os.MkdirAll(filepath.Dir(keystorePath), 0700) + assert.NoError(t, err) + + err = os.WriteFile(keystorePath, encryptedKey, 0600) + assert.NoError(t, err) + + mockKMS := new(mocks.MockKMS) + mockKMS.On("Decrypt", mock.Anything, encryptedKey).Return([]byte(nil), errors.New("decryption failed")) + + logger, _ := zap.NewDevelopment() + defer logger.Sync() + + cfg := &Config{ + CommonConfig: provider.CommonConfig{ + HomeDir: tempDir, + NID: nid, + Address: address, + }, + } + + provider := &Provider{ + cfg: cfg, + log: logger, + kms: mockKMS, + privateKey: nil, + } + + err = provider.RestoreKeystore(context.Background()) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to decrypt keystore") + + mockKMS.AssertExpectations(t) +} diff --git a/relayer/chains/stacks/listener.go b/relayer/chains/stacks/listener.go new file mode 100644 index 00000000..807124a8 --- /dev/null +++ b/relayer/chains/stacks/listener.go @@ -0,0 +1,93 @@ +package stacks + +import ( + "context" + "time" + + providerTypes "github.com/icon-project/centralized-relay/relayer/types" + "go.uber.org/zap" +) + +func (p *Provider) Listener(ctx context.Context, lastProcessedTx providerTypes.LastProcessedTx, blockInfoChan chan *providerTypes.BlockInfo) error { + eventTypes := p.getSubscribedEventTypes() + + errChan := make(chan error, 1) + + callback := func(eventType string, data interface{}) error { + msg, err := p.getRelayMessageFromEvent(eventType, data) + if err != nil { + p.log.Error("Failed to parse relay message from event", zap.Error(err)) + + select { + case errChan <- err: + default: + } + return err + } + + blockHeight := uint64(0) + + blockInfo := &providerTypes.BlockInfo{ + Height: blockHeight, + Messages: []*providerTypes.Message{msg}, + } + + select { + case blockInfoChan <- blockInfo: + return nil + case <-ctx.Done(): + return ctx.Err() + } + } + + for { + select { + case <-ctx.Done(): + p.log.Info("Listener context canceled") + return ctx.Err() + default: + p.log.Info("Subscribing to Stacks contract events") + err := p.client.SubscribeToEvents(ctx, eventTypes, callback) + if err != nil { + p.log.Error("Failed to subscribe to events", zap.Error(err)) + select { + case <-time.After(5 * time.Second): + p.log.Info("Retrying subscription to events") + case <-ctx.Done(): + p.log.Info("Listener context canceled during retry wait") + return ctx.Err() + } + continue + } + + select { + case err := <-errChan: + p.log.Error("Error received in event subscription", zap.Error(err)) + select { + case <-time.After(5 * time.Second): + p.log.Info("Re-subscribing to events after error") + case <-ctx.Done(): + p.log.Info("Listener context canceled during resubscription wait") + return ctx.Err() + } + case <-ctx.Done(): + p.log.Info("Listener context canceled") + return ctx.Err() + } + } + } +} + +func (p *Provider) getSubscribedEventTypes() []string { + eventTypeSet := make(map[string]struct{}) + for _, eventMap := range p.contracts { + for _, eventType := range eventMap.SigType { + eventTypeSet[eventType] = struct{}{} + } + } + eventTypes := make([]string, 0, len(eventTypeSet)) + for et := range eventTypeSet { + eventTypes = append(eventTypes, et) + } + return eventTypes +} diff --git a/relayer/chains/stacks/listener_test.go b/relayer/chains/stacks/listener_test.go new file mode 100644 index 00000000..c2812917 --- /dev/null +++ b/relayer/chains/stacks/listener_test.go @@ -0,0 +1,336 @@ +package stacks + +import ( + "context" + "math/big" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "go.uber.org/zap" + + "github.com/icon-project/centralized-relay/relayer/chains/stacks/interfaces" + "github.com/icon-project/centralized-relay/relayer/chains/stacks/mocks" + "github.com/icon-project/centralized-relay/relayer/events" + "github.com/icon-project/centralized-relay/relayer/provider" + providerTypes "github.com/icon-project/centralized-relay/relayer/types" +) + +func setupProvider(t *testing.T, mockClient *mocks.MockClient, cfg *Config) *Provider { + logger, err := zap.NewDevelopment() + assert.NoError(t, err) + p, err := cfg.NewProvider(context.Background(), logger, "/tmp/relayer", false, "stacks_testnet") + assert.NoError(t, err) + assert.NotNil(t, p) + + providerInstance := p.(*Provider) + providerInstance.client = mockClient + providerInstance.contracts = cfg.eventMap() + return providerInstance +} + +func TestListener_Success(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + mockClient := new(mocks.MockClient) + + emitMsgEvent := EmitMessageEvent{ + TargetNetwork: "stacks_testnet", + Sn: "12345", + Msg: "Hello, Stacks!", + } + + callMsgEvent := CallMessageEvent{ + ReqID: "67890", + Sn: "54321", + Data: "0xabcdef", + } + + mockClient.On("SubscribeToEvents", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + callback := args.Get(2).(interfaces.EventCallback) + + go func() { + err := callback("message_event", emitMsgEvent) + assert.NoError(t, err, "Callback for EmitMessageEvent should not error") + + err = callback("call_message_event", callMsgEvent) + assert.NoError(t, err, "Callback for CallMessageEvent should not error") + }() + }).Return(nil) + + cfg := &Config{ + CommonConfig: provider.CommonConfig{ + ChainName: "stacks_testnet", + RPCUrl: "https://stacks-node-api.example.com", + Contracts: providerTypes.ContractConfigMap{ + "xcall": "ST000000000000000000002AMW42H", + "connection": "ST000000000000000000002AMW42H", + }, + NID: "stacks_testnet", + }, + } + + providerInstance := setupProvider(t, mockClient, cfg) + + blockInfoChan := make(chan *providerTypes.BlockInfo, 2) + + go func() { + err := providerInstance.Listener(ctx, providerTypes.LastProcessedTx{}, blockInfoChan) + if err != nil { + t.Logf("Listener exited with error: %v", err) + } + }() + + expectedMessages := map[string]*providerTypes.Message{ + events.EmitMessage: { + Dst: "stacks_testnet", + Src: "stacks_testnet", + Sn: big.NewInt(12345), + MessageHeight: 0, // todo: update + EventType: events.EmitMessage, + Data: []byte("Hello, Stacks!"), + }, + events.CallMessage: { + Dst: "stacks_testnet", + Src: "stacks_testnet", + Sn: big.NewInt(54321), + MessageHeight: 0, // todo: update + EventType: events.CallMessage, + Data: []byte("0xabcdef"), + ReqID: big.NewInt(67890), + }, + } + + receivedMessages := make(map[string]*providerTypes.Message) + + timeout := time.After(2 * time.Second) + for i := 0; i < 2; i++ { + select { + case blockInfo := <-blockInfoChan: + assert.NotNil(t, blockInfo, "Received BlockInfo should not be nil") + assert.Equal(t, uint64(0), blockInfo.Height, "Block height should be 0") + assert.Len(t, blockInfo.Messages, 1, "BlockInfo should contain one message") + + msg := blockInfo.Messages[0] + expectedMsg, exists := expectedMessages[msg.EventType] + assert.True(t, exists, "Unexpected event type received: %s", msg.EventType) + + assert.Equal(t, expectedMsg.Dst, msg.Dst, "Dst field mismatch") + assert.Equal(t, expectedMsg.Src, msg.Src, "Src field mismatch") + assert.True(t, msg.Sn.Cmp(expectedMsg.Sn) == 0, "Sn field mismatch") + assert.Equal(t, expectedMsg.EventType, msg.EventType, "EventType field mismatch") + assert.Equal(t, expectedMsg.Data, msg.Data, "Data field mismatch") + + if msg.EventType == events.CallMessage { + assert.True(t, msg.ReqID.Cmp(expectedMsg.ReqID) == 0, "ReqID field mismatch for CallMessageEvent") + } + + receivedMessages[msg.EventType] = msg + + case <-timeout: + t.Fatal("Timed out waiting for BlockInfo messages") + } + } + + for eventType, expectedMsg := range expectedMessages { + receivedMsg, exists := receivedMessages[eventType] + assert.True(t, exists, "Expected to receive event type: %s", eventType) + assert.Equal(t, expectedMsg.Dst, receivedMsg.Dst, "Dst field mismatch for event type: %s", eventType) + assert.Equal(t, expectedMsg.Src, receivedMsg.Src, "Src field mismatch for event type: %s", eventType) + assert.True(t, receivedMsg.Sn.Cmp(expectedMsg.Sn) == 0, "Sn field mismatch for event type: %s", eventType) + assert.Equal(t, expectedMsg.EventType, receivedMsg.EventType, "EventType field mismatch for event type: %s", eventType) + assert.Equal(t, expectedMsg.Data, receivedMsg.Data, "Data field mismatch for event type: %s", eventType) + + if eventType == events.CallMessage { + assert.True(t, receivedMsg.ReqID.Cmp(expectedMsg.ReqID) == 0, "ReqID field mismatch for CallMessageEvent") + } + } + + cancel() + + time.Sleep(100 * time.Millisecond) + + select { + case blockInfo := <-blockInfoChan: + t.Errorf("Received unexpected BlockInfo after cancellation: %+v", blockInfo) + default: + } + + mockClient.AssertNumberOfCalls(t, "SubscribeToEvents", 1) +} + +func TestListener_CallbackError(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + mockClient := new(mocks.MockClient) + + invalidEmitMsgEvent := EmitMessageEvent{ + TargetNetwork: "stacks_testnet", + Sn: "invalid_sn", + Msg: "Hello, Stacks!", + } + + mockClient.On("SubscribeToEvents", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + callback := args.Get(2).(interfaces.EventCallback) + + go func() { + err := callback("message_event", invalidEmitMsgEvent) + assert.Error(t, err, "Callback should return an error due to invalid SN") + }() + }).Return(nil) + + cfg := &Config{ + CommonConfig: provider.CommonConfig{ + ChainName: "stacks_testnet", + RPCUrl: "https://stacks-node-api.example.com", + Contracts: providerTypes.ContractConfigMap{ + "xcall": "ST000000000000000000002AMW42H", + "connection": "ST000000000000000000002AMW42H", + }, + NID: "stacks_testnet", + }, + } + + providerInstance := setupProvider(t, mockClient, cfg) + + blockInfoChan := make(chan *providerTypes.BlockInfo, 1) + + go func() { + err := providerInstance.Listener(ctx, providerTypes.LastProcessedTx{}, blockInfoChan) + if err != nil { + t.Logf("Listener exited with error: %v", err) + } + }() + + time.Sleep(100 * time.Millisecond) + + select { + case blockInfo := <-blockInfoChan: + t.Errorf("Received unexpected BlockInfo due to callback error: %+v", blockInfo) + default: + } + + mockClient.AssertNumberOfCalls(t, "SubscribeToEvents", 1) +} + +func TestListener_InvalidEvent(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + mockClient := new(mocks.MockClient) + + unknownEventType := "unknown_event_type" + unknownEventData := map[string]interface{}{ + "some_field": "some_value", + } + + mockClient.On("SubscribeToEvents", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + callback := args.Get(2).(interfaces.EventCallback) + + go func() { + err := callback(unknownEventType, unknownEventData) + assert.Error(t, err, "Callback should return an error for unknown event type") + }() + }).Return(nil) + + cfg := &Config{ + CommonConfig: provider.CommonConfig{ + ChainName: "stacks_testnet", + RPCUrl: "https://stacks-node-api.example.com", + Contracts: providerTypes.ContractConfigMap{ + "xcall": "ST000000000000000000002AMW42H", + "connection": "ST000000000000000000002AMW42H", + }, + NID: "stacks_testnet", + }, + } + + providerInstance := setupProvider(t, mockClient, cfg) + + blockInfoChan := make(chan *providerTypes.BlockInfo, 1) + + go func() { + err := providerInstance.Listener(ctx, providerTypes.LastProcessedTx{}, blockInfoChan) + if err != nil { + t.Logf("Listener exited with error: %v", err) + } + }() + + time.Sleep(100 * time.Millisecond) + + select { + case blockInfo := <-blockInfoChan: + t.Errorf("Received unexpected BlockInfo for unknown event type: %+v", blockInfo) + default: + } + + mockClient.AssertNumberOfCalls(t, "SubscribeToEvents", 1) +} + +func TestListener_ContextCancel(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + + mockClient := new(mocks.MockClient) + + emitMsgEvent := EmitMessageEvent{ + TargetNetwork: "stacks_testnet", + Sn: "12345", + Msg: "Hello, Stacks!", + } + + mockClient.On("SubscribeToEvents", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { + callback := args.Get(2).(interfaces.EventCallback) + + go func() { + for { + select { + case <-ctx.Done(): + return + default: + callback("message_event", emitMsgEvent) + time.Sleep(50 * time.Millisecond) + } + } + }() + }).Return(nil) + + cfg := &Config{ + CommonConfig: provider.CommonConfig{ + ChainName: "stacks_testnet", + RPCUrl: "https://stacks-node-api.example.com", + Contracts: providerTypes.ContractConfigMap{ + "xcall": "ST000000000000000000002AMW42H", + "connection": "ST000000000000000000002AMW42H", + }, + NID: "stacks_testnet", + }, + } + + providerInstance := setupProvider(t, mockClient, cfg) + + blockInfoChan := make(chan *providerTypes.BlockInfo, 10) + + go func() { + err := providerInstance.Listener(ctx, providerTypes.LastProcessedTx{}, blockInfoChan) + if err != nil { + t.Logf("Listener exited with error: %v", err) + } + }() + + time.Sleep(200 * time.Millisecond) + + cancel() + + time.Sleep(100 * time.Millisecond) + + select { + case blockInfo := <-blockInfoChan: + t.Logf("Received BlockInfo before cancellation: %+v", blockInfo) + default: + } + + mockClient.AssertNumberOfCalls(t, "SubscribeToEvents", 1) +} diff --git a/relayer/chains/stacks/mocks/client_mock.go b/relayer/chains/stacks/mocks/client_mock.go new file mode 100644 index 00000000..43b00141 --- /dev/null +++ b/relayer/chains/stacks/mocks/client_mock.go @@ -0,0 +1,101 @@ +package mocks + +import ( + "context" + "math/big" + + "github.com/icon-project/centralized-relay/relayer/chains/stacks/interfaces" + "github.com/icon-project/stacks-go-sdk/pkg/clarity" + blockchainApiClient "github.com/icon-project/stacks-go-sdk/pkg/stacks_blockchain_api_client" + "github.com/stretchr/testify/mock" + "go.uber.org/zap" +) + +type MockClient struct { + mock.Mock +} + +func (m *MockClient) GetAccountBalance(ctx context.Context, address string) (*big.Int, error) { + args := m.Called(ctx, address) + return args.Get(0).(*big.Int), args.Error(1) +} + +func (m *MockClient) GetAccountNonce(ctx context.Context, address string) (uint64, error) { + args := m.Called(ctx, address) + return args.Get(0).(uint64), args.Error(1) +} + +func (m *MockClient) GetTransactionById(ctx context.Context, id string) (*blockchainApiClient.GetTransactionById200Response, error) { + args := m.Called(ctx, id) + return args.Get(0).(*blockchainApiClient.GetTransactionById200Response), args.Error(1) +} + +func (m *MockClient) GetBlockByHeightOrHash(ctx context.Context, height uint64) (*blockchainApiClient.GetBlocks200ResponseResultsInner, error) { + args := m.Called(ctx, height) + return args.Get(0).(*blockchainApiClient.GetBlocks200ResponseResultsInner), args.Error(1) +} + +func (m *MockClient) GetLatestBlock(ctx context.Context) (*blockchainApiClient.GetBlocks200ResponseResultsInner, error) { + args := m.Called(ctx) + return args.Get(0).(*blockchainApiClient.GetBlocks200ResponseResultsInner), args.Error(1) +} + +func (m *MockClient) CallReadOnlyFunction(ctx context.Context, contractAddress string, contractName string, functionName string, functionArgs []string) (*string, error) { + args := m.Called(ctx, contractAddress, contractName, functionName, functionArgs) + return args.Get(0).(*string), args.Error(1) +} + +func (m *MockClient) GetCurrentImplementation(ctx context.Context, contractAddress string) (clarity.ClarityValue, error) { + args := m.Called(ctx, contractAddress) + return args.Get(0).(clarity.ClarityValue), args.Error(1) +} + +func (m *MockClient) SetAdmin(ctx context.Context, contractAddress string, newAdmin string, currentImplementation clarity.ClarityValue, senderAddress string, senderKey []byte) (string, error) { + args := m.Called(ctx, contractAddress, newAdmin, currentImplementation, senderAddress, senderKey) + return args.Get(0).(string), args.Error(1) +} + +func (m *MockClient) GetReceipt(ctx context.Context, contractAddress string, srcNetwork string, connSnIn *big.Int) (bool, error) { + args := m.Called(ctx, contractAddress, srcNetwork, connSnIn) + return args.Get(0).(bool), args.Error(1) +} + +func (m *MockClient) ClaimFee(ctx context.Context, contractAddress string, senderAddress string, senderKey []byte) (string, error) { + args := m.Called(ctx, contractAddress, senderAddress, senderKey) + return args.Get(0).(string), args.Error(1) +} + +func (m *MockClient) SetFee(ctx context.Context, contractAddress string, networkID string, messageFee *big.Int, responseFee *big.Int, senderAddress string, senderKey []byte) (string, error) { + args := m.Called(ctx, contractAddress, networkID, messageFee, responseFee, senderAddress, senderKey) + return args.Get(0).(string), args.Error(1) +} + +func (m *MockClient) GetFee(ctx context.Context, contractAddress string, networkID string, responseFee bool) (uint64, error) { + args := m.Called(ctx, contractAddress, networkID, responseFee) + return args.Get(0).(uint64), args.Error(1) +} + +func (m *MockClient) SendCallMessage(ctx context.Context, contractAddress string, args []clarity.ClarityValue, senderAddress string, senderKey []byte) (string, error) { + mockArgs := m.Called(ctx, contractAddress, args, senderAddress, senderKey) + return mockArgs.String(0), mockArgs.Error(1) +} + +func (m *MockClient) ExecuteCall(ctx context.Context, contractAddress string, args []clarity.ClarityValue, senderAddress string, senderKey []byte) (string, error) { + mockArgs := m.Called(ctx, contractAddress, args, senderAddress, senderKey) + return mockArgs.String(0), mockArgs.Error(1) +} + +func (m *MockClient) ExecuteRollback(ctx context.Context, contractAddress string, args []clarity.ClarityValue, senderAddress string, senderKey []byte) (string, error) { + mockArgs := m.Called(ctx, contractAddress, args, senderAddress, senderKey) + return mockArgs.String(0), mockArgs.Error(1) +} + +func (m *MockClient) SubscribeToEvents(ctx context.Context, eventTypes []string, callback interfaces.EventCallback) error { + args := m.Called(ctx, eventTypes, callback) + return args.Error(0) +} + +func (m *MockClient) Log() *zap.Logger { + args := m.Called() + return args.Get(0).(*zap.Logger) +} diff --git a/relayer/chains/stacks/mocks/kms_mock.go b/relayer/chains/stacks/mocks/kms_mock.go new file mode 100644 index 00000000..1d91b4e2 --- /dev/null +++ b/relayer/chains/stacks/mocks/kms_mock.go @@ -0,0 +1,30 @@ +package mocks + +import ( + "context" + + "github.com/stretchr/testify/mock" +) + +type MockKMS struct { + mock.Mock +} + +func (m *MockKMS) Init(ctx context.Context) (*string, error) { + args := m.Called(ctx) + if args.Get(0) != nil { + s := args.String(0) + return &s, args.Error(1) + } + return nil, args.Error(1) +} + +func (m *MockKMS) Encrypt(ctx context.Context, data []byte) ([]byte, error) { + args := m.Called(ctx, data) + return args.Get(0).([]byte), args.Error(1) +} + +func (m *MockKMS) Decrypt(ctx context.Context, data []byte) ([]byte, error) { + args := m.Called(ctx, data) + return args.Get(0).([]byte), args.Error(1) +} diff --git a/relayer/chains/stacks/provider.go b/relayer/chains/stacks/provider.go new file mode 100644 index 00000000..28edfdb5 --- /dev/null +++ b/relayer/chains/stacks/provider.go @@ -0,0 +1,258 @@ +package stacks + +import ( + "context" + "fmt" + "math/big" + "path/filepath" + "sync" + "time" + + "go.uber.org/zap" + + "github.com/icon-project/centralized-relay/relayer/chains/stacks/interfaces" + "github.com/icon-project/centralized-relay/relayer/kms" + "github.com/icon-project/centralized-relay/relayer/provider" + "github.com/icon-project/centralized-relay/relayer/types" + providerTypes "github.com/icon-project/centralized-relay/relayer/types" + "github.com/icon-project/stacks-go-sdk/pkg/stacks" +) + +type Config struct { + provider.CommonConfig `json:",inline" yaml:",inline"` +} + +type Provider struct { + cfg *Config + client interfaces.IClient + log *zap.Logger + kms kms.KMS + privateKey []byte + contracts map[string]providerTypes.EventMap + LastSavedHeightFunc func() uint64 + routerMutex sync.Mutex +} + +func (c *Config) NewProvider(ctx context.Context, log *zap.Logger, homepath string, debug bool, chainName string) (provider.ChainProvider, error) { + if err := c.Validate(); err != nil { + return nil, err + } + + var network *stacks.StacksNetwork + if c.NID == "stacks" { + network = stacks.NewStacksMainnet() + } else if c.NID == "stacks_testnet" { + network = stacks.NewStacksTestnet() + } else { + return nil, fmt.Errorf("no network found for nid: %v", c.NID) + } + + xcallAbiPath := filepath.Join("abi", "xcall-proxy-abi.json") + client, err := NewClient(log, network, xcallAbiPath) + if err != nil { + return nil, fmt.Errorf("failed to create Stacks client: %v", err) + } + + c.ChainName = chainName + c.HomeDir = homepath + + return &Provider{ + cfg: c, + client: client, + log: log.With(zap.Stringp("nid", &c.NID), zap.Stringp("name", &c.ChainName)), + contracts: c.eventMap(), + }, nil +} + +func (c *Config) Validate() error { + if c.RPCUrl == "" { + return fmt.Errorf("stacks provider rpc endpoint is empty") + } + + if err := c.Contracts.Validate(); err != nil { + return fmt.Errorf("contracts are not valid: %s", err) + } + + return nil +} + +func (c *Config) Enabled() bool { + return !c.Disabled +} + +func (c *Config) SetWallet(addr string) { + c.Address = addr +} + +func (c *Config) GetWallet() string { + return c.Address +} + +func (p *Provider) NID() string { + return p.cfg.NID +} + +func (p *Provider) Name() string { + return p.cfg.ChainName +} + +func (p *Provider) Type() string { + return "stacks" +} + +func (p *Provider) Config() provider.Config { + return p.cfg +} + +func (p *Provider) Init(ctx context.Context, homepath string, kms kms.KMS) error { + p.kms = kms + return nil +} + +func (p *Provider) FinalityBlock(ctx context.Context) uint64 { + return p.cfg.FinalityBlock +} + +func (p *Provider) SetLastSavedHeightFunc(f func() uint64) { + p.LastSavedHeightFunc = f +} + +func (p *Provider) GetLastSavedBlockHeight() uint64 { + return p.LastSavedHeightFunc() +} + +func (p *Provider) SetAdmin(ctx context.Context, newAdmin string) error { + if newAdmin == "" { + return fmt.Errorf("new admin address cannot be empty") + } + + contractAddress := p.cfg.Contracts[providerTypes.XcallContract] + if contractAddress == "" { + return fmt.Errorf("xcall contract address is not set") + } + + currentImplementation, err := p.client.GetCurrentImplementation(ctx, contractAddress) + if err != nil { + return fmt.Errorf("failed to get current implementation: %w", err) + } + + txID, err := p.client.SetAdmin(ctx, contractAddress, newAdmin, currentImplementation, p.cfg.Address, p.privateKey) + if err != nil { + return fmt.Errorf("failed to set new admin: %w", err) + } + + p.log.Info("SetAdmin transaction broadcasted", zap.String("txID", txID)) + + receipt, err := p.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return fmt.Errorf("failed to confirm SetAdmin transaction: %w", err) + } + + if !receipt.Status { + return fmt.Errorf("SetAdmin transaction failed: %s", txID) + } + + p.log.Info("SetAdmin transaction confirmed", + zap.String("txID", txID), + zap.Uint64("blockHeight", receipt.Height)) + + return nil +} + +func (p *Provider) waitForTransactionConfirmation(ctx context.Context, txID string) (*types.Receipt, error) { + timeout := time.After(2 * time.Minute) + ticker := time.NewTicker(10 * time.Second) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + receipt, err := p.QueryTransactionReceipt(ctx, txID) + if err != nil { + p.log.Warn("Failed to query transaction receipt", zap.Error(err)) + continue + } + if receipt.Status { + p.log.Info("Transaction confirmed", zap.String("txID", txID)) + return receipt, nil + } + p.log.Debug("Transaction not yet confirmed", zap.String("txID", txID)) + case <-timeout: + return nil, fmt.Errorf("transaction confirmation timed out after 2 minutes") + case <-ctx.Done(): + return nil, ctx.Err() + } + } +} + +func (p *Provider) QueryBalance(ctx context.Context, addr string) (*providerTypes.Coin, error) { + balance, err := p.client.GetAccountBalance(ctx, addr) + if err != nil { + return nil, err + } + return &providerTypes.Coin{ + Amount: balance.Uint64(), + Denom: "STX", + }, nil +} + +func (p *Provider) RevertMessage(ctx context.Context, sn *big.Int) error { + return fmt.Errorf("not implemented") +} + +func (p *Provider) GetFee(ctx context.Context, networkID string, responseFee bool) (uint64, error) { + p.log.Debug("Getting fee", zap.String("networkID", networkID), zap.Bool("responseFee", responseFee)) + + fee, err := p.client.GetFee( + ctx, + p.cfg.Contracts[providerTypes.ConnectionContract], + networkID, + responseFee, + ) + if err != nil { + p.log.Error("Failed to get fee", zap.Error(err)) + return 0, fmt.Errorf("failed to get fee: %w", err) + } + + p.log.Debug("Fee retrieved successfully", zap.Uint64("fee", fee)) + return fee, nil +} + +func (p *Provider) SetFee(ctx context.Context, networkID string, msgFee, resFee *big.Int) error { + p.log.Debug("Setting fees", zap.String("networkID", networkID), zap.String("messageFee", msgFee.String()), zap.String("responseFee", resFee.String())) + + txID, err := p.client.SetFee( + ctx, + p.cfg.Contracts[providerTypes.ConnectionContract], + networkID, + msgFee, + resFee, + p.cfg.Address, + p.privateKey, + ) + if err != nil { + p.log.Error("Failed to set fees", zap.Error(err)) + return fmt.Errorf("failed to set fees: %w", err) + } + + p.log.Info("Fees set successfully", zap.String("txID", txID)) + return nil +} + +func (p *Provider) ClaimFee(ctx context.Context) error { + p.log.Debug("Claiming fees") + + txID, err := p.client.ClaimFee( + ctx, + p.cfg.Contracts[providerTypes.ConnectionContract], + p.cfg.Address, + p.privateKey, + ) + if err != nil { + p.log.Error("Failed to claim fees", zap.Error(err)) + return fmt.Errorf("failed to claim fees: %w", err) + } + + p.log.Info("Fees claimed successfully", zap.String("txID", txID)) + return nil +} diff --git a/relayer/chains/stacks/query.go b/relayer/chains/stacks/query.go new file mode 100644 index 00000000..fda5cef1 --- /dev/null +++ b/relayer/chains/stacks/query.go @@ -0,0 +1,166 @@ +package stacks + +import ( + "context" + "fmt" + "reflect" + "time" + + "github.com/icon-project/centralized-relay/relayer/events" + providerTypes "github.com/icon-project/centralized-relay/relayer/types" + "go.uber.org/zap" +) + +const eventListeningTimeout = 30 * time.Second + +func (p *Provider) ShouldReceiveMessage(ctx context.Context, message *providerTypes.Message) (bool, error) { + return true, nil +} + +func (p *Provider) ShouldSendMessage(ctx context.Context, message *providerTypes.Message) (bool, error) { + return true, nil +} + +func (p *Provider) MessageReceived(ctx context.Context, key *providerTypes.MessageKey) (bool, error) { + switch key.EventType { + case events.EmitMessage: + return p.client.GetReceipt(ctx, p.cfg.Contracts[providerTypes.ConnectionContract], key.Src, key.Sn) + case events.CallMessage: + return false, nil + case events.RollbackMessage: + return false, nil + default: + return true, fmt.Errorf("unknown event type") + } +} + +func (p *Provider) QueryTransactionReceipt(ctx context.Context, id string) (*providerTypes.Receipt, error) { + res, err := p.client.GetTransactionById(ctx, id) + if err != nil { + p.log.Error("Failed to query transaction receipt", zap.String("txHash", id), zap.Error(err)) + return nil, err + } + + if mempoolResp := res.GetMempoolTransactionList200ResponseResultsInner; mempoolResp != nil { + receipt, err := GetReceipt(mempoolResp) + if err != nil { + return nil, fmt.Errorf("failed to extract mempool transaction: %w", err) + } + return receipt, nil + } + + if confirmedResp := res.GetTransactionList200ResponseResultsInner; confirmedResp != nil { + receipt, err := GetReceipt(confirmedResp) + if err != nil { + return nil, fmt.Errorf("failed to extract confirmed transaction: %w", err) + } + return receipt, nil + } + + return nil, fmt.Errorf("failed to query transaction: %w", err) +} + +func (p *Provider) QueryLatestHeight(ctx context.Context) (uint64, error) { + latestBlock, err := p.client.GetLatestBlock(ctx) + if err != nil { + return 0, err + } + if latestBlock == nil { + return 0, fmt.Errorf("no blocks found") + } + return uint64(latestBlock.Height), nil +} + +func GetReceipt(tx interface{}) (*providerTypes.Receipt, error) { + val := reflect.ValueOf(tx).Elem() + typ := val.Type() + + for i := 0; i < val.NumField(); i++ { + field := val.Field(i) + fieldType := typ.Field(i).Name + + if !field.IsNil() { + txStruct := field.Elem() + + txTypeField := txStruct.FieldByName("TxType") + if !txTypeField.IsValid() || txTypeField.Kind() != reflect.String { + return nil, fmt.Errorf("TxType field is missing or not a string in %s", fieldType) + } + + txIdField := txStruct.FieldByName("TxId") + if !txIdField.IsValid() || txIdField.Kind() != reflect.String { + return nil, fmt.Errorf("TxId field is missing or not a string in %s", fieldType) + } + txId := txIdField.String() + + var blockHeight uint64 = 0 + blockHeightField := txStruct.FieldByName("BlockHeight") + if blockHeightField.IsValid() && blockHeightField.Kind() == reflect.Int32 { + blockHeight = uint64(blockHeightField.Int()) + } + + var status bool = false + txStatusField := txStruct.FieldByName("TxStatus") + if txStatusField.IsValid() && txStatusField.Kind() == reflect.String { + status = txStatusField.String() == "success" + } + + height := blockHeight + if txTypeField.Kind() == reflect.String && blockHeight == 0 { + height = 0 + } + + return &providerTypes.Receipt{ + TxHash: txId, + Height: height, + Status: status, + }, nil + } + } + + return nil, fmt.Errorf("no non-nil transaction field found") +} + +func (p *Provider) GenerateMessages(ctx context.Context, key *providerTypes.MessageKeyWithMessageHeight) ([]*providerTypes.Message, error) { + p.log.Info("Generating messages", zap.Any("messagekey", key)) + if key == nil { + return nil, fmt.Errorf("GenerateMessages: message key cannot be nil") + } + + eventTypes := p.getSubscribedEventTypes() + + var messages []*providerTypes.Message + errChan := make(chan error, 1) + + callback := func(eventType string, data interface{}) error { + msg, err := p.getRelayMessageFromEvent(eventType, data) + if err != nil { + p.log.Error("Failed to parse relay message from event", zap.Error(err)) + return err + } + + msg.MessageHeight = key.Height + + messages = append(messages, msg) + return nil + } + + ctxWithTimeout, cancel := context.WithTimeout(ctx, eventListeningTimeout) + defer cancel() + + err := p.client.SubscribeToEvents(ctxWithTimeout, eventTypes, callback) + if err != nil { + return nil, fmt.Errorf("failed to subscribe to events: %w", err) + } + + select { + case err := <-errChan: + return nil, fmt.Errorf("error occurred while processing events: %w", err) + case <-ctxWithTimeout.Done(): + if len(messages) == 0 { + return nil, fmt.Errorf("no messages generated within the timeout period") + } + } + + return messages, nil +} diff --git a/relayer/chains/stacks/route.go b/relayer/chains/stacks/route.go new file mode 100644 index 00000000..ced5bb62 --- /dev/null +++ b/relayer/chains/stacks/route.go @@ -0,0 +1,123 @@ +package stacks + +import ( + "context" + "fmt" + + "github.com/icon-project/centralized-relay/relayer/events" + "github.com/icon-project/centralized-relay/relayer/types" + "github.com/icon-project/stacks-go-sdk/pkg/clarity" + "go.uber.org/zap" +) + +func (p *Provider) Route(ctx context.Context, message *types.Message, callback types.TxResponseFunc) error { + p.log.Info("Starting to route message", + zap.Any("sn", message.Sn), + zap.Any("req_id", message.ReqID), + zap.String("src", message.Src), + zap.String("event_type", message.EventType)) + + var txID string + var err error + + switch message.EventType { + case events.EmitMessage: + txID, err = p.handleEmitMessage(ctx, message) + case events.CallMessage: + txID, err = p.handleCallMessage(ctx, message) + case events.RollbackMessage: + txID, err = p.handleRollbackMessage(ctx, message) + default: + return fmt.Errorf("unknown event type: %s", message.EventType) + } + + if err != nil { + return fmt.Errorf("failed to handle %s: %w", message.EventType, err) + } + + p.log.Info("Transaction sent", zap.String("txID", txID)) + + receipt, err := p.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return fmt.Errorf("failed to confirm transaction: %w", err) + } + + response := &types.TxResponse{ + TxHash: txID, + Height: int64(receipt.Height), + Code: types.Success, + } + + callback(message.MessageKey(), response, nil) + + return nil +} + +func (p *Provider) handleEmitMessage(ctx context.Context, message *types.Message) (string, error) { + contractAddress := p.cfg.Contracts[types.ConnectionContract] + + srcNetworkArg, err := clarity.NewStringASCII(message.Src) + if err != nil { + return "", fmt.Errorf("failed to create srcNetwork argument: %w", err) + } + + connSnArg, err := clarity.NewUInt(message.Sn.String()) + if err != nil { + return "", fmt.Errorf("failed to create connSn argument: %w", err) + } + + msgArg, err := clarity.NewStringASCII(string(message.Data)) + if err != nil { + return "", fmt.Errorf("failed to create msg argument: %w", err) + } + + args := []clarity.ClarityValue{srcNetworkArg, connSnArg, msgArg} + + txID, err := p.client.SendCallMessage(ctx, contractAddress, args, p.cfg.Address, p.privateKey) + if err != nil { + return "", fmt.Errorf("failed to send message: %w", err) + } + + return txID, nil +} + +func (p *Provider) handleCallMessage(ctx context.Context, message *types.Message) (string, error) { + contractAddress := p.cfg.Contracts[types.XcallContract] + + reqIDArg, err := clarity.NewUInt(message.ReqID.String()) + if err != nil { + return "", fmt.Errorf("failed to create reqID argument: %w", err) + } + + dataArg, err := clarity.NewStringASCII(string(message.Data)) + if err != nil { + return "", fmt.Errorf("failed to create data argument: %w", err) + } + + args := []clarity.ClarityValue{reqIDArg, dataArg} + + txID, err := p.client.ExecuteCall(ctx, contractAddress, args, p.cfg.Address, p.privateKey) + if err != nil { + return "", fmt.Errorf("failed to execute call: %w", err) + } + + return txID, nil +} + +func (p *Provider) handleRollbackMessage(ctx context.Context, message *types.Message) (string, error) { + contractAddress := p.cfg.Contracts[types.XcallContract] + + snArg, err := clarity.NewUInt(message.Sn.String()) + if err != nil { + return "", fmt.Errorf("failed to create sn argument: %w", err) + } + + args := []clarity.ClarityValue{snArg} + + txID, err := p.client.ExecuteRollback(ctx, contractAddress, args, p.cfg.Address, p.privateKey) + if err != nil { + return "", fmt.Errorf("failed to execute rollback: %w", err) + } + + return txID, nil +} diff --git a/relayer/chains/stacks/stacks_test.go b/relayer/chains/stacks/stacks_test.go new file mode 100644 index 00000000..67c6e168 --- /dev/null +++ b/relayer/chains/stacks/stacks_test.go @@ -0,0 +1,82 @@ +package stacks_test + +import ( + "context" + "math/big" + "testing" + "time" + + "github.com/icon-project/centralized-relay/relayer/chains/stacks" + "github.com/icon-project/centralized-relay/relayer/events" + "github.com/icon-project/centralized-relay/relayer/provider" + providerTypes "github.com/icon-project/centralized-relay/relayer/types" + "github.com/stretchr/testify/assert" + "go.uber.org/zap" +) + +func setupTestStacksProvider(t *testing.T) *stacks.Provider { + logger, _ := zap.NewDevelopment() + cfg := &stacks.Config{ + CommonConfig: provider.CommonConfig{ + RPCUrl: "https://stacks-node-api.testnet.stacks.co", + Contracts: providerTypes.ContractConfigMap{ + "XcallContract": "ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH.xcall-proxy", + "ConnectionContract": "ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH.centralized-connection", + }, + NID: "stacks_testnet", + }, + } + + p, err := cfg.NewProvider(context.Background(), logger, "/tmp/relayer", false, "stacks_testnet") + assert.NoError(t, err) + assert.NotNil(t, p) + + return p.(*stacks.Provider) +} + +func TestGenerateMessages(t *testing.T) { + p := setupTestStacksProvider(t) + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) + defer cancel() + + // Trigger an event on the contract (you'll need to do this manually or automate it) + // For example, call a function on your XCall contract that emits an event + + key := &providerTypes.MessageKeyWithMessageHeight{ + Height: 12345, // Use an appropriate block height + } + + messages, err := p.GenerateMessages(ctx, key) + assert.NoError(t, err) + assert.NotEmpty(t, messages) + + for _, msg := range messages { + t.Logf("Generated message: %+v", msg) + // Add more specific assertions based on the expected event data + } +} + +func TestRoute(t *testing.T) { + p := setupTestStacksProvider(t) + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() + + message := &providerTypes.Message{ + Dst: "stacks_testnet", + Src: "icon_testnet", + Sn: big.NewInt(12345), + EventType: events.EmitMessage, + Data: []byte("Hello, Stacks!"), + } + + callback := func(key *providerTypes.MessageKey, response *providerTypes.TxResponse, err error) { + assert.NoError(t, err) + assert.NotNil(t, response) + assert.Equal(t, providerTypes.Success, response.Code) + } + + err := p.Route(ctx, message, callback) + assert.NoError(t, err) +} diff --git a/test/chains/stacks/remotenet.go b/test/chains/stacks/remotenet.go new file mode 100644 index 00000000..12bf7177 --- /dev/null +++ b/test/chains/stacks/remotenet.go @@ -0,0 +1,650 @@ +package stacks + +import ( + "context" + "fmt" + "os" + "strings" + "time" + + stacksClient "github.com/icon-project/centralized-relay/relayer/chains/stacks" + "github.com/icon-project/centralized-relay/relayer/kms" + "github.com/icon-project/centralized-relay/test/chains" + "github.com/icon-project/centralized-relay/test/interchaintest/relayer/centralized" + "github.com/icon-project/centralized-relay/test/testsuite/testconfig" + "github.com/icon-project/stacks-go-sdk/pkg/clarity" + "github.com/icon-project/stacks-go-sdk/pkg/crypto" + "github.com/icon-project/stacks-go-sdk/pkg/stacks" + "github.com/icon-project/stacks-go-sdk/pkg/transaction" + "go.uber.org/zap" + "gopkg.in/yaml.v3" +) + +type StacksLocalnet struct { + log *zap.Logger + testName string + cfg chains.ChainConfig + IBCAddresses map[string]string + Wallets map[string]string // map of keyName to private key (as hex string) + network *stacks.StacksNetwork + client *stacksClient.Client + testconfig *testconfig.Chain + kms kms.KMS +} + +func NewStacksLocalnet(testName string, log *zap.Logger, chainConfig chains.ChainConfig, testconfig *testconfig.Chain, kms kms.KMS) chains.Chain { + network := stacks.NewStacksLocalnet() + client, err := stacksClient.NewClient(log, network, testconfig.Contracts["xcall"]) + if err != nil { + log.Error("Failed to create Stacks client", zap.Error(err)) + return nil + } + + return &StacksLocalnet{ + testName: testName, + cfg: chainConfig, + log: log, + network: network, + client: client, + testconfig: testconfig, + IBCAddresses: make(map[string]string), + Wallets: make(map[string]string), + kms: kms, + } +} + +func (s *StacksLocalnet) Config() chains.ChainConfig { + return s.cfg +} + +func (s *StacksLocalnet) Height(ctx context.Context) (uint64, error) { + block, err := s.client.GetLatestBlock(ctx) + if err != nil { + return 0, err + } + return uint64(block.Height), nil +} + +func (s *StacksLocalnet) GetRelayConfig(ctx context.Context, rlyHome string, keyName string) ([]byte, error) { + contracts := make(map[string]string) + contracts["xcall"] = s.GetContractAddress("xcall") + contracts["connection"] = s.GetContractAddress("connection") + + config := ¢ralized.StacksRelayerChainConfig{ + Type: "stacks", + Value: centralized.StacksRelayerChainConfigValue{ + RPCURL: s.testconfig.RPCUri, + StartHeight: 0, + Contracts: contracts, + BlockInterval: "6s", + Address: s.testconfig.RelayWalletAddress, + FinalityBlock: 10, + }, + } + return yaml.Marshal(config) +} + +func (s *StacksLocalnet) GetContractAddress(key string) string { + value, exist := s.IBCAddresses[key] + if !exist { + panic(fmt.Sprintf("IBC address does not exist: %s", key)) + } + return value +} + +func (s *StacksLocalnet) SetupXCall(ctx context.Context) error { + if s.testconfig.Environment == "preconfigured" { + testcase := ctx.Value("testcase").(string) + s.IBCAddresses["xcall"] = "STXCALLPROXYADDRESS" + s.IBCAddresses["connection"] = "STXCONNECTIONADDRESS" + s.IBCAddresses[fmt.Sprintf("dapp-%s", testcase)] = "STXDAPPADDRESS" + return nil + } + + privateKey, senderAddress, err := s.loadPrivateKey(s.testconfig.KeystoreFile, s.testconfig.KeystorePassword) + if err != nil { + return fmt.Errorf("failed to load deployer's private key: %w", err) + } + + xcallContractName := "xcall-proxy" + codeBody, err := os.ReadFile(s.testconfig.Contracts["xcall"]) + if err != nil { + return fmt.Errorf("failed to read xcall contract code: %w", err) + } + + tx, err := transaction.MakeContractDeploy( + xcallContractName, + string(codeBody), + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create contract deploy transaction: %w", err) + } + + txID, err := transaction.BroadcastTransaction(tx, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast transaction: %w", err) + } + + s.log.Info("Deployed xcall-proxy contract", zap.String("txID", txID)) + + contractAddress := senderAddress + "." + xcallContractName + s.IBCAddresses["xcall"] = contractAddress + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return err + } + + return nil +} + +func (s *StacksLocalnet) SetupConnection(ctx context.Context, target chains.Chain) error { + if s.testconfig.Environment == "preconfigured" { + return nil + } + + privateKey, senderAddress, err := s.loadPrivateKey(s.testconfig.KeystoreFile, s.testconfig.KeystorePassword) + if err != nil { + return fmt.Errorf("failed to load deployer's private key: %w", err) + } + + connectionContractName := "centralized-connection" + codeBody, err := os.ReadFile(s.testconfig.Contracts["connection"]) + if err != nil { + return fmt.Errorf("failed to read connection contract code: %w", err) + } + + tx, err := transaction.MakeContractDeploy( + connectionContractName, + string(codeBody), + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create contract deploy transaction: %w", err) + } + + txID, err := transaction.BroadcastTransaction(tx, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast transaction: %w", err) + } + + s.log.Info("Deployed centralized-connection contract", zap.String("txID", txID)) + + contractAddress := senderAddress + "." + connectionContractName + s.IBCAddresses["connection"] = contractAddress + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return err + } + + xcallAddress := s.IBCAddresses["xcall"] + relayerAddress := s.testconfig.RelayWalletAddress + + xcallPrincipal, err := clarity.StringToPrincipal(xcallAddress) + if err != nil { + return fmt.Errorf("invalid xcall address: %w", err) + } + relayerPrincipal, err := clarity.StringToPrincipal(relayerAddress) + if err != nil { + return fmt.Errorf("invalid relayer address: %w", err) + } + + args := []clarity.ClarityValue{xcallPrincipal, relayerPrincipal} + + txCall, err := transaction.MakeContractCall( + senderAddress, + connectionContractName, + "initialize", + args, + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create contract call transaction: %w", err) + } + + txID, err = transaction.BroadcastTransaction(txCall, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast transaction: %w", err) + } + + s.log.Info("Initialized centralized-connection contract", zap.String("txID", txID)) + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return err + } + + return nil +} + +func (s *StacksLocalnet) DeployXCallMockApp(ctx context.Context, keyName string, connections []chains.XCallConnection) error { + if s.testconfig.Environment == "preconfigured" { + return nil + } + + testcase := ctx.Value("testcase").(string) + appContractName := "xcall-mock-app-" + testcase + + codeBody, err := os.ReadFile(s.testconfig.Contracts["dapp"]) + if err != nil { + return fmt.Errorf("failed to read dapp contract code: %w", err) + } + + privateKey, senderAddress, err := s.loadPrivateKey(s.testconfig.KeystoreFile, s.testconfig.KeystorePassword) + if err != nil { + return fmt.Errorf("failed to load deployer's private key: %w", err) + } + + tx, err := transaction.MakeContractDeploy( + appContractName, + string(codeBody), + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create contract deploy transaction: %w", err) + } + + txID, err := transaction.BroadcastTransaction(tx, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast transaction: %w", err) + } + + s.log.Info("Deployed xcall mock app contract", zap.String("txID", txID)) + + contractAddress := senderAddress + "." + appContractName + s.IBCAddresses[fmt.Sprintf("dapp-%s", testcase)] = contractAddress + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return err + } + + xcallAddress := s.IBCAddresses["xcall"] + xcallPrincipal, err := clarity.StringToPrincipal(xcallAddress) + if err != nil { + return fmt.Errorf("invalid xcall address: %w", err) + } + + args := []clarity.ClarityValue{xcallPrincipal} + + txCall, err := transaction.MakeContractCall( + senderAddress, + appContractName, + "initialize", + args, + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create contract call transaction: %w", err) + } + + txID, err = transaction.BroadcastTransaction(txCall, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast transaction: %w", err) + } + + s.log.Info("Initialized xcall mock app contract", zap.String("txID", txID)) + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return err + } + + for _, connection := range connections { + connPrincipal, err := clarity.StringToPrincipal(s.IBCAddresses[connection.Connection]) + if err != nil { + s.log.Error("Invalid connection address", zap.Error(err), zap.String("address", s.IBCAddresses[connection.Connection])) + continue + } + + nidArg, err := clarity.NewStringASCII(connection.Nid) + if err != nil { + s.log.Error("Failed to create nid argument", zap.Error(err)) + continue + } + + destArg, err := clarity.NewStringASCII(connection.Destination) + if err != nil { + s.log.Error("Failed to create destination argument", zap.Error(err)) + continue + } + + args := []clarity.ClarityValue{ + nidArg, + connPrincipal, + destArg, + } + + txCall, err := transaction.MakeContractCall( + senderAddress, + appContractName, + "add-connection", + args, + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + s.log.Error("Failed to create contract call transaction", zap.Error(err)) + continue + } + + txID, err = transaction.BroadcastTransaction(txCall, s.network) + if err != nil { + s.log.Error("Failed to broadcast transaction", zap.Error(err)) + continue + } + + s.log.Info("Added connection to xcall mock app", zap.String("txID", txID)) + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + s.log.Error("Failed to confirm transaction", zap.Error(err)) + continue + } + } + + return nil +} + +func (s *StacksLocalnet) SendPacketXCall(ctx context.Context, keyName, _to string, data, rollback []byte) (context.Context, error) { + testcase := ctx.Value("testcase").(string) + dappKey := fmt.Sprintf("dapp-%s", testcase) + dappAddress := s.IBCAddresses[dappKey] + + privateKey, senderAddress, err := s.loadPrivateKey(s.testconfig.KeystoreFile, s.testconfig.KeystorePassword) + if err != nil { + return nil, fmt.Errorf("failed to load user's private key: %w", err) + } + + toArg, err := clarity.NewStringASCII(_to) + if err != nil { + return nil, fmt.Errorf("failed to create 'to' argument: %w", err) + } + + dataArg := clarity.NewBuffer(data) + rollbackArg := clarity.NewBuffer(rollback) + + args := []clarity.ClarityValue{ + toArg, + dataArg, + rollbackArg, + } + + txCall, err := transaction.MakeContractCall( + senderAddress, + dappAddress, + "send-message", + args, + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return nil, fmt.Errorf("failed to create contract call transaction: %w", err) + } + + txID, err := transaction.BroadcastTransaction(txCall, s.network) + if err != nil { + return nil, fmt.Errorf("failed to broadcast transaction: %w", err) + } + + s.log.Info("Sent message via xcall mock app", zap.String("txID", txID)) + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return nil, err + } + + // TODO: Extract 'sn' (serial number) from transaction events + // For now, we return the txID in context + ctx = context.WithValue(ctx, "txID", txID) + return ctx, nil +} + +func (s *StacksLocalnet) FindCallMessage(ctx context.Context, startHeight uint64, from, to, sn string) (string, string, error) { + foundChan := make(chan struct { + txID string + data string + }, 1) + + callback := func(eventType string, data interface{}) error { + if eventType == stacksClient.CallMessage { + if callMsg, ok := data.(stacksClient.CallMessageEvent); ok { + if callMsg.Sn == sn { + foundChan <- struct { + txID string + data string + }{ + txID: callMsg.ReqID, + data: callMsg.Data, + } + } + } + } + return nil + } + + err := s.client.SubscribeToEvents(ctx, []string{stacksClient.CallMessage}, callback) + if err != nil { + return "", "", fmt.Errorf("failed to subscribe to events: %w", err) + } + + select { + case found := <-foundChan: + return found.txID, found.data, nil + case <-time.After(2 * time.Minute): + return "", "", fmt.Errorf("find call message timed out") + case <-ctx.Done(): + return "", "", ctx.Err() + } +} + +func (s *StacksLocalnet) FindCallResponse(ctx context.Context, startHeight uint64, sn string) (string, error) { + foundChan := make(chan string, 1) + + callback := func(eventType string, data interface{}) error { + if eventType == stacksClient.CallMessage { + if callMsg, ok := data.(stacksClient.CallMessageEvent); ok { + if callMsg.Sn == sn { + foundChan <- callMsg.ReqID + } + } + } + return nil + } + + err := s.client.SubscribeToEvents(ctx, []string{stacksClient.CallMessage}, callback) + if err != nil { + return "", fmt.Errorf("failed to subscribe to events: %w", err) + } + + select { + case txID := <-foundChan: + return txID, nil + case <-time.After(2 * time.Minute): + return "", fmt.Errorf("find call response timed out") + case <-ctx.Done(): + return "", ctx.Err() + } +} + +func (s *StacksLocalnet) FindRollbackExecutedMessage(ctx context.Context, startHeight uint64, sn string) (string, error) { + foundChan := make(chan string, 1) + + callback := func(eventType string, data interface{}) error { + if eventType == stacksClient.RollbackMessage { + if rollbackMsg, ok := data.(stacksClient.RollbackMessageEvent); ok { + if rollbackMsg.Sn == sn { + foundChan <- rollbackMsg.Sn + } + } + } + return nil + } + + err := s.client.SubscribeToEvents(ctx, []string{stacksClient.RollbackMessage}, callback) + if err != nil { + return "", fmt.Errorf("failed to subscribe to events: %w", err) + } + + select { + case txID := <-foundChan: + return txID, nil + case <-time.After(2 * time.Minute): + return "", fmt.Errorf("find rollback message timed out") + case <-ctx.Done(): + return "", ctx.Err() + } +} + +func (s *StacksLocalnet) FindTargetXCallMessage(ctx context.Context, target chains.Chain, height uint64, to string) (*chains.XCallResponse, error) { + foundChan := make(chan *chains.XCallResponse, 1) + + callback := func(eventType string, data interface{}) error { + if eventType == stacksClient.EmitMessage { + if emitMsg, ok := data.(stacksClient.EmitMessageEvent); ok { + if emitMsg.TargetNetwork == to { + foundChan <- &chains.XCallResponse{ + SerialNo: emitMsg.Sn, + Data: emitMsg.Msg, + // RequestID isn't in EmitMessageEvent, will be empty + } + } + } + } else if eventType == stacksClient.CallMessage { + if callMsg, ok := data.(stacksClient.CallMessageEvent); ok { + foundChan <- &chains.XCallResponse{ + SerialNo: callMsg.Sn, + RequestID: callMsg.ReqID, + Data: callMsg.Data, + } + } + } + return nil + } + + err := s.client.SubscribeToEvents(ctx, []string{stacksClient.EmitMessage, stacksClient.CallMessage}, callback) + if err != nil { + return nil, fmt.Errorf("failed to subscribe to events: %w", err) + } + + select { + case response := <-foundChan: + return response, nil + case <-time.After(2 * time.Minute): + return nil, fmt.Errorf("find target message timed out") + case <-ctx.Done(): + return nil, ctx.Err() + } +} + +func (s *StacksLocalnet) loadPrivateKey(keystoreFile, password string) ([]byte, string, error) { + if s.kms == nil { + return nil, "", fmt.Errorf("KMS not initialized") + } + + encryptedKey, err := os.ReadFile(keystoreFile) + if err != nil { + s.log.Error("Failed to read keystore file", + zap.String("path", keystoreFile), + zap.Error(err)) + return nil, "", fmt.Errorf("failed to read keystore file: %w", err) + } + + privateKey, err := s.kms.Decrypt(context.Background(), encryptedKey) + if err != nil { + s.log.Error("Failed to decrypt keystore", zap.Error(err)) + return nil, "", fmt.Errorf("failed to decrypt keystore: %w", err) + } + + network, err := stacksClient.MapNIDToChainID(s.cfg.ChainID) + if err != nil { + s.log.Error("Chain id not found. Check the NID config", zap.Error(err)) + return nil, "", fmt.Errorf("chain id not found: %w", err) + } + + address, err := crypto.GetAddressFromPrivateKey(privateKey, network) + if err != nil { + s.log.Error("Failed to derive address from private key", zap.Error(err)) + return nil, "", fmt.Errorf("failed to derive address: %w", err) + } + + return privateKey, address, nil +} + +func (s *StacksLocalnet) XCall(ctx context.Context, targetChain chains.Chain, keyName, _to string, data, rollback []byte) (*chains.XCallResponse, error) { + height, err := targetChain.Height(ctx) + if err != nil { + return nil, err + } + + ctx, err = s.SendPacketXCall(ctx, keyName, _to, data, rollback) + if err != nil { + return nil, err + } + + return s.FindTargetXCallMessage(ctx, targetChain, height, strings.Split(_to, "/")[1]) +} + +func (s *StacksLocalnet) waitForTransactionConfirmation(ctx context.Context, txID string) error { + timeout := time.After(2 * time.Minute) + ticker := time.NewTicker(2 * time.Second) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + res, err := s.client.GetTransactionById(ctx, txID) + if err != nil { + s.log.Warn("Failed to query transaction receipt", zap.Error(err)) + continue + } + + receipt, err := stacksClient.GetReceipt(res) + if err != nil { + s.log.Warn("Failed to extract transaction receipt", zap.Error(err)) + continue + } + + if receipt.Status { + s.log.Info("Transaction confirmed", + zap.String("txID", txID), + zap.Uint64("height", receipt.Height)) + return nil + } + s.log.Debug("Transaction not yet confirmed", zap.String("txID", txID)) + + case <-timeout: + return fmt.Errorf("transaction confirmation timed out after 2 minutes") + case <-ctx.Done(): + return ctx.Err() + } + } +} From 9124403eb9c48d43b238636ad291ed4d15fc5351 Mon Sep 17 00:00:00 2001 From: CyrusVorwald <90732384+CyrusVorwald@users.noreply.github.com> Date: Wed, 6 Nov 2024 19:54:53 -0500 Subject: [PATCH 2/9] feat: stacks integration --- go.mod | 25 +++--- go.sum | 76 ++++++++++++++++--- go.work | 4 +- relayer/chains/stacks/query.go | 23 ++++-- relayer/chains/stacks/stacks_test.go | 13 ++-- test/go.mod | 2 +- .../centralized/centralized_relayer.go | 14 ++++ 7 files changed, 118 insertions(+), 39 deletions(-) diff --git a/go.mod b/go.mod index 2c822c2b..3657c652 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/icon-project/centralized-relay -go 1.22 +go 1.23 + +toolchain go1.23.1 require ( github.com/CosmWasm/wasmd v0.52.0 @@ -14,6 +16,7 @@ require ( github.com/gofrs/flock v0.8.1 github.com/gorilla/websocket v1.5.3 github.com/icon-project/goloop v1.3.11 + github.com/icon-project/stacks-go-sdk v0.3.1 github.com/json-iterator/go v1.1.12 github.com/jsternberg/zap-logfmt v1.3.0 github.com/near/borsh-go v0.3.1 @@ -25,7 +28,7 @@ require ( github.com/stretchr/testify v1.9.0 github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d go.uber.org/zap v1.27.0 - golang.org/x/sync v0.7.0 + golang.org/x/sync v0.8.0 google.golang.org/grpc v1.64.0 gopkg.in/yaml.v3 v3.0.1 @@ -37,6 +40,8 @@ require ( contrib.go.opencensus.io/exporter/prometheus v0.4.2 // indirect cosmossdk.io/x/upgrade v0.1.3 // indirect github.com/CosmWasm/wasmvm/v2 v2.1.0 // indirect + github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect + github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect github.com/VictoriaMetrics/fastcache v1.12.2 // indirect github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.9 // indirect @@ -75,6 +80,7 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.12.0 // indirect + github.com/go-resty/resty/v2 v2.14.0 // indirect github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect @@ -110,6 +116,7 @@ require ( github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/tinylib/msgp v1.1.9 // indirect + github.com/tyler-smith/go-bip32 v1.0.0 // indirect github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect @@ -125,8 +132,8 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect - golang.org/x/net v0.26.0 // indirect - golang.org/x/time v0.5.0 // indirect + golang.org/x/net v0.27.0 // indirect + golang.org/x/time v0.6.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/protobuf v1.34.1 // indirect gopkg.in/go-playground/validator.v9 v9.31.0 // indirect @@ -166,7 +173,7 @@ require ( github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/bits-and-blooms/bitset v1.13.0 // indirect - github.com/btcsuite/btcd/btcec/v2 v2.3.3 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -288,11 +295,11 @@ require ( github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v0.14.3 // indirect go.etcd.io/bbolt v1.3.8 // indirect - golang.org/x/crypto v0.25.0 // indirect + golang.org/x/crypto v0.26.0 // indirect golang.org/x/oauth2 v0.20.0 // indirect - golang.org/x/sys v0.22.0 // indirect - golang.org/x/term v0.22.0 // indirect - golang.org/x/text v0.16.0 // indirect + golang.org/x/sys v0.23.0 // indirect + golang.org/x/term v0.23.0 // indirect + golang.org/x/text v0.17.0 // indirect google.golang.org/api v0.180.0 // indirect google.golang.org/genproto v0.0.0-20240513163218-0867130af1f8 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8 // indirect diff --git a/go.sum b/go.sum index 91f9575e..ee7a9924 100644 --- a/go.sum +++ b/go.sum @@ -239,6 +239,10 @@ github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dX github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e h1:ahyvB3q25YnZWly5Gq1ekg6jcmWaGj/vG/MhF4aisoc= +github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec h1:1Qb69mGp/UtRPn422BH4/Y4Q3SLUrD9KHuDkm8iodFc= +github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec/go.mod h1:CD8UlnlLDiqb36L110uqiP2iSflVjx9g/3U9hCI4q2U= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= @@ -336,8 +340,8 @@ github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd h1:js1gPwhcFflTZ7 github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A= github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= -github.com/btcsuite/btcd/btcec/v2 v2.3.3 h1:6+iXlDKE8RMtKsvK0gshlXIuPbyWM/h84Ensb7o3sC0= -github.com/btcsuite/btcd/btcec/v2 v2.3.3/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8= @@ -389,6 +393,8 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e h1:0XBUw73chJ1VYSsfvcPvVT7auykAJce9FpRr10L6Qhw= +github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -625,6 +631,8 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.12.0 h1:E4gtWgxWxp8YSxExrQFv5BpCahla0PVF2oTTEYaWQGI= github.com/go-playground/validator/v10 v10.12.0/go.mod h1:hCAPuzYvKdP33pxWa+2+6AIKXEKqjIUyqsNCtbsSJrA= +github.com/go-resty/resty/v2 v2.14.0 h1:/rhkzsAqGQkozwfKS5aFAbb6TyKd3zyFRWcdRXLPCAU= +github.com/go-resty/resty/v2 v2.14.0/go.mod h1:IW6mekUOsElt9C7oWr0XRt9BNSD6D5rr9mhk6NjmNHg= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= @@ -872,6 +880,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/icon-project/goloop v1.3.11 h1:Lry7rCM9QeZudiAqi7n7CqmoOsg7qNDwrw6O12j7vuo= github.com/icon-project/goloop v1.3.11/go.mod h1:9PoWRb5kowidc9jYy0RLuLpay1zT5FXgEKijx7rDQjE= +github.com/icon-project/stacks-go-sdk v0.3.1 h1:tw7sz9P6HICG+sclTCFs2wgYs1I5Xom3QZLhRXJOOIw= +github.com/icon-project/stacks-go-sdk v0.3.1/go.mod h1:yg4j/KACqhZ7+ZR0zpf3tE6Vw6HiZKBpFtVFzZlaGKw= github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= @@ -1248,6 +1258,7 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.1.5-0.20170601210322-f6abca593680/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 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= @@ -1287,6 +1298,8 @@ github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/tyler-smith/go-bip32 v1.0.0 h1:sDR9juArbUgX+bO/iblgZnMPeWY1KZMUC2AFUJdv5KE= +github.com/tyler-smith/go-bip32 v1.0.0/go.mod h1:onot+eHknzV4BVPwrzqY5OoVpyCvnwD7lMawL5aQupE= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= @@ -1402,6 +1415,7 @@ go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/crypto v0.0.0-20170613210332-850760c427c5/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1417,8 +1431,12 @@ golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1458,6 +1476,10 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1521,8 +1543,13 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1564,8 +1591,12 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1667,16 +1698,28 @@ golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= +golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1688,14 +1731,20 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= +golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1757,6 +1806,9 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2052,6 +2104,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087 h1:Izowp2XBH6Ya6rv+hqbceQyw/gSGoXfH/UPoTGduL54= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw= diff --git a/go.work b/go.work index 3941f4b2..093f3031 100644 --- a/go.work +++ b/go.work @@ -1,6 +1,6 @@ -go 1.22.2 +go 1.23 -toolchain go1.22.5 +toolchain go1.23.1 use ( . diff --git a/relayer/chains/stacks/query.go b/relayer/chains/stacks/query.go index fda5cef1..90e59adb 100644 --- a/relayer/chains/stacks/query.go +++ b/relayer/chains/stacks/query.go @@ -121,14 +121,10 @@ func GetReceipt(tx interface{}) (*providerTypes.Receipt, error) { return nil, fmt.Errorf("no non-nil transaction field found") } -func (p *Provider) GenerateMessages(ctx context.Context, key *providerTypes.MessageKeyWithMessageHeight) ([]*providerTypes.Message, error) { - p.log.Info("Generating messages", zap.Any("messagekey", key)) - if key == nil { - return nil, fmt.Errorf("GenerateMessages: message key cannot be nil") - } +func (p *Provider) GenerateMessages(ctx context.Context, fromHeight uint64, toHeight uint64) ([]*providerTypes.Message, error) { + p.log.Info("Generating messages", zap.Uint64("fromHeight", fromHeight), zap.Uint64("toHeight", toHeight)) eventTypes := p.getSubscribedEventTypes() - var messages []*providerTypes.Message errChan := make(chan error, 1) @@ -139,8 +135,7 @@ func (p *Provider) GenerateMessages(ctx context.Context, key *providerTypes.Mess return err } - msg.MessageHeight = key.Height - + msg.MessageHeight = fromHeight messages = append(messages, msg) return nil } @@ -164,3 +159,15 @@ func (p *Provider) GenerateMessages(ctx context.Context, key *providerTypes.Mess return messages, nil } + +func (p *Provider) FetchTxMessages(ctx context.Context, txHash string) ([]*providerTypes.Message, error) { + p.log.Info("Fetching messages from transaction", zap.String("txHash", txHash)) + + receipt, err := p.QueryTransactionReceipt(ctx, txHash) + if err != nil { + return nil, fmt.Errorf("failed to get transaction receipt: %w", err) + } + + // Pass the same height for both from and to since we're looking at a specific transaction + return p.GenerateMessages(ctx, receipt.Height, receipt.Height) +} diff --git a/relayer/chains/stacks/stacks_test.go b/relayer/chains/stacks/stacks_test.go index 67c6e168..7fc377dd 100644 --- a/relayer/chains/stacks/stacks_test.go +++ b/relayer/chains/stacks/stacks_test.go @@ -40,20 +40,17 @@ func TestGenerateMessages(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) defer cancel() - // Trigger an event on the contract (you'll need to do this manually or automate it) - // For example, call a function on your XCall contract that emits an event + fromHeight := uint64(12345) + toHeight := uint64(12345) - key := &providerTypes.MessageKeyWithMessageHeight{ - Height: 12345, // Use an appropriate block height - } - - messages, err := p.GenerateMessages(ctx, key) + messages, err := p.GenerateMessages(ctx, fromHeight, toHeight) assert.NoError(t, err) assert.NotEmpty(t, messages) for _, msg := range messages { t.Logf("Generated message: %+v", msg) - // Add more specific assertions based on the expected event data + assert.GreaterOrEqual(t, msg.MessageHeight, fromHeight) + assert.LessOrEqual(t, msg.MessageHeight, toHeight) } } diff --git a/test/go.mod b/test/go.mod index d336d006..1f501606 100644 --- a/test/go.mod +++ b/test/go.mod @@ -1,6 +1,6 @@ module github.com/icon-project/centralized-relay/test -go 1.22.0 +go 1.23 require ( github.com/BurntSushi/toml v1.3.2 diff --git a/test/interchaintest/relayer/centralized/centralized_relayer.go b/test/interchaintest/relayer/centralized/centralized_relayer.go index 31c42cd4..c70d75f2 100644 --- a/test/interchaintest/relayer/centralized/centralized_relayer.go +++ b/test/interchaintest/relayer/centralized/centralized_relayer.go @@ -154,6 +154,15 @@ type SolanaRelayerChainConfigValue struct { StartHeight uint64 `yaml:"start-height"` } +type StacksRelayerChainConfigValue struct { + RPCURL string `yaml:"rpc-url"` + StartHeight int `yaml:"start-height"` + Contracts map[string]string `yaml:"contracts"` + BlockInterval string `yaml:"block-interval"` + Address string `yaml:"address"` + FinalityBlock uint64 `yaml:"finality-block"` +} + type ICONRelayerChainConfig struct { Type string `json:"type"` Value ICONRelayerChainConfigValue `json:"value"` @@ -183,6 +192,11 @@ type StellarRelayerChainConfig struct { Value StellarRelayerChainConfigValue `json:"value"` } +type StacksRelayerChainConfig struct { + Type string `yaml:"type"` + Value StacksRelayerChainConfigValue `yaml:"value"` +} + const ( DefaultContainerImage = "centralized-relay" DefaultContainerVersion = "latest" From d74387140a79e6ac9c17c364ce02b71de99ca1cc Mon Sep 17 00:00:00 2001 From: CyrusVorwald <90732384+CyrusVorwald@users.noreply.github.com> Date: Wed, 6 Nov 2024 22:01:48 -0500 Subject: [PATCH 3/9] feat(stacks): add provider unit tests --- relayer/chains/stacks/client_test.go | 46 +- relayer/chains/stacks/keys.go | 2 +- relayer/chains/stacks/provider.go | 13 +- relayer/chains/stacks/provider_test.go | 728 +++++++++++++++++++++++++ relayer/chains/stacks/query.go | 21 +- relayer/chains/stacks/route.go | 2 +- 6 files changed, 782 insertions(+), 30 deletions(-) create mode 100644 relayer/chains/stacks/provider_test.go diff --git a/relayer/chains/stacks/client_test.go b/relayer/chains/stacks/client_test.go index b9a62d36..6a2b2bba 100644 --- a/relayer/chains/stacks/client_test.go +++ b/relayer/chains/stacks/client_test.go @@ -5,7 +5,9 @@ import ( "encoding/hex" "path/filepath" "strings" + "sync" "testing" + "time" "github.com/icon-project/centralized-relay/relayer/chains/stacks" "github.com/icon-project/stacks-go-sdk/pkg/clarity" @@ -177,29 +179,31 @@ func TestClient_SetAdmin(t *testing.T) { t.Logf("SetAdmin transaction ID: %s", txID) } -// func TestClient_SubscribeToEvents(t *testing.T) { -// ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) -// defer cancel() +func TestClient_SubscribeToEvents(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() -// logger, _ := zap.NewDevelopment() -// client, err := stacks.NewClient("https://api.testnet.hiro.so", logger) -// if err != nil { -// t.Fatalf("Failed to create client: %v", err) -// } + logger, _ := zap.NewDevelopment() + network := stacksSdk.NewStacksTestnet() + xcallAbiPath := filepath.Join("abi", "xcall-proxy-abi.json") + client, err := stacks.NewClient(logger, network, xcallAbiPath) + if err != nil { + t.Fatalf("Failed to create client: %v", err) + } -// var wg sync.WaitGroup -// wg.Add(1) + var wg sync.WaitGroup + wg.Add(1) -// callback := func(eventType string, data interface{}) error { -// t.Logf("Received event: %s, Data: %+v", eventType, data) -// wg.Done() -// return nil -// } + callback := func(eventType string, data interface{}) error { + t.Logf("Received event: %s, Data: %+v", eventType, data) + wg.Done() + return nil + } -// err = client.SubscribeToEvents(ctx, []string{"block"}, callback) -// if err != nil { -// t.Fatalf("Failed to subscribe to events: %v", err) -// } + err = client.SubscribeToEvents(ctx, []string{"block"}, callback) + if err != nil { + t.Fatalf("Failed to subscribe to events: %v", err) + } -// wg.Wait() -// } + wg.Wait() +} diff --git a/relayer/chains/stacks/keys.go b/relayer/chains/stacks/keys.go index 0328e0e4..94da0b05 100644 --- a/relayer/chains/stacks/keys.go +++ b/relayer/chains/stacks/keys.go @@ -39,7 +39,7 @@ func (p *Provider) NewKeystore(passphrase string) (string, error) { p.log.Error("Failed to generate new private key", zap.Error(err)) return "", fmt.Errorf("failed to generate new private key: %w", err) } - privateKeyBytes := newKey.Serialize() + privateKeyBytes := append(newKey.Serialize(), byte(0x01)) network, err := MapNIDToChainID(p.cfg.NID) if err != nil { diff --git a/relayer/chains/stacks/provider.go b/relayer/chains/stacks/provider.go index 28edfdb5..efc2e865 100644 --- a/relayer/chains/stacks/provider.go +++ b/relayer/chains/stacks/provider.go @@ -18,6 +18,9 @@ import ( "github.com/icon-project/stacks-go-sdk/pkg/stacks" ) +const BLOCK_TIME = 5 * time.Second +const MAX_WAIT_TIME = 3 * BLOCK_TIME + type Config struct { provider.CommonConfig `json:",inline" yaml:",inline"` } @@ -143,7 +146,7 @@ func (p *Provider) SetAdmin(ctx context.Context, newAdmin string) error { p.log.Info("SetAdmin transaction broadcasted", zap.String("txID", txID)) - receipt, err := p.waitForTransactionConfirmation(ctx, txID) + receipt, err := p.waitForTransactionConfirmation(ctx, txID, MAX_WAIT_TIME) if err != nil { return fmt.Errorf("failed to confirm SetAdmin transaction: %w", err) } @@ -159,9 +162,9 @@ func (p *Provider) SetAdmin(ctx context.Context, newAdmin string) error { return nil } -func (p *Provider) waitForTransactionConfirmation(ctx context.Context, txID string) (*types.Receipt, error) { - timeout := time.After(2 * time.Minute) - ticker := time.NewTicker(10 * time.Second) +func (p *Provider) waitForTransactionConfirmation(ctx context.Context, txID string, timeoutDuration time.Duration) (*types.Receipt, error) { + timeout := time.After(timeoutDuration) + ticker := time.NewTicker(time.Second) defer ticker.Stop() for { @@ -178,7 +181,7 @@ func (p *Provider) waitForTransactionConfirmation(ctx context.Context, txID stri } p.log.Debug("Transaction not yet confirmed", zap.String("txID", txID)) case <-timeout: - return nil, fmt.Errorf("transaction confirmation timed out after 2 minutes") + return nil, fmt.Errorf("transaction confirmation timed out after %v", timeoutDuration) case <-ctx.Done(): return nil, ctx.Err() } diff --git a/relayer/chains/stacks/provider_test.go b/relayer/chains/stacks/provider_test.go new file mode 100644 index 00000000..574826b7 --- /dev/null +++ b/relayer/chains/stacks/provider_test.go @@ -0,0 +1,728 @@ +package stacks + +import ( + "context" + "fmt" + "math/big" + "os" + "path/filepath" + "testing" + "time" + + "github.com/icon-project/centralized-relay/relayer/chains/stacks/mocks" + "github.com/icon-project/centralized-relay/relayer/events" + "github.com/icon-project/centralized-relay/relayer/provider" + providerTypes "github.com/icon-project/centralized-relay/relayer/types" + "github.com/icon-project/stacks-go-sdk/pkg/clarity" + blockchainApiClient "github.com/icon-project/stacks-go-sdk/pkg/stacks_blockchain_api_client" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "go.uber.org/zap" +) + +func setupTestProvider(t *testing.T) (*Provider, *mocks.MockClient) { + logger, _ := zap.NewDevelopment() + mockClient := new(mocks.MockClient) + + cfg := &Config{ + CommonConfig: provider.CommonConfig{ + RPCUrl: "https://stacks-node-api.testnet.stacks.co", + Contracts: providerTypes.ContractConfigMap{ + providerTypes.XcallContract: "ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH.xcall-proxy", + providerTypes.ConnectionContract: "ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH.centralized-connection", + }, + NID: "stacks_testnet", + ChainName: "stacks_testnet", + }, + } + + p, err := cfg.NewProvider(context.Background(), logger, "/tmp/relayer", false, "stacks_testnet") + assert.NoError(t, err) + + provider := p.(*Provider) + provider.client = mockClient + + return provider, mockClient +} + +func TestProvider_Init(t *testing.T) { + provider, _ := setupTestProvider(t) + mockKMS := new(mocks.MockKMS) + + err := provider.Init(context.Background(), "/tmp/relayer", mockKMS) + assert.NoError(t, err) + assert.Equal(t, mockKMS, provider.kms) +} + +func TestProvider_QueryLatestHeight(t *testing.T) { + provider, mockClient := setupTestProvider(t) + + expectedHeight := uint64(1234) + mockBlock := &blockchainApiClient.GetBlocks200ResponseResultsInner{ + Height: int32(expectedHeight), + } + + mockClient.On("GetLatestBlock", mock.Anything).Return(mockBlock, nil) + + height, err := provider.QueryLatestHeight(context.Background()) + assert.NoError(t, err) + assert.Equal(t, expectedHeight, height) + + mockClient.AssertExpectations(t) +} + +func TestProvider_QueryBalance(t *testing.T) { + provider, mockClient := setupTestProvider(t) + + address := "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM" + expectedBalance := big.NewInt(1000000) + + mockClient.On("GetAccountBalance", mock.Anything, address).Return(expectedBalance, nil) + + balance, err := provider.QueryBalance(context.Background(), address) + assert.NoError(t, err) + assert.Equal(t, uint64(1000000), balance.Amount) + assert.Equal(t, "STX", balance.Denom) + + mockClient.AssertExpectations(t) +} + +func TestProvider_GetFee(t *testing.T) { + provider, mockClient := setupTestProvider(t) + + networkID := "icon" + expectedFee := uint64(1000) + + mockClient.On("GetFee", mock.Anything, provider.cfg.Contracts[providerTypes.ConnectionContract], networkID, true). + Return(expectedFee, nil) + + fee, err := provider.GetFee(context.Background(), networkID, true) + assert.NoError(t, err) + assert.Equal(t, expectedFee, fee) + + mockClient.AssertExpectations(t) +} + +func TestProvider_SetFee(t *testing.T) { + provider, mockClient := setupTestProvider(t) + + networkID := "icon" + msgFee := big.NewInt(1000) + resFee := big.NewInt(500) + expectedTxID := "0x123456789" + + mockClient.On("SetFee", + mock.Anything, + provider.cfg.Contracts[providerTypes.ConnectionContract], + networkID, + msgFee, + resFee, + provider.cfg.Address, + provider.privateKey, + ).Return(expectedTxID, nil) + + err := provider.SetFee(context.Background(), networkID, msgFee, resFee) + assert.NoError(t, err) + + mockClient.AssertExpectations(t) +} + +func TestProvider_ClaimFee(t *testing.T) { + provider, mockClient := setupTestProvider(t) + + expectedTxID := "0x123456789" + + mockClient.On("ClaimFee", + mock.Anything, + provider.cfg.Contracts[providerTypes.ConnectionContract], + provider.cfg.Address, + provider.privateKey, + ).Return(expectedTxID, nil) + + err := provider.ClaimFee(context.Background()) + assert.NoError(t, err) + + mockClient.AssertExpectations(t) +} + +func TestProvider_SetAdmin(t *testing.T) { + provider, mockClient := setupTestProvider(t) + + newAdmin := "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM" + expectedTxID := "0x123456789" + + var hash160 [20]byte + copy(hash160[:], []byte("ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH")) + currentImpl, err := clarity.NewContractPrincipal(0, hash160, "xcall-impl") + assert.NoError(t, err) + + mockClient.On("GetCurrentImplementation", mock.Anything, provider.cfg.Contracts[providerTypes.XcallContract]). + Return(currentImpl, nil).Once() + + mockClient.On("SetAdmin", + mock.Anything, + provider.cfg.Contracts[providerTypes.XcallContract], + newAdmin, + currentImpl, + provider.cfg.Address, + provider.privateKey, + ).Return(expectedTxID, nil).Once() + + successStatus := "success" + mockResponse := &blockchainApiClient.GetTransactionById200Response{ + GetTransactionList200ResponseResultsInner: &blockchainApiClient.GetTransactionList200ResponseResultsInner{ + ContractCallTransaction: &blockchainApiClient.ContractCallTransaction{ + TxId: expectedTxID, + BlockHeight: 1234, + TxStatus: blockchainApiClient.TokenTransferTransactionTxStatus{ + String: &successStatus, + }, + Canonical: true, + }, + }, + } + mockClient.On("GetTransactionById", mock.Anything, expectedTxID). + Return(mockResponse, nil).Once() + + err = provider.SetAdmin(context.Background(), newAdmin) + assert.NoError(t, err, "SetAdmin should execute without error") + + mockClient.AssertExpectations(t) +} + +func TestProvider_MessageReceived(t *testing.T) { + provider, mockClient := setupTestProvider(t) + + tests := []struct { + name string + key *providerTypes.MessageKey + mockSetup func() + expected bool + expectErr bool + }{ + { + name: "EmitMessage Success", + key: &providerTypes.MessageKey{ + EventType: events.EmitMessage, + Src: "icon", + Sn: big.NewInt(12345), + }, + mockSetup: func() { + mockClient.On("GetReceipt", + mock.Anything, + provider.cfg.Contracts[providerTypes.ConnectionContract], + "icon", + big.NewInt(12345), + ).Return(true, nil).Once() + }, + expected: true, + expectErr: false, + }, + { + name: "CallMessage Returns False", + key: &providerTypes.MessageKey{ + EventType: events.CallMessage, + Src: "icon", + Sn: big.NewInt(12345), + }, + mockSetup: func() {}, + expected: false, + expectErr: false, + }, + { + name: "RollbackMessage Returns False", + key: &providerTypes.MessageKey{ + EventType: events.RollbackMessage, + Src: "icon", + Sn: big.NewInt(12345), + }, + mockSetup: func() {}, + expected: false, + expectErr: false, + }, + { + name: "Unknown Event Type", + key: &providerTypes.MessageKey{ + EventType: "unknown", + Src: "icon", + Sn: big.NewInt(12345), + }, + mockSetup: func() {}, + expected: true, + expectErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.mockSetup() + + received, err := provider.MessageReceived(context.Background(), tt.key) + + if tt.expectErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, tt.expected, received) + } + }) + } + + mockClient.AssertExpectations(t) +} + +func TestProvider_RestoreKeystore(t *testing.T) { + provider, _ := setupTestProvider(t) + mockKMS := new(mocks.MockKMS) + provider.kms = mockKMS + + tempDir := t.TempDir() + provider.cfg.HomeDir = tempDir + provider.cfg.Address = "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM" + + keystorePath := filepath.Join(tempDir, "keystore", provider.NID(), provider.cfg.Address) + err := os.MkdirAll(filepath.Dir(keystorePath), 0700) + assert.NoError(t, err) + + encryptedKey := []byte("encrypted_key_data") + err = os.WriteFile(keystorePath, encryptedKey, 0600) + assert.NoError(t, err) + + decryptedKey := []byte("decrypted_key_data") + mockKMS.On("Decrypt", mock.Anything, encryptedKey).Return(decryptedKey, nil) + + err = provider.RestoreKeystore(context.Background()) + assert.NoError(t, err) + assert.Equal(t, decryptedKey, provider.privateKey) + + mockKMS.AssertExpectations(t) +} + +func TestProvider_NewKeystore(t *testing.T) { + provider, _ := setupTestProvider(t) + mockKMS := new(mocks.MockKMS) + provider.kms = mockKMS + + passphrase := "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" + tempDir := t.TempDir() + provider.cfg.HomeDir = tempDir + + mockKMS.On("Encrypt", mock.Anything, mock.AnythingOfType("[]uint8")). + Return([]byte("encrypted_key"), nil) + mockKMS.On("Encrypt", mock.Anything, []byte(passphrase)). + Return([]byte("encrypted_passphrase"), nil) + + address, err := provider.NewKeystore(passphrase) + assert.NoError(t, err, "NewKeystore should not error") + assert.NotEmpty(t, address, "NewKeystore should return a non-empty address") + + assert.Equal(t, 33, len(provider.privateKey), "Private key should be 33 bytes") + t.Logf("PrivateKey length: %d", len(provider.privateKey)) + t.Logf("PrivateKey bytes: %x", provider.privateKey) + + keystorePath := filepath.Join(tempDir, "keystore", provider.NID(), address) + _, err = os.Stat(keystorePath) + assert.NoError(t, err, "Keystore file should exist") + + _, err = os.Stat(keystorePath + ".pass") + assert.NoError(t, err, "Passphrase file should exist") + + mockKMS.AssertExpectations(t) +} + +func TestProvider_Config(t *testing.T) { + provider, _ := setupTestProvider(t) + + cfg := provider.Config() + assert.NotNil(t, cfg) + assert.IsType(t, &Config{}, cfg) + + typedCfg := cfg.(*Config) + assert.Equal(t, provider.cfg, typedCfg) +} + +func TestProvider_Type(t *testing.T) { + provider, _ := setupTestProvider(t) + + providerType := provider.Type() + assert.Equal(t, "stacks", providerType) +} + +func TestProvider_NID(t *testing.T) { + provider, _ := setupTestProvider(t) + + nid := provider.NID() + assert.Equal(t, provider.cfg.NID, nid) +} + +func TestProvider_Name(t *testing.T) { + provider, _ := setupTestProvider(t) + + name := provider.Name() + assert.Equal(t, provider.cfg.ChainName, name) +} + +func TestProvider_FinalityBlock(t *testing.T) { + provider, _ := setupTestProvider(t) + provider.cfg.FinalityBlock = 10 + + finality := provider.FinalityBlock(context.Background()) + assert.Equal(t, uint64(10), finality) +} + +func TestProvider_GetLastSavedBlockHeight(t *testing.T) { + provider, _ := setupTestProvider(t) + + expectedHeight := uint64(1234) + provider.LastSavedHeightFunc = func() uint64 { + return expectedHeight + } + + height := provider.GetLastSavedBlockHeight() + assert.Equal(t, expectedHeight, height) +} + +func TestProvider_RevertMessage(t *testing.T) { + provider, _ := setupTestProvider(t) + + err := provider.RevertMessage(context.Background(), big.NewInt(12345)) + assert.Error(t, err) + assert.Equal(t, "not implemented", err.Error()) +} + +func TestProviderConfig_Validate(t *testing.T) { + tests := []struct { + name string + cfg *Config + expectErr bool + }{ + { + name: "Valid Config", + cfg: &Config{ + CommonConfig: provider.CommonConfig{ + RPCUrl: "https://example.com", + Contracts: providerTypes.ContractConfigMap{ + "XcallContract": "ST1234", + }, + }, + }, + expectErr: false, + }, + { + name: "Empty RPC URL", + cfg: &Config{ + CommonConfig: provider.CommonConfig{ + RPCUrl: "", + Contracts: providerTypes.ContractConfigMap{ + "XcallContract": "ST1234", + }, + }, + }, + expectErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.cfg.Validate() + if tt.expectErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestProviderConfig_Enabled(t *testing.T) { + tests := []struct { + name string + cfg *Config + expected bool + }{ + { + name: "Enabled Config", + cfg: &Config{ + CommonConfig: provider.CommonConfig{ + Disabled: false, + }, + }, + expected: true, + }, + { + name: "Disabled Config", + cfg: &Config{ + CommonConfig: provider.CommonConfig{ + Disabled: true, + }, + }, + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + enabled := tt.cfg.Enabled() + assert.Equal(t, tt.expected, enabled) + }) + } +} + +func TestProviderConfig_SetWallet(t *testing.T) { + cfg := &Config{} + address := "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM" + + cfg.SetWallet(address) + assert.Equal(t, address, cfg.Address) +} + +func TestProviderConfig_GetWallet(t *testing.T) { + cfg := &Config{ + CommonConfig: provider.CommonConfig{ + Address: "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM", + }, + } + + address := cfg.GetWallet() + assert.Equal(t, cfg.Address, address) +} + +func TestProvider_QueryTransactionReceipt(t *testing.T) { + provider, mockClient := setupTestProvider(t) + + txID := "0x123456789" + + t.Run("Mempool Transaction", func(t *testing.T) { + pendingStatus := "pending" + response := &blockchainApiClient.GetTransactionById200Response{ + GetMempoolTransactionList200ResponseResultsInner: &blockchainApiClient.GetMempoolTransactionList200ResponseResultsInner{ + ContractCallMempoolTransaction1: &blockchainApiClient.ContractCallMempoolTransaction1{ + TxId: txID, + TxStatus: blockchainApiClient.TokenTransferMempoolTransaction1TxStatus{ + String: &pendingStatus, + }, + }, + }, + } + + mockClient.On("GetTransactionById", mock.Anything, txID).Return(response, nil).Once() + + receipt, err := provider.QueryTransactionReceipt(context.Background(), txID) + assert.NoError(t, err) + assert.NotNil(t, receipt) + assert.Equal(t, txID, receipt.TxHash) + assert.Equal(t, uint64(0), receipt.Height) + }) + + t.Run("Confirmed Transaction", func(t *testing.T) { + successStatus := "success" + response := &blockchainApiClient.GetTransactionById200Response{ + GetTransactionList200ResponseResultsInner: &blockchainApiClient.GetTransactionList200ResponseResultsInner{ + ContractCallTransaction: &blockchainApiClient.ContractCallTransaction{ + TxId: txID, + BlockHeight: 1234, + TxStatus: blockchainApiClient.TokenTransferTransactionTxStatus{ + String: &successStatus, + }, + Canonical: true, + }, + }, + } + + mockClient.On("GetTransactionById", mock.Anything, txID).Return(response, nil).Once() + + receipt, err := provider.QueryTransactionReceipt(context.Background(), txID) + assert.NoError(t, err) + assert.NotNil(t, receipt) + assert.Equal(t, txID, receipt.TxHash) + assert.Equal(t, uint64(1234), receipt.Height) + assert.True(t, receipt.Status) + }) + + t.Run("Error Case", func(t *testing.T) { + mockClient.On("GetTransactionById", mock.Anything, txID). + Return((*blockchainApiClient.GetTransactionById200Response)(nil), fmt.Errorf("transaction not found")).Once() + + receipt, err := provider.QueryTransactionReceipt(context.Background(), txID) + assert.Error(t, err) + assert.Nil(t, receipt) + }) + + mockClient.AssertExpectations(t) +} + +func TestProvider_ShouldReceiveMessage(t *testing.T) { + provider, _ := setupTestProvider(t) + + message := &providerTypes.Message{ + Dst: "stacks_testnet", + Src: "icon", + Sn: big.NewInt(12345), + } + + should, err := provider.ShouldReceiveMessage(context.Background(), message) + assert.NoError(t, err) + assert.True(t, should) +} + +func TestProvider_ShouldSendMessage(t *testing.T) { + provider, _ := setupTestProvider(t) + + message := &providerTypes.Message{ + Dst: "icon", + Src: "stacks_testnet", + Sn: big.NewInt(12345), + } + + should, err := provider.ShouldSendMessage(context.Background(), message) + assert.NoError(t, err) + assert.True(t, should) +} + +func TestProvider_WaitForTransactionConfirmation(t *testing.T) { + provider, mockClient := setupTestProvider(t) + + txID := "0x123456789" + + t.Run("Successful Confirmation", func(t *testing.T) { + successStatus := "success" + response := &blockchainApiClient.GetTransactionById200Response{ + GetTransactionList200ResponseResultsInner: &blockchainApiClient.GetTransactionList200ResponseResultsInner{ + ContractCallTransaction: &blockchainApiClient.ContractCallTransaction{ + TxId: txID, + BlockHeight: 1234, + TxStatus: blockchainApiClient.TokenTransferTransactionTxStatus{ + String: &successStatus, + }, + Canonical: true, + }, + }, + } + + mockClient.On("GetTransactionById", mock.Anything, txID).Return(response, nil) + + receipt, err := provider.waitForTransactionConfirmation(context.Background(), txID, MAX_WAIT_TIME) + assert.NoError(t, err) + assert.NotNil(t, receipt) + assert.Equal(t, txID, receipt.TxHash) + assert.True(t, receipt.Status) + assert.Equal(t, uint64(1234), receipt.Height) + }) + + t.Run("Context Cancellation", func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + _, err := provider.waitForTransactionConfirmation(ctx, txID, MAX_WAIT_TIME) + assert.Error(t, err) + assert.Equal(t, context.Canceled, err) + }) + + t.Run("Timeout", func(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) + defer cancel() + + pendingStatus := "pending" + pendingResponse := &blockchainApiClient.GetTransactionById200Response{ + GetMempoolTransactionList200ResponseResultsInner: &blockchainApiClient.GetMempoolTransactionList200ResponseResultsInner{ + ContractCallMempoolTransaction1: &blockchainApiClient.ContractCallMempoolTransaction1{ + TxId: txID, + TxStatus: blockchainApiClient.TokenTransferMempoolTransaction1TxStatus{ + String: &pendingStatus, + }, + }, + }, + } + + mockClient.On("GetTransactionById", mock.Anything, txID).Return(pendingResponse, nil) + + timeoutDuration := 100 * time.Millisecond + _, err := provider.waitForTransactionConfirmation(ctx, txID, timeoutDuration) + assert.Error(t, err) + assert.Contains(t, err.Error(), "transaction confirmation timed out") + }) + + mockClient.AssertExpectations(t) +} + +func TestProvider_ImportKeystore(t *testing.T) { + provider, _ := setupTestProvider(t) + mockKMS := new(mocks.MockKMS) + provider.kms = mockKMS + + tempDir := t.TempDir() + provider.cfg.HomeDir = tempDir + + importKeyPath := filepath.Join(tempDir, "import_keystore") + encryptedKey := []byte("encrypted_import_key") + err := os.WriteFile(importKeyPath, encryptedKey, 0600) + assert.NoError(t, err) + + // Create a 33-byte private key (32 bytes for the key + 1 byte for compression flag) + decryptedKey := make([]byte, 33) + copy(decryptedKey, []byte("00000000000000000000000000000000")) // 32 bytes + decryptedKey[32] = 0x01 // compression flag + + passphrase := "test_passphrase" + + mockKMS.On("Decrypt", mock.Anything, encryptedKey).Return(decryptedKey, nil) + mockKMS.On("Encrypt", mock.Anything, decryptedKey).Return([]byte("new_encrypted_key"), nil) + mockKMS.On("Encrypt", mock.Anything, []byte(passphrase)).Return([]byte("encrypted_passphrase"), nil) + + err = os.MkdirAll(filepath.Join(tempDir, "keystore", provider.NID()), 0700) + assert.NoError(t, err) + + address, err := provider.ImportKeystore(context.Background(), importKeyPath, passphrase) + assert.NoError(t, err) + assert.NotEmpty(t, address) + + keystorePath := filepath.Join(tempDir, "keystore", provider.NID(), address) + _, err = os.Stat(keystorePath) + assert.NoError(t, err) + + _, err = os.Stat(keystorePath + ".pass") + assert.NoError(t, err) + + assert.Equal(t, decryptedKey, provider.privateKey) + assert.Equal(t, address, provider.cfg.Address) + + mockKMS.AssertExpectations(t) +} + +func TestProvider_GetAddressByEventType(t *testing.T) { + provider, _ := setupTestProvider(t) + + tests := []struct { + name string + eventType string + expected string + }{ + { + name: "EmitMessage Event", + eventType: events.EmitMessage, + expected: provider.cfg.Contracts[providerTypes.ConnectionContract], + }, + { + name: "CallMessage Event", + eventType: events.CallMessage, + expected: provider.cfg.Contracts[providerTypes.XcallContract], + }, + { + name: "RollbackMessage Event", + eventType: events.RollbackMessage, + expected: provider.cfg.Contracts[providerTypes.XcallContract], + }, + { + name: "Unknown Event", + eventType: "unknown", + expected: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + address := provider.GetAddressByEventType(tt.eventType) + assert.Equal(t, tt.expected, address) + }) + } +} diff --git a/relayer/chains/stacks/query.go b/relayer/chains/stacks/query.go index 90e59adb..ca8debc1 100644 --- a/relayer/chains/stacks/query.go +++ b/relayer/chains/stacks/query.go @@ -101,8 +101,25 @@ func GetReceipt(tx interface{}) (*providerTypes.Receipt, error) { var status bool = false txStatusField := txStruct.FieldByName("TxStatus") - if txStatusField.IsValid() && txStatusField.Kind() == reflect.String { - status = txStatusField.String() == "success" + if txStatusField.IsValid() && txStatusField.Kind() == reflect.Struct { + stringField := txStatusField.FieldByName("String") + if stringField.IsValid() { + if stringField.Kind() == reflect.Ptr { + if !stringField.IsNil() && stringField.Elem().Kind() == reflect.String { + status = stringField.Elem().String() == "success" + } else { + return nil, fmt.Errorf("string field in txstatus did not parse %s", fieldType) + } + } else if stringField.Kind() == reflect.String { + status = stringField.String() == "success" + } else { + return nil, fmt.Errorf("string field in txstatus did not parse %s", fieldType) + } + } else { + return nil, fmt.Errorf("string field in txstatus did not parse %s", fieldType) + } + } else { + return nil, fmt.Errorf("TxStatus field is missing or not a struct in %s", fieldType) } height := blockHeight diff --git a/relayer/chains/stacks/route.go b/relayer/chains/stacks/route.go index ced5bb62..ce827602 100644 --- a/relayer/chains/stacks/route.go +++ b/relayer/chains/stacks/route.go @@ -37,7 +37,7 @@ func (p *Provider) Route(ctx context.Context, message *types.Message, callback t p.log.Info("Transaction sent", zap.String("txID", txID)) - receipt, err := p.waitForTransactionConfirmation(ctx, txID) + receipt, err := p.waitForTransactionConfirmation(ctx, txID, MAX_WAIT_TIME) if err != nil { return fmt.Errorf("failed to confirm transaction: %w", err) } From 160ee968988197b8e682ee53cbb2fe010fc853a8 Mon Sep 17 00:00:00 2001 From: CyrusVorwald <90732384+CyrusVorwald@users.noreply.github.com> Date: Thu, 7 Nov 2024 00:49:18 -0500 Subject: [PATCH 4/9] chore: update go mod and add stacks xcall artifact --- go.mod | 72 +- go.sum | 184 +++-- go.work.sum | 1111 +++++++++---------------------- scripts/execute-test.sh | 1 + scripts/optimize-xcall-build.sh | 2 + test/sample-config.yaml | 27 + 6 files changed, 475 insertions(+), 922 deletions(-) diff --git a/go.mod b/go.mod index 3657c652..42b4335c 100644 --- a/go.mod +++ b/go.mod @@ -6,11 +6,11 @@ toolchain go1.23.1 require ( github.com/CosmWasm/wasmd v0.52.0 - github.com/cometbft/cometbft v0.38.10 + github.com/cometbft/cometbft v0.38.15 github.com/coming-chat/go-sui/v2 v2.0.1 github.com/cosmos/cosmos-sdk v0.50.8 github.com/cosmos/relayer/v2 v2.5.2 - github.com/ethereum/go-ethereum v1.14.7 + github.com/ethereum/go-ethereum v1.14.11 github.com/fardream/go-bcs v0.4.0 github.com/gagliardetto/solana-go v1.11.0 github.com/gofrs/flock v0.8.1 @@ -29,7 +29,7 @@ require ( github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d go.uber.org/zap v1.27.0 golang.org/x/sync v0.8.0 - google.golang.org/grpc v1.64.0 + google.golang.org/grpc v1.67.1 gopkg.in/yaml.v3 v3.0.1 ) @@ -55,8 +55,8 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/blendle/zapdriver v1.3.1 // indirect github.com/bshuster-repo/logrus-logstash-hook v0.4.1 // indirect - github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd // indirect - github.com/btcsuite/btcd/btcutil v1.1.5 // indirect + github.com/btcsuite/btcd v0.24.2 // indirect + github.com/btcsuite/btcd/btcutil v1.1.6 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect github.com/btcsuite/btcutil v1.0.2 // indirect github.com/cespare/cp v1.1.1 // indirect @@ -65,7 +65,8 @@ require ( github.com/cosmos/ibc-go/v8 v8.3.2 // indirect github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect - github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 // indirect + github.com/dgraph-io/badger/v4 v4.2.0 // indirect + github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 // indirect github.com/evalphobia/logrus_fluent v0.5.4 // indirect github.com/fluent/fluent-logger-golang v1.9.0 // indirect github.com/gagliardetto/binary v0.8.0 // indirect @@ -85,6 +86,7 @@ require ( github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect + github.com/google/flatbuffers v1.12.1 // indirect github.com/gorilla/schema v1.2.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect @@ -99,12 +101,13 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 // indirect github.com/mr-tron/base58 v1.2.0 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/philhofer/fwd v1.1.2 // indirect - github.com/prometheus/client_golang v1.19.1 // indirect + github.com/prometheus/client_golang v1.20.5 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.52.2 // indirect - github.com/prometheus/procfs v0.13.0 // indirect + github.com/prometheus/common v0.60.1 // indirect + github.com/prometheus/procfs v0.15.1 // indirect github.com/prometheus/statsd_exporter v0.26.0 // indirect github.com/sagikazarmark/locafero v0.6.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect @@ -132,10 +135,10 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect - golang.org/x/net v0.27.0 // indirect + golang.org/x/net v0.30.0 // indirect golang.org/x/time v0.6.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/protobuf v1.34.1 // indirect + google.golang.org/protobuf v1.35.1 // indirect gopkg.in/go-playground/validator.v9 v9.31.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect @@ -143,7 +146,7 @@ require ( require ( cloud.google.com/go v0.113.0 // indirect - cloud.google.com/go/compute/metadata v0.3.0 // indirect + cloud.google.com/go/compute/metadata v0.5.0 // indirect cloud.google.com/go/iam v1.1.8 // indirect cloud.google.com/go/storage v1.41.0 // indirect cosmossdk.io/api v0.7.5 // indirect @@ -175,15 +178,14 @@ require ( github.com/bits-and-blooms/bitset v1.13.0 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.4 github.com/cenkalti/backoff/v4 v4.2.1 // indirect - github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cockroachdb/errors v1.11.3 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect - github.com/cockroachdb/pebble v1.1.1 // indirect + github.com/cockroachdb/pebble v1.1.2 // indirect github.com/cockroachdb/redact v1.1.5 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect - github.com/cometbft/cometbft-db v0.9.1 // indirect + github.com/cometbft/cometbft-db v0.14.1 // indirect github.com/consensys/bavard v0.1.13 // indirect github.com/consensys/gnark-crypto v0.12.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect @@ -191,7 +193,7 @@ require ( github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect github.com/cosmos/go-bip39 v1.0.0 github.com/cosmos/gogogateway v1.2.0 // indirect - github.com/cosmos/gogoproto v1.5.0 // indirect + github.com/cosmos/gogoproto v1.7.0 // indirect github.com/cosmos/iavl v1.2.0 // indirect github.com/cosmos/ibc-go/modules/capability v1.0.0 // indirect github.com/cosmos/ics23/go v0.10.0 // indirect @@ -201,9 +203,7 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect - github.com/dgraph-io/badger/v2 v2.2007.4 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect - github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/distribution/reference v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.6.0 // indirect @@ -213,15 +213,15 @@ require ( github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/getsentry/sentry-go v0.27.0 // indirect - github.com/go-kit/kit v0.12.0 // indirect + github.com/go-kit/kit v0.13.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.3 // indirect - github.com/golang/glog v1.2.0 // indirect + github.com/golang/glog v1.2.2 // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect - github.com/google/btree v1.1.2 // indirect + github.com/google/btree v1.1.3 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/orderedcode v0.0.1 // indirect @@ -246,14 +246,14 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/hdevalence/ed25519consensus v0.1.0 // indirect - github.com/holiman/uint256 v1.3.0 // indirect + github.com/holiman/uint256 v1.3.1 // indirect github.com/huandu/skiplist v1.2.0 // indirect github.com/iancoleman/strcase v0.3.0 // indirect github.com/improbable-eng/grpc-web v0.15.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect - github.com/klauspost/compress v1.17.8 // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/lib/pq v1.10.9 // indirect @@ -262,7 +262,7 @@ require ( github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect - github.com/minio/highwayhash v1.0.2 // indirect + github.com/minio/highwayhash v1.0.3 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -272,20 +272,20 @@ require ( github.com/oklog/run v1.1.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect - github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 // indirect + github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rivo/uniseg v0.4.3 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect - github.com/rs/cors v1.10.1 // indirect + github.com/rs/cors v1.11.1 // indirect github.com/rs/zerolog v1.33.0 // indirect - github.com/sasha-s/go-deadlock v0.3.1 // indirect + github.com/sasha-s/go-deadlock v0.3.5 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 github.com/subosito/gotenv v1.6.0 // indirect - github.com/supranational/blst v0.3.12 // indirect + github.com/supranational/blst v0.3.13 // indirect github.com/tendermint/go-amino v0.16.0 // indirect github.com/tidwall/btree v1.7.0 // indirect github.com/tklauser/go-sysconf v0.3.13 // indirect @@ -294,16 +294,16 @@ require ( github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v0.14.3 // indirect - go.etcd.io/bbolt v1.3.8 // indirect - golang.org/x/crypto v0.26.0 // indirect - golang.org/x/oauth2 v0.20.0 // indirect - golang.org/x/sys v0.23.0 // indirect - golang.org/x/term v0.23.0 // indirect - golang.org/x/text v0.17.0 // indirect + go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5 // indirect + golang.org/x/crypto v0.28.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/term v0.25.0 // indirect + golang.org/x/text v0.19.0 // indirect google.golang.org/api v0.180.0 // indirect google.golang.org/genproto v0.0.0-20240513163218-0867130af1f8 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gotest.tools/v3 v3.5.1 // indirect nhooyr.io/websocket v1.8.6 // indirect diff --git a/go.sum b/go.sum index ee7a9924..d6a8c6c8 100644 --- a/go.sum +++ b/go.sum @@ -72,8 +72,8 @@ cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= -cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= +cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= @@ -248,7 +248,6 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= -github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= @@ -256,8 +255,8 @@ github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjC github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/adlio/schema v1.3.3 h1:oBJn8I02PyTB466pZO1UZEn1TV5XLlifBSyMrmHl/1I= -github.com/adlio/schema v1.3.3/go.mod h1:1EsRssiv9/Ce2CMzq5DoL7RiMshhuigQxrR4DMV9fHg= +github.com/adlio/schema v1.3.6 h1:k1/zc2jNfeiZBA5aFTRy37jlBIuCkXCm0XmvpzCKI9I= +github.com/adlio/schema v1.3.6/go.mod h1:qkxwLgPBd1FgLRHYVCmQT/rrBr3JH38J9LjmVzWNudg= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f h1:zvClvFQwU++UpIUBGC8YmDlfhUrweEy1R1Fj1gu5iIM= @@ -278,7 +277,6 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= @@ -336,16 +334,18 @@ github.com/bshuster-repo/logrus-logstash-hook v0.4.1 h1:pgAtgj+A31JBVtEHu2uHuEx0 github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= -github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd h1:js1gPwhcFflTZ7Nzl7WHaOTlTr5hIrR4n1NM4v9n4Kw= github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A= +github.com/btcsuite/btcd v0.24.2 h1:aLmxPguqxza+4ag8R1I2nnJjSu2iFn/kqtHTIImswcY= +github.com/btcsuite/btcd v0.24.2/go.mod h1:5C8ChTkl5ejr3WHj8tkQSCmydiMEPB0ZhQhehpq7Dgg= github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= -github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8= github.com/btcsuite/btcd/btcutil v1.1.5/go.mod h1:PSZZ4UitpLBWzxGd5VGOrLnmOjtPP/a6HaFo12zMs00= +github.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/AYFd6c= +github.com/btcsuite/btcd/btcutil v1.1.6/go.mod h1:9dFymx8HpuLqBnsPELrImQeTQfKBQqzqGbbV3jK55aE= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= @@ -372,7 +372,6 @@ github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU= github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -415,17 +414,17 @@ github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/e github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v1.1.1 h1:XnKU22oiCLy2Xn8vp1re67cXg4SAasg/WDt1NtcRFaw= -github.com/cockroachdb/pebble v1.1.1/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= +github.com/cockroachdb/pebble v1.1.2 h1:CUh2IPtR4swHlEj48Rhfzw6l/d0qA31fItcIszQVIsA= +github.com/cockroachdb/pebble v1.1.2/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/cometbft/cometbft v0.38.10 h1:2ePuglchT+j0Iao+cfmt/nw5U7K2lnGDzXSUPGVdXaU= -github.com/cometbft/cometbft v0.38.10/go.mod h1:jHPx9vQpWzPHEAiYI/7EDKaB1NXhK6o3SArrrY8ExKc= -github.com/cometbft/cometbft-db v0.9.1 h1:MIhVX5ja5bXNHF8EYrThkG9F7r9kSfv8BX4LWaxWJ4M= -github.com/cometbft/cometbft-db v0.9.1/go.mod h1:iliyWaoV0mRwBJoizElCwwRA9Tf7jZJOURcRZF9m60U= +github.com/cometbft/cometbft v0.38.15 h1:5veFd8k1uXM27PBg9sMO3hAfRJ3vbh4OmmLf6cVrqXg= +github.com/cometbft/cometbft v0.38.15/go.mod h1:+wh6ap6xctVG+JOHwbl8pPKZ0GeqdPYqISu7F4b43cQ= +github.com/cometbft/cometbft-db v0.14.1 h1:SxoamPghqICBAIcGpleHbmoPqy+crij/++eZz3DlerQ= +github.com/cometbft/cometbft-db v0.14.1/go.mod h1:KHP1YghilyGV/xjD5DP3+2hyigWx0WTp9X+0Gnx0RxQ= github.com/coming-chat/go-aptos v0.0.0-20221013022715-39f91035c785 h1:xIOXIW3uXakffHoVqA6qkyUgYYuhJWLPohIyR1tBS38= github.com/coming-chat/go-aptos v0.0.0-20221013022715-39f91035c785/go.mod h1:HaGBPmQOlKzxkbGancRSX8wcwDxvj9Zs173CSla43vE= github.com/coming-chat/go-sui/v2 v2.0.1 h1:Mi7IGUvKd8OLP5zA3YhfDN/L5AJTXHsSsJnLb9WX9+4= @@ -436,8 +435,6 @@ github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJ github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= @@ -455,8 +452,8 @@ github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4x github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ4GUkT+tbFI= github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU= -github.com/cosmos/gogoproto v1.5.0 h1:SDVwzEqZDDBoslaeZg+dGE55hdzHfgUA40pEanMh52o= -github.com/cosmos/gogoproto v1.5.0/go.mod h1:iUM31aofn3ymidYG6bUR5ZFrk+Om8p5s754eMUcyp8I= +github.com/cosmos/gogoproto v1.7.0 h1:79USr0oyXAbxg3rspGh/m4SWNyoz/GLaAh0QlCe2fro= +github.com/cosmos/gogoproto v1.7.0/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0= github.com/cosmos/iavl v1.2.0 h1:kVxTmjTh4k0Dh1VNL046v6BXqKziqMDzxo93oh3kOfM= github.com/cosmos/iavl v1.2.0/go.mod h1:HidWWLVAtODJqFD6Hbne2Y0q3SdxByJepHUOeoH4LiI= github.com/cosmos/ibc-go/modules/apps/callbacks v0.2.1-0.20231113120333-342c00b0f8bd h1:Lx+/5dZ/nN6qPXP2Ofog6u1fmlkCFA1ElcOconnofEM= @@ -471,8 +468,6 @@ github.com/cosmos/ledger-cosmos-go v0.13.3 h1:7ehuBGuyIytsXbd4MP43mLeoN2LTOEnk5n github.com/cosmos/ledger-cosmos-go v0.13.3/go.mod h1:HENcEP+VtahZFw38HZ3+LS3Iv5XV6svsnkk9vdJtLr8= github.com/cosmos/relayer/v2 v2.5.2 h1:AF0MOo1GvJo94QNB996fBHdKlH+vrIY3JcFNrIvZNP0= github.com/cosmos/relayer/v2 v2.5.2/go.mod h1:h4Ng2QsVpxExIq5S+WvLr8slDb9MSBh82gQS4DeMwDo= -github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -500,9 +495,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3 github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= -github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= -github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= -github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/badger/v4 v4.2.0 h1:kJrlajbXXL9DFTNuhhu9yCx7JJa4qpYWxtE8BzuWsEs= +github.com/dgraph-io/badger/v4 v4.2.0/go.mod h1:qfCqhPoWDFJRx1gp5QwwyGo8xk1lbHUxvK9nK0OGAak= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= @@ -540,10 +534,10 @@ github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go. github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ethereum/c-kzg-4844 v1.0.2 h1:8tV84BCEiPeOkiVgW9mpYBeBUir2bkCNVqxPwwVeO+s= github.com/ethereum/c-kzg-4844 v1.0.2/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/ethereum/go-ethereum v1.14.7 h1:EHpv3dE8evQmpVEQ/Ne2ahB06n2mQptdwqaMNhAT29g= -github.com/ethereum/go-ethereum v1.14.7/go.mod h1:Mq0biU2jbdmKSZoqOj29017ygFrMnB5/Rifwp980W4o= -github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 h1:KrE8I4reeVvf7C1tm8elRjj4BdscTYzz/WAbYyf/JI4= -github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0/go.mod h1:D9AJLVXSyZQXJQVk8oh1EwjISE+sJTn2duYIZC0dy3w= +github.com/ethereum/go-ethereum v1.14.11 h1:8nFDCUUE67rPc6AKxFj7JKaOa2W/W1Rse3oS6LvvxEY= +github.com/ethereum/go-ethereum v1.14.11/go.mod h1:+l/fr42Mma+xBnhefL/+z11/hcmJ2egl+ScIVPjhc7E= +github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 h1:8NfxH2iXvJ60YRB8ChToFTUzl8awsc3cJ8CbLjGIl/A= +github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= github.com/evalphobia/logrus_fluent v0.5.4 h1:G4BSBTm7+L+oanWfFtA/A5Y3pvL2OMxviczyZPYO5xc= github.com/evalphobia/logrus_fluent v0.5.4/go.mod h1:hasyj+CXm3BDP1YhFk/rnTcjlegyqvkokV9A25cQsaA= github.com/fardream/go-bcs v0.4.0 h1:J2yQZRAnkg/yMgP9MPf/qj9jJfD6w/LCMdWtC9Cbn08= @@ -556,8 +550,6 @@ github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA= -github.com/fjl/memsize v0.0.2/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= github.com/fluent/fluent-logger-golang v1.9.0 h1:zUdY44CHX2oIUc7VTNZc+4m+ORuO/mldQDA7czhWXEg= github.com/fluent/fluent-logger-golang v1.9.0/go.mod h1:2/HCT/jTy78yGyeNGQLGQsjF3zzzAuy6Xlk6FCMV5eU= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= @@ -601,8 +593,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= -github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= -github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= +github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU= +github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= @@ -662,8 +654,8 @@ github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzq github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= -github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY= +github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -708,8 +700,10 @@ github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXi github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw= +github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -864,8 +858,8 @@ github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6w github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= -github.com/holiman/uint256 v1.3.0 h1:4wdcm/tnd0xXdu7iS3ruNvxkWwrb4aeBQv19ayYn8F4= -github.com/holiman/uint256 v1.3.0/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/holiman/uint256 v1.3.1 h1:JfTzmih28bittyHM8z360dCjIA9dbPIBlcTI6lmctQs= +github.com/holiman/uint256 v1.3.1/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= @@ -929,11 +923,10 @@ github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6 github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= -github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= -github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -965,7 +958,6 @@ github.com/linxGnu/grocksdb v1.8.14/go.mod h1:QYiYypR2d4v63Wj1adOOfzglnoII0gLj3P github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= @@ -992,8 +984,8 @@ github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZ github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= -github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= +github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -1030,6 +1022,8 @@ github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -1077,8 +1071,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= -github.com/opencontainers/runc v1.1.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b+d8w= -github.com/opencontainers/runc v1.1.3/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= +github.com/opencontainers/runc v1.1.12 h1:BOIssBaW1La0/qbNZHXOOa71dZfZEQOzW7dqQf3phss= +github.com/opencontainers/runc v1.1.12/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -1094,13 +1088,11 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= -github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= -github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 h1:jik8PHtAIsPlCRJjJzl4udgEf7hawInF9texMeO2jrU= -github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw= +github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= @@ -1127,8 +1119,8 @@ github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqr github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= -github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -1147,8 +1139,8 @@ github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9 github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/common v0.52.2 h1:LW8Vk7BccEdONfrJBDffQGRtpSzi5CQaRZGtboOO2ck= -github.com/prometheus/common v0.52.2/go.mod h1:lrWtQx+iDfn2mbH5GUzlH9TSHyfZpHkSiG1W7y3sF2Q= +github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc= +github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -1158,8 +1150,8 @@ github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o= -github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI= github.com/prometheus/statsd_exporter v0.26.0 h1:SQl3M6suC6NWQYEzOvIv+EF6dAMYEqIuZy+o4H9F5Ig= github.com/prometheus/statsd_exporter v0.26.0/go.mod h1:GXFLADOmBTVDrHc7b04nX8ooq3azG61pnECNqT7O5DM= @@ -1178,13 +1170,11 @@ github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/f github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= -github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= +github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= -github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -1194,13 +1184,13 @@ github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= -github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= -github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= +github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU= +github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentio/go-loggly v0.5.1-0.20171222203950-eb91657e62b2 h1:S4OC0+OBKz6mJnzuHioeEat74PuQ4Sgvbf8eus695sc= github.com/segmentio/go-loggly v0.5.1-0.20171222203950-eb91657e62b2/go.mod h1:8zLRYR5npGjaOXgPSKat5+oOh+UHd8OdbS18iqX9F6Y= -github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= -github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shamaton/msgpack/v2 v2.2.0 h1:IP1m01pHwCrMa6ZccP9B3bqxEMKMSmMVAVKk54g3L/Y= github.com/shamaton/msgpack/v2 v2.2.0/go.mod h1:6khjYnkx73f7VQU7wjcFS9DFjs+59naVWJv1TB7qdOI= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= @@ -1221,24 +1211,16 @@ github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJ github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= -github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobtDnDzA= @@ -1276,8 +1258,8 @@ github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8 github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/supranational/blst v0.3.12 h1:Vfas2U2CFHhniv2QkUm2OVa1+pGTdqtpqm9NnhUUbZ8= -github.com/supranational/blst v0.3.12/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/supranational/blst v0.3.13 h1:AYeSxdOMacwu7FBmpfloBz5pbFXDmJL33RuwnKtmTjk= +github.com/supranational/blst v0.3.13/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= @@ -1304,7 +1286,6 @@ github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2n github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= @@ -1339,7 +1320,6 @@ github.com/xeipuuv/gojsonreference v0.0.0-20150808065054-e02fc20de94c/go.mod h1: github.com/xeipuuv/gojsonschema v0.0.0-20161231055540-f06f290571ce h1:cVSRGH8cOveJNwFEEZLXtB+XMnRqKLjUP6V/ZFYQCXI= github.com/xeipuuv/gojsonschema v0.0.0-20161231055540-f06f290571ce/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yalp/jsonpath v0.0.0-20150812003900-31a79c7593bb h1:06WAhQa+mYv7BiOk13B/ywyTlkoE/S7uu6TBKU6FHnE= @@ -1362,8 +1342,8 @@ github.com/zondax/hid v0.9.2/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWp github.com/zondax/ledger-go v0.14.3 h1:wEpJt2CEcBJ428md/5MgSLsXLBos98sBOyxNmCjfUCw= github.com/zondax/ledger-go v0.14.3/go.mod h1:IKKaoxupuB43g4NxeQmbLXv7T9AlQyie1UpHb342ycI= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= -go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5 h1:qxen9oVGzDdIRP6ejyAJc760RwW4SnVDiTYTzwnXuxo= +go.etcd.io/bbolt v1.4.0-alpha.0.0.20240404170359-43604f3112c5/go.mod h1:eW0HG9/oHQhvRCvb1/pIXW4cOvtDqeQK+XSi3TnwaXY= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.mongodb.org/mongo-driver v1.11.0 h1:FZKhBSTydeuffHj9CBjXlR8vQLee1cQyTWYPA6/tqiE= go.mongodb.org/mongo-driver v1.11.0/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8= @@ -1395,8 +1375,8 @@ 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.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -1419,7 +1399,6 @@ golang.org/x/crypto v0.0.0-20170613210332-850760c427c5/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -1435,8 +1414,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1548,8 +1527,9 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1575,8 +1555,8 @@ golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= -golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo= -golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1605,8 +1585,6 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1615,7 +1593,6 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1705,9 +1682,10 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1718,8 +1696,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1737,8 +1715,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1989,10 +1967,10 @@ google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= google.golang.org/genproto v0.0.0-20240513163218-0867130af1f8 h1:XpH03M6PDRKTo1oGfZBXu2SzwcbfxUokgobVinuUZoU= google.golang.org/genproto v0.0.0-20240513163218-0867130af1f8/go.mod h1:OLh2Ylz+WlYAJaSBRpJIJLP8iQP+8da+fpxbwNEAV/o= -google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8 h1:W5Xj/70xIA4x60O/IFyXivR5MGqblAb8R3w26pnD6No= -google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8/go.mod h1:vPrPUTsDCYxXWjP7clS81mZ6/803D8K4iM9Ma27VKas= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 h1:mxSlqyb8ZAHsYDCfiXN1EDdNTdvjUJSLY+OnAUtYNYA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8/go.mod h1:I7Y+G38R2bu5j1aLzfFmQfTcU/WnFuqDwLZAbvKTKpM= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8= +google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= @@ -2034,8 +2012,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -2052,8 +2030,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/go.work.sum b/go.work.sum index 011843fc..9ae36b41 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1,44 +1,17 @@ 4d63.com/gocheckcompilerdirectives v1.2.1/go.mod h1:yjDJSxmDTtIHHCqX0ufRYZDL6vQtMG7tJdKVeWwsqvs= +4d63.com/gochecknoglobals v0.1.0/go.mod h1:wfdC5ZjKSPr7CybKEcgJhUOgeAQW1+7WcyK8OvUilfo= 4d63.com/gochecknoglobals v0.2.1/go.mod h1:KRE8wtJB3CXCsb1xy421JfTHIIbmT3U5ruxw2Qu8fSU= +cel.dev/expr v0.16.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg= cloud.google.com/go v0.0.0-20170206221025-ce650573d812/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= -cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= -cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= cloud.google.com/go v0.110.10/go.mod h1:v1OoFqYxiBkUrruItNM3eT4lLByNjxmJSV/xDKJNnic= cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4= cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= -cloud.google.com/go v0.113.0 h1:g3C70mn3lWfckKBiCVsAshabrDg01pQ0pnX1MNtnMkA= -cloud.google.com/go v0.113.0/go.mod h1:glEqlogERKYeePz6ZdkcLJ28Q2I6aERgDDErBg9GzO8= cloud.google.com/go/accessapproval v1.7.7/go.mod h1:10ZDPYiTm8tgxuMPid8s2DL93BfCt6xBh/Vg0Xd8pU0= cloud.google.com/go/accesscontextmanager v1.8.7/go.mod h1:jSvChL1NBQ+uLY9zUBdPy9VIlozPoHptdBnRYeWuQoM= -cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= -cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= cloud.google.com/go/aiplatform v1.67.0/go.mod h1:s/sJ6btBEr6bKnrNWdK9ZgHCvwbZNdP90b3DDtxxw+Y= -cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= -cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= cloud.google.com/go/analytics v0.23.2/go.mod h1:vtE3olAXZ6edJYk1UOndEs6EfaEc9T2B28Y4G5/a7Fo= cloud.google.com/go/apigateway v1.6.7/go.mod h1:7wAMb/33Rzln+PrGK16GbGOfA1zAO5Pq6wp19jtIt7c= cloud.google.com/go/apigeeconnect v1.6.7/go.mod h1:hZxCKvAvDdKX8+eT0g5eEAbRSS9Gkzi+MPWbgAMAy5U= @@ -46,54 +19,23 @@ cloud.google.com/go/apigeeregistry v0.8.5/go.mod h1:ZMg60hq2K35tlqZ1VVywb9yjFzk9 cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= cloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8= cloud.google.com/go/appengine v1.8.7/go.mod h1:1Fwg2+QTgkmN6Y+ALGwV8INLbdkI7+vIvhcKPZCML0g= -cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= -cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= cloud.google.com/go/area120 v0.8.7/go.mod h1:L/xTq4NLP9mmxiGdcsVz7y1JLc9DI8pfaXRXbnjkR6w= -cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= -cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= cloud.google.com/go/artifactregistry v1.14.9/go.mod h1:n2OsUqbYoUI2KxpzQZumm6TtBgtRf++QulEohdnlsvI= -cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= -cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= -cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= cloud.google.com/go/asset v1.19.1/go.mod h1:kGOS8DiCXv6wU/JWmHWCgaErtSZ6uN5noCy0YwVaGfs= -cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= -cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= -cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= cloud.google.com/go/assuredworkloads v1.11.7/go.mod h1:CqXcRH9N0KCDtHhFisv7kk+cl//lyV+pYXGi1h8rCEU= -cloud.google.com/go/auth v0.4.1 h1:Z7YNIhlWRtrnKlZke7z3GMqzvuYzdc2z98F9D1NV5Hg= -cloud.google.com/go/auth v0.4.1/go.mod h1:QVBuVEKpCn4Zp58hzRGvL0tjRGU0YqdRTdCHM1IHnro= -cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= -cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= cloud.google.com/go/automl v1.13.7/go.mod h1:E+s0VOsYXUdXpq0y4gNZpi0A/s6y9+lAarmV5Eqlg40= cloud.google.com/go/baremetalsolution v1.2.6/go.mod h1:KkS2BtYXC7YGbr42067nzFr+ABFMs6cxEcA1F+cedIw= cloud.google.com/go/batch v1.8.5/go.mod h1:YSWU2RTIeoHWVwieZJDTLEfWWUsuk10uhAr5K1dTMiw= cloud.google.com/go/beyondcorp v1.0.6/go.mod h1:wRkenqrVRtnGFfnyvIg0zBFUdN2jIfeojFF9JJDwVIA= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= cloud.google.com/go/bigquery v1.61.0/go.mod h1:PjZUje0IocbuTOdq4DBOJLNYB0WF3pAKBHzAYyxCwFo= -cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= -cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= cloud.google.com/go/billing v1.18.5/go.mod h1:lHw7fxS6p7hLWEPzdIolMtOd0ahLwlokW06BzbleKP8= -cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= -cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= cloud.google.com/go/binaryauthorization v1.8.3/go.mod h1:Cul4SsGlbzEsWPOz2sH8m+g2Xergb6ikspUyQ7iOThE= cloud.google.com/go/certificatemanager v1.8.1/go.mod h1:hDQzr50Vx2gDB+dOfmDSsQzJy/UPrYRdzBdJ5gAVFIc= cloud.google.com/go/channel v1.17.7/go.mod h1:b+FkgBrhMKM3GOqKUvqHFY/vwgp+rwsAuaMd54wCdN4= cloud.google.com/go/cloudbuild v1.16.1/go.mod h1:c2KUANTtCBD8AsRavpPout6Vx8W+fsn5zTsWxCpWgq4= cloud.google.com/go/clouddms v1.7.6/go.mod h1:8HWZ2tznZ0mNAtTpfnRNT0QOThqn9MBUqTj0Lx8npIs= -cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= -cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= cloud.google.com/go/cloudtasks v1.12.8/go.mod h1:aX8qWCtmVf4H4SDYUbeZth9C0n9dBj4dwiTYi4Or/P4= -cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= -cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= -cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= -cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= -cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= -cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= -cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls= @@ -102,73 +44,38 @@ cloud.google.com/go/compute v1.26.0/go.mod h1:T9RIRap4pVHCGUkVFRJ9hygT3KCXjip41X cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/contactcenterinsights v1.13.2/go.mod h1:AfkSB8t7mt2sIY6WpfO61nD9J9fcidIchtxm9FqJVXk= cloud.google.com/go/container v1.35.1/go.mod h1:udm8fgLm3TtpnjFN4QLLjZezAIIp/VnMo316yIRVRQU= -cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= -cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= cloud.google.com/go/containeranalysis v0.11.6/go.mod h1:YRf7nxcTcN63/Kz9f86efzvrV33g/UV8JDdudRbYEUI= -cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= -cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= -cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= cloud.google.com/go/datacatalog v1.20.1/go.mod h1:Jzc2CoHudhuZhpv78UBAjMEg3w7I9jHA11SbRshWUjk= -cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= -cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= cloud.google.com/go/dataflow v0.9.7/go.mod h1:3BjkOxANrm1G3+/EBnEsTEEgJu1f79mFqoOOZfz3v+E= -cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= -cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= cloud.google.com/go/dataform v0.9.4/go.mod h1:jjo4XY+56UrNE0wsEQsfAw4caUs4DLJVSyFBDelRDtQ= cloud.google.com/go/datafusion v1.7.7/go.mod h1:qGTtQcUs8l51lFA9ywuxmZJhS4ozxsBSus6ItqCUWMU= -cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= -cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= cloud.google.com/go/datalabeling v0.8.7/go.mod h1:/PPncW5gxrU15UzJEGQoOT3IobeudHGvoExrtZ8ZBwo= cloud.google.com/go/dataplex v1.16.0/go.mod h1:OlBoytuQ56+7aUCC03D34CtoF/4TJ5SiIrLsBdDu87Q= cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= cloud.google.com/go/dataproc/v2 v2.4.2/go.mod h1:smGSj1LZP3wtnsM9eyRuDYftNAroAl6gvKp/Wk64XDE= -cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= -cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= cloud.google.com/go/dataqna v0.8.7/go.mod h1:hvxGaSvINAVH5EJJsONIwT1y+B7OQogjHPjizOFoWOo= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/datastore v1.17.0/go.mod h1:RiRZU0G6VVlIVlv1HRo3vSAPFHULV0ddBNsXO+Sony4= -cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= -cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= cloud.google.com/go/datastream v1.10.6/go.mod h1:lPeXWNbQ1rfRPjBFBLUdi+5r7XrniabdIiEaCaAU55o= cloud.google.com/go/deploy v1.18.1/go.mod h1:uyUQPHkz695IbRyyCtmU+jypWZlbd69Le55hhAqEx4A= -cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= -cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= -cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= cloud.google.com/go/dialogflow v1.53.0/go.mod h1:LqAvxq7bXiiGC3/DWIz9XXCxth2z2qpSnBAAmlNOj6U= cloud.google.com/go/dlp v1.13.0/go.mod h1:5T/dFtKOn2Q3QLnaKjjir7nEGA8K00WaqoKodLkbF/c= -cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= -cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= cloud.google.com/go/documentai v1.28.0/go.mod h1:ZTt9RkTRmqOn5GQgU4JxHJxbobemOoo6FSy0byEQHqY= -cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= -cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= cloud.google.com/go/domains v0.9.7/go.mod h1:u/yVf3BgfPJW3QDZl51qTJcDXo9PLqnEIxfGmGgbHEc= -cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= -cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= cloud.google.com/go/edgecontainer v1.2.1/go.mod h1:OE2D0lbkmGDVYLCvpj8Y0M4a4K076QB7E2JupqOR/qU= cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= cloud.google.com/go/essentialcontacts v1.6.8/go.mod h1:EHONVDSum2xxG2p+myyVda/FwwvGbY58ZYC4XqI/lDQ= cloud.google.com/go/eventarc v1.13.6/go.mod h1:QReOaYnDNdjwAQQWNC7nfr63WnaKFUw7MSdQ9PXJYj0= cloud.google.com/go/filestore v1.8.3/go.mod h1:QTpkYpKBF6jlPRmJwhLqXfJQjVrQisplyb4e2CwfJWc= cloud.google.com/go/firestore v1.15.0/go.mod h1:GWOxFXcv8GZUtYpWHw/w6IuYNux/BtmeVTMmjrm4yhk= -cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= -cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= cloud.google.com/go/functions v1.16.2/go.mod h1:+gMvV5E3nMb9EPqX6XwRb646jTyVz8q4yk3DD6xxHpg= -cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= -cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= cloud.google.com/go/gkebackup v1.4.1/go.mod h1:tVwSKC1/UxEA011ijRG8vlXaZThzTSy6vReO9fTOlX8= -cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= -cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= cloud.google.com/go/gkeconnect v0.8.7/go.mod h1:iUH1jgQpTyNFMK5LgXEq2o0beIJ2p7KKUUFerkf/eGc= -cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= -cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= cloud.google.com/go/gkehub v0.14.7/go.mod h1:NLORJVTQeCdxyAjDgUwUp0A6BLEaNLq84mCiulsM4OE= cloud.google.com/go/gkemulticloud v1.1.3/go.mod h1:4WzfPnsOfdCIj6weekE5FIGCaeQKZ1HzGNUVZ1PpIxw= -cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= cloud.google.com/go/grafeas v0.3.5/go.mod h1:y54iTBcI+lgUdI+kAPKb8jtPqeTkA2dsYzWSrQtpc5s= cloud.google.com/go/gsuiteaddons v1.6.7/go.mod h1:u+sGBvr07OKNnOnQiB/Co1q4U2cjo50ERQwvnlcpNis= -cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= -cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk= cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= cloud.google.com/go/iam v1.1.7/go.mod h1:J4PMPg8TtyurAUvSmPj8FF3EDgY1SPRZxcUGrn7WXGA= @@ -177,11 +84,7 @@ cloud.google.com/go/ids v1.4.7/go.mod h1:yUkDC71u73lJoTaoONy0dsA0T7foekvg6ZRg9IJ cloud.google.com/go/iot v1.7.7/go.mod h1:tr0bCOSPXtsg64TwwZ/1x+ReTWKlQRVXbM+DnrE54yM= cloud.google.com/go/kms v1.15.8/go.mod h1:WoUHcDjD9pluCg7pNds131awnH429QGvRM3N/4MyoVs= cloud.google.com/go/kms v1.16.0/go.mod h1:olQUXy2Xud+1GzYfiBO9N0RhjsJk5IJLU6n/ethLXVc= -cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= -cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= cloud.google.com/go/language v1.12.5/go.mod h1:w/6a7+Rhg6Bc2Uzw6thRdKKNjnOzfKTJuxzD0JZZ0nM= -cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= -cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= cloud.google.com/go/lifesciences v0.9.7/go.mod h1:FQ713PhjAOHqUVnuwsCe1KPi9oAdaTfh58h1xPiW13g= cloud.google.com/go/logging v1.9.0/go.mod h1:1Io0vnZv4onoUnsVUQY3HZ3Igb1nBchky0A0y7BBBhE= cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s= @@ -189,83 +92,39 @@ cloud.google.com/go/longrunning v0.5.6/go.mod h1:vUaDrWYOMKRuhiv6JBnn49YxCPz2Ayn cloud.google.com/go/longrunning v0.5.7/go.mod h1:8GClkudohy1Fxm3owmBGid8W0pSgodEMwEAztp38Xng= cloud.google.com/go/managedidentities v1.6.7/go.mod h1:UzslJgHnc6luoyx2JV19cTCi2Fni/7UtlcLeSYRzTV8= cloud.google.com/go/maps v1.8.0/go.mod h1:b/O9YYxiySNN0N/9swc9SHIM4b4phuoGORN2/H965Ek= -cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= -cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= cloud.google.com/go/mediatranslation v0.8.7/go.mod h1:6eJbPj1QJwiCP8R4K413qMx6ZHZJUi9QFpApqY88xWU= -cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= -cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= cloud.google.com/go/memcache v1.10.7/go.mod h1:SrU6+QBhvXJV0TA59+B3oCHtLkPx37eqdKmRUlmSE1k= -cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= -cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= cloud.google.com/go/metastore v1.13.6/go.mod h1:OBCVMCP7X9vA4KKD+5J4Q3d+tiyKxalQZnksQMq5MKY= cloud.google.com/go/monitoring v1.19.0/go.mod h1:25IeMR5cQ5BoZ8j1eogHE5VPJLlReQ7zFp5OiLgiGZw= -cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= -cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= cloud.google.com/go/networkconnectivity v1.14.6/go.mod h1:/azB7+oCSmyBs74Z26EogZ2N3UcXxdCHkCPcz8G32bU= cloud.google.com/go/networkmanagement v1.13.2/go.mod h1:24VrV/5HFIOXMEtVQEUoB4m/w8UWvUPAYjfnYZcBc4c= -cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= -cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= cloud.google.com/go/networksecurity v0.9.7/go.mod h1:aB6UiPnh/l32+TRvgTeOxVRVAHAFFqvK+ll3idU5BoY= -cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= -cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= cloud.google.com/go/notebooks v1.11.5/go.mod h1:pz6P8l2TvhWqAW3sysIsS0g2IUJKOzEklsjWJfi8sd4= cloud.google.com/go/optimization v1.6.5/go.mod h1:eiJjNge1NqqLYyY75AtIGeQWKO0cvzD1ct/moCFaP2Q= cloud.google.com/go/orchestration v1.9.2/go.mod h1:8bGNigqCQb/O1kK7PeStSNlyi58rQvZqDiuXT9KAcbg= cloud.google.com/go/orgpolicy v1.12.3/go.mod h1:6BOgIgFjWfJzTsVcib/4QNHOAeOjCdaBj69aJVs//MA= -cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= -cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= cloud.google.com/go/osconfig v1.12.7/go.mod h1:ID7Lbqr0fiihKMwAOoPomWRqsZYKWxfiuafNZ9j1Y1M= -cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= -cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= cloud.google.com/go/oslogin v1.13.3/go.mod h1:WW7Rs1OJQ1iSUckZDilvNBSNPE8on740zF+4ZDR4o8U= -cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= -cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= cloud.google.com/go/phishingprotection v0.8.7/go.mod h1:FtYaOyGc/HQQU7wY4sfwYZBFDKAL+YtVBjUj8E3A3/I= cloud.google.com/go/policytroubleshooter v1.10.5/go.mod h1:bpOf94YxjWUqsVKokzPBibMSAx937Jp2UNGVoMAtGYI= -cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= -cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= cloud.google.com/go/privatecatalog v0.9.7/go.mod h1:NWLa8MCL6NkRSt8jhL8Goy2A/oHkvkeAxiA0gv0rIXI= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/pubsub v1.37.0/go.mod h1:YQOQr1uiUM092EXwKs56OPT650nwnawc+8/IjoUeGzQ= cloud.google.com/go/pubsub v1.38.0/go.mod h1:IPMJSWSus/cu57UyR01Jqa/bNOQA+XnPF6Z4dKW4fAA= cloud.google.com/go/pubsublite v1.8.1/go.mod h1:fOLdU4f5xldK4RGJrBMm+J7zMWNj/k4PxwEZXy39QS0= -cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= -cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= -cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= -cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= cloud.google.com/go/recaptchaenterprise/v2 v2.13.0/go.mod h1:jNYyn2ScR4DTg+VNhjhv/vJQdaU8qz+NpmpIzEE7HFQ= -cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= -cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= cloud.google.com/go/recommendationengine v0.8.7/go.mod h1:YsUIbweUcpm46OzpVEsV5/z+kjuV6GzMxl7OAKIGgKE= -cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= -cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= cloud.google.com/go/recommender v1.12.3/go.mod h1:OgN0MjV7/6FZUUPgF2QPQtYErtZdZc4u+5onvurcGEI= -cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= -cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= cloud.google.com/go/redis v1.14.4/go.mod h1:EnHDflqTNQmCBPCN4FQPZdM28vLdweAgxe6avAZpqug= cloud.google.com/go/resourcemanager v1.9.7/go.mod h1:cQH6lJwESufxEu6KepsoNAsjrUtYYNXRwxm4QFE5g8A= cloud.google.com/go/resourcesettings v1.6.7/go.mod h1:zwRL5ZoNszs1W6+eJYMk6ILzgfnTj13qfU4Wvfupuqk= -cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= -cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= cloud.google.com/go/retail v1.16.2/go.mod h1:T7UcBh4/eoxRBpP3vwZCoa+PYA9/qWRTmOCsV8DRdZ0= cloud.google.com/go/run v1.3.7/go.mod h1:iEUflDx4Js+wK0NzF5o7hE9Dj7QqJKnRj0/b6rhVq20= -cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= -cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= cloud.google.com/go/scheduler v1.10.8/go.mod h1:0YXHjROF1f5qTMvGTm4o7GH1PGAcmu/H/7J7cHOiHl0= -cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= cloud.google.com/go/secretmanager v1.13.0/go.mod h1:yWdfNmM2sLIiyv6RM6VqWKeBV7CdS0SO3ybxJJRhBEs= -cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= -cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= -cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= cloud.google.com/go/security v1.16.1/go.mod h1:UoF8QXvvJlV9ORs4YW/izW5GmDQtFUoq2P6TJgPlif8= -cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= -cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= cloud.google.com/go/securitycenter v1.30.0/go.mod h1:/tmosjS/dfTnzJxOzZhTXdX3MXWsCmPWfcYOgkJmaJk= cloud.google.com/go/servicecontrol v1.10.0/go.mod h1:pQvyvSRh7YzUF2efw7H87V92mxU8FnFDawMClGCNuAA= cloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk= -cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= -cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= cloud.google.com/go/servicedirectory v1.11.6/go.mod h1:peVGYNc1xArhcqSuhPP+NXp8kdl22XhB5E8IiNBNfZY= cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= cloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4= @@ -273,77 +132,55 @@ cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLo cloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DRwPG1xtWMDeuPA= cloud.google.com/go/shell v1.7.7/go.mod h1:7OYaMm3TFMSZBh8+QYw6Qef+fdklp7CjjpxYAoJpZbQ= cloud.google.com/go/spanner v1.61.0/go.mod h1:+hdNE+zL7EWNfOWRetw01jxz8H5qsE/ayZvF/pfrAl8= -cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= -cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= cloud.google.com/go/speech v1.23.1/go.mod h1:UNgzNxhNBuo/OxpF1rMhA/U2rdai7ILL6PBXFs70wq0= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= -cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= -cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= +cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= -cloud.google.com/go/storage v1.41.0 h1:RusiwatSu6lHeEXe3kglxakAmAbfV+rhtPqA6i8RBx0= -cloud.google.com/go/storage v1.41.0/go.mod h1:J1WCa/Z2FcgdEDuPUY8DxT5I+d9mFKsCepp5vR6Sq80= cloud.google.com/go/storagetransfer v1.10.6/go.mod h1:3sAgY1bx1TpIzfSzdvNGHrGYldeCTyGI/Rzk6Lc6A7w= -cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= -cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= cloud.google.com/go/talent v1.6.8/go.mod h1:kqPAJvhxmhoUTuqxjjk2KqA8zUEeTDmH+qKztVubGlQ= cloud.google.com/go/texttospeech v1.7.7/go.mod h1:XO4Wr2VzWHjzQpMe3gS58Oj68nmtXMyuuH+4t0wy9eA= cloud.google.com/go/tpu v1.6.7/go.mod h1:o8qxg7/Jgt7TCgZc3jNkd4kTsDwuYD3c4JTMqXZ36hU= cloud.google.com/go/trace v1.10.7/go.mod h1:qk3eiKmZX0ar2dzIJN/3QhY2PIFh1eqcIdaN5uEjQPM= cloud.google.com/go/translate v1.10.3/go.mod h1:GW0vC1qvPtd3pgtypCv4k4U8B7EdgK9/QEF2aJEUovs= cloud.google.com/go/video v1.20.6/go.mod h1:d5AOlIfWXpDg15wvztHmjFvKTTImWJU7EnMVWkoiEAk= -cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= -cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= cloud.google.com/go/videointelligence v1.11.7/go.mod h1:iMCXbfjurmBVgKuyLedTzv90kcnppOJ6ttb0+rLDID0= -cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= -cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= -cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= cloud.google.com/go/vision/v2 v2.8.2/go.mod h1:BHZA1LC7dcHjSr9U9OVhxMtLKd5l2jKPzLRALEJvuaw= cloud.google.com/go/vmmigration v1.7.7/go.mod h1:qYIK5caZY3IDMXQK+A09dy81QU8qBW0/JDTc39OaKRw= cloud.google.com/go/vmwareengine v1.1.3/go.mod h1:UoyF6LTdrIJRvDN8uUB8d0yimP5A5Ehkr1SRzL1APZw= cloud.google.com/go/vpcaccess v1.7.7/go.mod h1:EzfSlgkoAnFWEMznZW0dVNvdjFjEW97vFlKk4VNBhwY= -cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= -cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= cloud.google.com/go/webrisk v1.9.7/go.mod h1:7FkQtqcKLeNwXCdhthdXHIQNcFWPF/OubrlyRcLHNuQ= cloud.google.com/go/websecurityscanner v1.6.7/go.mod h1:EpiW84G5KXxsjtFKK7fSMQNt8JcuLA8tQp7j0cyV458= -cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= -cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= cloud.google.com/go/workflows v1.12.6/go.mod h1:oDbEHKa4otYg4abwdw2Z094jB0TLLiFGAPA78EDAKag= -contrib.go.opencensus.io/exporter/prometheus v0.4.2 h1:sqfsYl5GIY/L570iT+l93ehxaWJs2/OwXtiWwew3oAg= -contrib.go.opencensus.io/exporter/prometheus v0.4.2/go.mod h1:dvEHbiKmgvbr5pjaF9fpw1KeYcjrnC1J8B+JKjsZyRQ= +cosmossdk.io/api v0.3.1/go.mod h1:DfHfMkiNA2Uhy8fj0JJlOCYOBp4eWUUJ1te5zBGNyIw= +cosmossdk.io/api v0.7.0/go.mod h1:kJFAEMLN57y0viszHDPLMmieF0471o5QAwwApa+270M= cosmossdk.io/api v0.7.2/go.mod h1:IcxpYS5fMemZGqyYtErK7OqvdM0C8kdW3dq8Q/XIG38= -cosmossdk.io/api v0.7.5 h1:eMPTReoNmGUm8DeiQL9DyM8sYDjEhWzL1+nLbI9DqtQ= -cosmossdk.io/api v0.7.5/go.mod h1:IcxpYS5fMemZGqyYtErK7OqvdM0C8kdW3dq8Q/XIG38= +cosmossdk.io/core v0.5.1/go.mod h1:KZtwHCLjcFuo0nmDc24Xy6CRNEL9Vl/MeimQ2aC7NLE= cosmossdk.io/errors v1.0.0/go.mod h1:+hJZLuhdDE0pYN8HkOrVNwrIOYvUGnn6+4fjnJs/oV0= cosmossdk.io/log v1.2.0/go.mod h1:GNSCc/6+DhFIj1aLn/j7Id7PaO8DzNylUZoOYBL9+I4= cosmossdk.io/log v1.2.1/go.mod h1:GNSCc/6+DhFIj1aLn/j7Id7PaO8DzNylUZoOYBL9+I4= +cosmossdk.io/math v1.1.2/go.mod h1:l2Gnda87F0su8a/7FEKJfFdJrM0JZRXQaohlgJeyQh0= cosmossdk.io/math v1.2.0/go.mod h1:l2Gnda87F0su8a/7FEKJfFdJrM0JZRXQaohlgJeyQh0= +cosmossdk.io/store v0.1.0-alpha.1/go.mod h1:kmCMbhrleCZ6rDZPY/EGNldNvPebFNyVPFYp+pv05/k= cosmossdk.io/store v1.0.0/go.mod h1:ABMprwjvx6IpMp8l06TwuMrj6694/QP5NIW+X6jaTYc= cosmossdk.io/tools/confix v0.1.0/go.mod h1:TdXKVYs4gEayav5wM+JHT+kTU2J7fozFNqoVaN+8CdY= cosmossdk.io/tools/confix v0.1.1/go.mod h1:nQVvP1tHsGXS83PonPVWJtSbddIqyjEw99L4M3rPJyQ= -cosmossdk.io/x/circuit v0.1.1/go.mod h1:B6f/urRuQH8gjt4eLIXfZJucrbreuYrKh5CSjaOxr+Q= -cosmossdk.io/x/evidence v0.1.1 h1:Ks+BLTa3uftFpElLTDp9L76t2b58htjVbSZ86aoK/E4= -cosmossdk.io/x/evidence v0.1.1/go.mod h1:OoDsWlbtuyqS70LY51aX8FBTvguQqvFrt78qL7UzeNc= -cosmossdk.io/x/feegrant v0.1.1 h1:EKFWOeo/pup0yF0svDisWWKAA9Zags6Zd0P3nRvVvw8= -cosmossdk.io/x/feegrant v0.1.1/go.mod h1:2GjVVxX6G2fta8LWj7pC/ytHjryA6MHAJroBWHFNiEQ= +cosmossdk.io/tools/rosetta v0.2.1 h1:ddOMatOH+pbxWbrGJKRAawdBkPYLfKXutK9IETnjYxw= +cosmossdk.io/tools/rosetta v0.2.1/go.mod h1:Pqdc1FdvkNV3LcNIkYWt2RQY6IP1ge6YWZk8MhhO9Hw= cosmossdk.io/x/tx v0.12.0/go.mod h1:qTth2coAGkwCwOCjqQ8EAQg+9udXNRzcnSbMgGKGEI0= -cosmossdk.io/x/tx v0.13.3 h1:Ha4mNaHmxBc6RMun9aKuqul8yHiL78EKJQ8g23Zf73g= -cosmossdk.io/x/tx v0.13.3/go.mod h1:I8xaHv0rhUdIvIdptKIqzYy27+n2+zBVaxO6fscFhys= cosmossdk.io/x/upgrade v0.1.0/go.mod h1:/6jjNGbiPCNtmA1N+rBtP601sr0g4ZXuj3yC6ClPCGY= -cosmossdk.io/x/upgrade v0.1.3 h1:q4XpXc6zp0dX6x74uBtfN6+J7ikaQev5Bla6Q0ADLK8= -cosmossdk.io/x/upgrade v0.1.3/go.mod h1:jOdQhnaY5B8CDUoUbed23/Lre0Dk+r6BMQE40iKlVVQ= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= firebase.google.com/go v3.12.0+incompatible/go.mod h1:xlah6XbEyW6tbfSklcfe5FHJIwjt8toICdV5Wh9ptHs= gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= +git.sr.ht/~sbinet/gg v0.5.0/go.mod h1:G2C0eRESqlKhS7ErsNey6HHrqU1PwsnCQlekFi9Q2Oo= github.com/2opremio/pretty v0.2.2-0.20230601220618-e1d5758b2a95/go.mod h1:Gv4NIpY67KDahg+DtIG5/2Ok4l8vzYEekiirSCH+IGA= github.com/99designs/keyring v1.2.1/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= +github.com/Abirdcfly/dupword v0.0.7/go.mod h1:K/4M1kj+Zh39d2aotRwypvasonOyAMH1c/IZJzE0dmk= github.com/Abirdcfly/dupword v0.0.11/go.mod h1:wH8mVGuf3CP5fsBTkfWwwwKTjDnVVCxtU8d8rgeVYXA= +github.com/Antonboom/errname v0.1.7/go.mod h1:g0ONh16msHIPgJSGsecu1G/dcF2hlYR/0SddnIAGavU= github.com/Antonboom/errname v0.1.9/go.mod h1:nLTcJzevREuAsgTbG85UsuiWpMpAqbKD1HNZ29OzE58= +github.com/Antonboom/nilnil v0.1.1/go.mod h1:L1jBqoWM7AOeTD+tSquifKSesRHs4ZdaxvZR+xdJEaI= github.com/Antonboom/nilnil v0.1.3/go.mod h1:iOov/7gRcXkeEU+EMGpBu2ORih3iyVEiWjeste1SJm8= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U= @@ -352,8 +189,8 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0/ github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0/go.mod h1:+6KLcKIVgxoBDMqMO/Nvy7bZ9a0nbU3I1DtFQK3YvB4= github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= -github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= +github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= +github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/ChainSafe/go-schnorrkel v1.0.0 h1:3aDA67lAykLaG1y3AOjs88dMxC88PgUuHRrLeDnvGIM= github.com/ChainSafe/go-schnorrkel v1.0.0/go.mod h1:dpzHYVxLZcp8pjlV+O+UR8K0Hp/z7vcchBSbMBEhCw4= github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= @@ -362,276 +199,241 @@ github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mo github.com/CloudyKit/jet/v6 v6.2.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4= github.com/ComposableFi/go-subkey/v2 v2.0.0-tm03420 h1:oknQF/iIhf5lVjbwjsVDzDByupRhga8nhA3NAmwyHDA= github.com/ComposableFi/go-subkey/v2 v2.0.0-tm03420/go.mod h1:KYkiMX5AbOlXXYfxkrYPrRPV6EbVUALTQh5ptUOJzu8= -github.com/CosmWasm/wasmd v0.52.0 h1:VRylqes1AMXqIgz/jUH9EzhjBZKsRXrrjCTAni0ILRM= -github.com/CosmWasm/wasmd v0.52.0/go.mod h1:hyy1wt7c589Cs4kOK2cYdtphzCd2Xo20q/t7tfby7oI= +github.com/CosmWasm/wasmd v0.45.0 h1:9zBqrturKJwC2kVsfHvbrA++EN0PS7UTXCffCGbg6JI= +github.com/CosmWasm/wasmd v0.45.0/go.mod h1:RnSAiqbNIZu4QhO+0pd7qGZgnYAMBPGmXpzTADag944= github.com/CosmWasm/wasmvm v1.4.0 h1:84I3MlvvzcOo2z+ed0ztPi7eeDNk6/sYuK76uyXP1nI= github.com/CosmWasm/wasmvm v1.4.0/go.mod h1:vW/E3h8j9xBQs9bCoijDuawKo9kCtxOaS8N8J7KFtkc= -github.com/CosmWasm/wasmvm/v2 v2.1.0 h1:bleLhNA36hM8iPjFJsNRi9RjrQW6MtXafw2+wVjAWAE= -github.com/CosmWasm/wasmvm/v2 v2.1.0/go.mod h1:bMhLQL4Yp9CzJi9A83aR7VO9wockOsSlZbT4ztOl6bg= +github.com/CosmWasm/wasmvm v1.5.0 h1:3hKeT9SfwfLhxTGKH3vXaKFzBz1yuvP8SlfwfQXbQfw= +github.com/CosmWasm/wasmvm v1.5.0/go.mod h1:fXB+m2gyh4v9839zlIXdMZGeLAxqUdYdFQqYsTha2hc= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= -github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e h1:ahyvB3q25YnZWly5Gq1ekg6jcmWaGj/vG/MhF4aisoc= -github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw= -github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec h1:1Qb69mGp/UtRPn422BH4/Y4Q3SLUrD9KHuDkm8iodFc= -github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec/go.mod h1:CD8UlnlLDiqb36L110uqiP2iSflVjx9g/3U9hCI4q2U= github.com/GaijinEntertainment/go-exhaustruct/v2 v2.3.0/go.mod h1:b3g59n2Y+T5xmcxJL+UEG2f8cQploZm1mR/v6BW0mU0= github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20190129172621-c8b1d7a94ddf/go.mod h1:aJ4qN3TfrelA6NZ6AXsXRfmEVaYin3EDbSPJrKS8OXo= github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.0/go.mod h1:dppbR7CwXD4pgtV9t3wD1812RaLDcBjtblcDF5f1vI0= +github.com/HdrHistogram/hdrhistogram-go v1.1.0/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/sprig/v3 v3.2.1/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= -github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= github.com/OpenPeeDeeP/depguard v1.1.1/go.mod h1:JtAMzWkmFEzDPyAd+W0NHl1lvpQKTvT9jnRVsohBKpc= +github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8= github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM= github.com/Shopify/sarama v1.26.4/go.mod h1:NbSGBSSndYaIhRcBtY9V0U7AyH+x71bG668AuWys/yU= github.com/StirlingMarketingGroup/go-namecase v1.0.0 h1:2CzaNtCzc4iNHirR+5ru9OzGg8rQp860gqLBFqRI02Y= github.com/StirlingMarketingGroup/go-namecase v1.0.0/go.mod h1:ZsoSKcafcAzuBx+sndbxHu/RjDcDTrEdT4UvhniHfio= -github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI= -github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI= github.com/aclements/go-gg v0.0.0-20170118225347-6dbb4e4fefb0/go.mod h1:55qNq4vcpkIuHowELi5C8e+1yUHtoLoOUR9QU5j7Tes= github.com/aclements/go-moremath v0.0.0-20210112150236-f10218a38794/go.mod h1:7e+I0LQFUI9AXWxOfsQROs9xPhoJtbsyWcjJqDd4KPY= +github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/adjust/goautoneg v0.0.0-20150426214442-d788f35a0315/go.mod h1:4U522XvlkqOY2AVBUM7ISHODDb6tdB+KAXfGaBDsWts= -github.com/adlio/schema v1.3.3/go.mod h1:1EsRssiv9/Ce2CMzq5DoL7RiMshhuigQxrR4DMV9fHg= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20210923152817-c3b6e2f0c527/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= -github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= -github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/apache/arrow/go/v15 v15.0.2/go.mod h1:DGXsR3ajT524njufqf95822i+KTh+yea1jass9YXgjA= github.com/araddon/gou v0.0.0-20190110011759-c797efecbb61/go.mod h1:ikc1XA58M+Rx7SEbf0bLJCfBkwayZ8T5jBo5FXK8Uz8= +github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/ashanbrown/forbidigo v1.3.0/go.mod h1:vVW7PEdqEFqapJe95xHkTfB1+XvZXBFg8t0sG2FIxmI= github.com/ashanbrown/forbidigo v1.5.1/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU= github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aws/aws-sdk-go v1.33.2/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= +github.com/aws/aws-sdk-go v1.44.203/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go v1.44.224/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= -github.com/aws/aws-sdk-go v1.53.2 h1:KhTx/eMkavqkpmrV+aBc+bWADSTzwKxTXOvGmRImgFs= -github.com/aws/aws-sdk-go v1.53.2/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= github.com/aws/aws-sdk-go-v2 v1.21.2/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM= -github.com/aws/aws-sdk-go-v2 v1.26.0 h1:/Ce4OCiM3EkpW7Y+xUnfAFpchU78K7/Ug01sZni9PgA= -github.com/aws/aws-sdk-go-v2 v1.26.0/go.mod h1:35hUlJVYd+M++iLI3ALmVwMOyRYMmRqUXpTtRGW+K9I= github.com/aws/aws-sdk-go-v2/config v1.18.45/go.mod h1:ZwDUgFnQgsazQTnWfeLWk5GjeqTQTL8lMkoE1UXzxdE= -github.com/aws/aws-sdk-go-v2/config v1.27.9 h1:gRx/NwpNEFSk+yQlgmk1bmxxvQ5TyJ76CWXs9XScTqg= -github.com/aws/aws-sdk-go-v2/config v1.27.9/go.mod h1:dK1FQfpwpql83kbD873E9vz4FyAxuJtR22wzoXn3qq0= github.com/aws/aws-sdk-go-v2/credentials v1.13.43/go.mod h1:zWJBz1Yf1ZtX5NGax9ZdNjhhI4rgjfgsyk6vTY1yfVg= -github.com/aws/aws-sdk-go-v2/credentials v1.17.9 h1:N8s0/7yW+h8qR8WaRlPQeJ6czVMNQVNtNdUqf6cItao= -github.com/aws/aws-sdk-go-v2/credentials v1.17.9/go.mod h1:446YhIdmSV0Jf/SLafGZalQo+xr2iw7/fzXGDPTU1yQ= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13/go.mod h1:f/Ib/qYjhV2/qdsf79H3QP/eRE4AkVyEf6sk7XfZ1tg= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.0 h1:af5YzcLf80tv4Em4jWVD75lpnOHSBkPUZxZfGkrI3HI= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.0/go.mod h1:nQ3how7DMnFMWiU1SpECohgC82fpn4cKZ875NDMmwtA= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43/go.mod h1:auo+PiyLl0n1l8A0e8RIeR8tOzYPfZZH/JNlrJ8igTQ= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4 h1:0ScVK/4qZ8CIW0k8jOeFVsyS/sAiXpYxRBLolMkuLQM= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4/go.mod h1:84KyjNZdHC6QZW08nfHI6yZgPd+qRgaWcYsyLUo3QY8= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37/go.mod h1:Qe+2KtKml+FEsQF/DHmDV+xjtche/hwoF75EG4UlHW8= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4 h1:sHmMWWX5E7guWEFQ9SVo6A3S4xpPrWnd77a6y4WM6PU= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4/go.mod h1:WjpDrhWisWOIoS9n3nk67A3Ll1vfULJ9Kq6h29HTD48= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45/go.mod h1:lD5M20o09/LCuQ2mE62Mb/iSdSlCNuj6H5ci7tW7OsE= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 h1:EyBZibRTVAs6ECHZOw5/wlylS9OcTzwyjeQMudmREjE= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1/go.mod h1:JKpmtYhhPs7D97NL/ltqz7yCkERFW5dOlHyVl66ZYF8= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.37/go.mod h1:vBmDnwWXWxNPFRMmG2m/3MKOe+xEcMDo1tanpaWCcck= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6 h1:b+E7zIUHMmcB4Dckjpkapoy47W6C9QBv/zoUP+Hn8Kc= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6/go.mod h1:S2fNV0rxrP78NhPbCZeQgY8H9jdDMeGtwcfZIRxzBqU= -github.com/aws/aws-sdk-go-v2/service/kms v1.30.0 h1:yS0JkEdV6h9JOo8sy2JSpjX+i7vsKifU8SIeHrqiDhU= -github.com/aws/aws-sdk-go-v2/service/kms v1.30.0/go.mod h1:+I8VUUSVD4p5ISQtzpgSva4I8cJ4SQ4b1dcBcof7O+g= github.com/aws/aws-sdk-go-v2/service/route53 v1.30.2/go.mod h1:TQZBt/WaQy+zTHoW++rnl8JBrmZ0VO6EUbVua1+foCA= github.com/aws/aws-sdk-go-v2/service/sso v1.15.2/go.mod h1:gsL4keucRCgW+xA85ALBpRFfdSLH4kHOVSnLMSuBECo= -github.com/aws/aws-sdk-go-v2/service/sso v1.20.3 h1:mnbuWHOcM70/OFUlZZ5rcdfA8PflGXXiefU/O+1S3+8= -github.com/aws/aws-sdk-go-v2/service/sso v1.20.3/go.mod h1:5HFu51Elk+4oRBZVxmHrSds5jFXmFj8C3w7DVF2gnrs= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.3/go.mod h1:a7bHA82fyUXOm+ZSWKU6PIoBxrjSprdLoM8xPYvzYVg= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3 h1:uLq0BKatTmDzWa/Nu4WO0M1AaQDaPpwTKAeByEc6WFM= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3/go.mod h1:b+qdhjnxj8GSR6t5YfphOffeoQSQ1KmpoVVuBn+PWxs= github.com/aws/aws-sdk-go-v2/service/sts v1.23.2/go.mod h1:Eows6e1uQEsc4ZaHANmsPRzAKcVDrcmjjWiih2+HUUQ= -github.com/aws/aws-sdk-go-v2/service/sts v1.28.5 h1:J/PpTf/hllOjx8Xu9DMflff3FajfLxqM5+tepvVXmxg= -github.com/aws/aws-sdk-go-v2/service/sts v1.28.5/go.mod h1:0ih0Z83YDH/QeQ6Ori2yGE2XvWYv/Xm+cZc01LC6oK0= +github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.15.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= -github.com/aws/smithy-go v1.20.1 h1:4SZlSlMr36UEqC7XOyRVb27XMeZubNcBNN+9IgEPIQw= -github.com/aws/smithy-go v1.20.1/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/bitly/go-hostpool v0.1.0/go.mod h1:4gOCgp6+NZnVqlKyZ/iBZFTAJKembaVENUpMkpg42fw= github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= -github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= -github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bkielbasa/cyclop v1.2.0/go.mod h1:qOI0yy6A7dYC4Zgsa72Ppm9kONl0RoIlPbzot9mhmeI= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= -github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= +github.com/bombsimon/wsl/v3 v3.3.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc= github.com/bombsimon/wsl/v3 v3.4.0/go.mod h1:KkIB+TXkqy6MvK9BDZVbZxKNYsE1/oLRJbIFtf14qqo= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/breml/bidichk v0.2.3/go.mod h1:8u2C6DnAy0g2cEq+k/A2+tr9O1s+vHGxWn0LTc70T2A= github.com/breml/bidichk v0.2.4/go.mod h1:7Zk0kRFt1LIZxtQdl9W9JwGAcLTTkOs+tN7wuEYGJ3s= +github.com/breml/errchkjson v0.3.0/go.mod h1:9Cogkyv9gcT8HREpzi3TiqBxCqDzo8awa92zSDFcofU= github.com/breml/errchkjson v0.3.1/go.mod h1:XroxrzKjdiutFyW3nWhw34VGg7kiMsDQox73yWCGI2U= -github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= github.com/btcsuite/btcd v0.23.0/go.mod h1:0QJIIN1wwIXF/3G/m87gIwGniDMDQqjVn4SZgnFpsYY= -github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd h1:js1gPwhcFflTZ7Nzl7WHaOTlTr5hIrR4n1NM4v9n4Kw= -github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A= -github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= -github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= +github.com/btcsuite/btcd/btcec/v2 v2.2.1/go.mod h1:9/CSmJxmuvqzX9Wh2fXMWToLOHhPd11lSPuIupwTkI8= github.com/btcsuite/btcd/btcec/v2 v2.3.3 h1:6+iXlDKE8RMtKsvK0gshlXIuPbyWM/h84Ensb7o3sC0= github.com/btcsuite/btcd/btcec/v2 v2.3.3/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= -github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= -github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= -github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8= -github.com/btcsuite/btcd/btcutil v1.1.5/go.mod h1:PSZZ4UitpLBWzxGd5VGOrLnmOjtPP/a6HaFo12zMs00= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= -github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= -github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= +github.com/btcsuite/btcd/btcutil v1.1.2/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= +github.com/bufbuild/buf v1.7.0/go.mod h1:Go40fMAF46PnPLC7jJgTQhAI95pmC0+VtxFKVC0qLq0= github.com/bufbuild/buf v1.15.1/go.mod h1:TQeGKam1QMfHy/xsSnnMpxN3JK5HBb6aNvZj4m52gkE= +github.com/bufbuild/connect-go v1.0.0/go.mod h1:9iNvh/NOsfhNBUH5CtvXeVUskQO1xsrEviH7ZArwZ3I= github.com/bufbuild/connect-go v1.5.2/go.mod h1:GmMJYR6orFqD0Y6ZgX8pwQ8j9baizDrIQMm1/a6LnHk= +github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= github.com/bufbuild/protocompile v0.5.1/go.mod h1:G5iLmavmF4NsYtpZFvE3B/zFch2GIY8+wjsYLR/lc40= github.com/buger/goreplay v1.3.2/go.mod h1:EyAKHxJR6K6phd0NaoPETSDbJRB/ogIw3Y15UlSbVBM= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/butuzov/ireturn v0.1.1/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc= +github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8= github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= -github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/charithe/durationcheck v0.0.9/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6prSM8ap1UCpNKtgg= github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ= +github.com/chavacava/garif v0.0.0-20220630083739-93517212f375/go.mod h1:4m1Rv7xfuwWPNKXlThldNuJvutYM6J95wNuuVmn55To= github.com/chavacava/garif v0.0.0-20230227094218-b8c73b2037b8/go.mod h1:gakxgyXaaPkxvLw1XQxNGK4I37ys9iBRzNUx/B7pUCo= github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= -github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= github.com/chigopher/pathlib v0.12.0/go.mod h1:EJ5UtJ/sK8Nt6q3VWN+EwZLZ3g0afJiG8NegYiQQ/gQ= github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= -github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= +github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cloudflare/cloudflare-go v0.79.0/go.mod h1:gkHQf9xEubaQPEuerBuoinR9P8bf8a05Lq0X6WKy1Oc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50/go.mod h1:5e1+Vvlzido69INQaVO6d87Qn543Xr6nooe9Kz7oBFM= +github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cockroachdb/datadriven v1.0.0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4= github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.6.1/go.mod h1:tm6FTP5G81vwJ5lC0SizQo374JNCOPrHyXGitRJoDqM= github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac= -github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= -github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= -github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= -github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= +github.com/cockroachdb/errors v1.10.0/go.mod h1:lknhIsEVQ9Ss/qKDBQS/UqFSvPQjOwNq2qyKAxtHRqE= github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/cockroachdb/pebble v0.0.0-20220817183557-09c6e030a677/go.mod h1:890yq1fUb9b6dGNwssgeUO5vQV9qfXnCPxAJhBQfXw0= +github.com/cockroachdb/pebble v0.0.0-20230525220056-bb4fc9527b3b/go.mod h1:TkdVsGYRqtULUppt2RbC+YaKtTHnHoWa2apfFrSKABw= github.com/cockroachdb/pebble v0.0.0-20231101195458-481da04154d6/go.mod h1:acMRUGd/BK8AUmQNK3spUCCGzFLZU2bSST3NMXSq2Kc= -github.com/cockroachdb/pebble v1.1.1 h1:XnKU22oiCLy2Xn8vp1re67cXg4SAasg/WDt1NtcRFaw= github.com/cockroachdb/pebble v1.1.1/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU= github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= +github.com/coinbase/rosetta-sdk-go v0.4.6 h1:zX2SLmBF1oFbK0c4QCMwkwcHN9VjenFfIt0Dr8k8JGY= +github.com/coinbase/rosetta-sdk-go/types v1.0.0 h1:jpVIwLcPoOeCR6o1tU+Xv7r5bMONNbHU7MuEHboiFuA= +github.com/coinbase/rosetta-sdk-go/types v1.0.0/go.mod h1:eq7W2TMRH22GTW0N0beDnN931DW0/WOI1R2sdHNHG4c= +github.com/cometbft/cometbft v0.38.0/go.mod h1:5Jz0Z8YsHSf0ZaAqGvi/ifioSdVFPtEGrm8Y9T/993k= github.com/cometbft/cometbft v0.38.2/go.mod h1:PIi48BpzwlHqtV3mzwPyQgOyOnU94BNBimLS2ebBHOg= github.com/cometbft/cometbft v0.38.7/go.mod h1:HIyf811dFMI73IE0F7RrnY/Fr+d1+HuJAgtkEpQjCMY= github.com/cometbft/cometbft v0.38.9/go.mod h1:xOoGZrtUT+A5izWfHSJgl0gYZUE7lu7Z2XIS1vWG/QQ= -github.com/cometbft/cometbft v0.38.10 h1:2ePuglchT+j0Iao+cfmt/nw5U7K2lnGDzXSUPGVdXaU= -github.com/cometbft/cometbft v0.38.10/go.mod h1:jHPx9vQpWzPHEAiYI/7EDKaB1NXhK6o3SArrrY8ExKc= github.com/cometbft/cometbft-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= +github.com/cometbft/cometbft-db v0.8.0/go.mod h1:6ASCP4pfhmrCBpfk01/9E1SI29nD3HfVHrY4PG8x5c0= github.com/coming-chat/lcs v0.0.0-20220829063658-0fa8432d2bdf/go.mod h1:CVVNl2j3TGYyUjuux+oYrRenPGvD+5UQbPGYp/zUews= +github.com/confio/ics23/go v0.9.0 h1:cWs+wdbS2KRPZezoaaj+qBleXgUk5WOQFMP3CQFGTr4= +github.com/confio/ics23/go v0.9.0/go.mod h1:4LPZ2NYqnYIVRklaozjNR1FScgDJ2s5Xrp+e/mYVRak= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= -github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= +github.com/containerd/containerd v1.6.8/go.mod h1:By6p5KqPK0/7/CgO/A6t/Gz+CUYUu2zf1hUaaymVXB0= github.com/containerd/stargz-snapshotter/estargz v0.12.1/go.mod h1:12VUuCq3qPq4y8yUW+l5w3+oXV3cx2Po3KSe/SmPGqw= +github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cosmos/cosmos-db v1.0.0/go.mod h1:iBvi1TtqaedwLdcrZVYRSSCb6eSy61NLj4UNmdIgs0U= +github.com/cosmos/cosmos-proto v1.0.0-beta.2/go.mod h1:+XRCLJ14pr5HFEHIUcn51IKXD1Fy3rkEQqt4WqmN4V0= github.com/cosmos/cosmos-proto v1.0.0-beta.3/go.mod h1:t8IASdLaAq+bbHbjq4p960BvcTqtwuAxid3b/2rOD6I= +github.com/cosmos/cosmos-sdk v0.47.5 h1:n1+WjP/VM/gAEOx3TqU2/Ny734rj/MX1kpUnn7zVJP8= +github.com/cosmos/cosmos-sdk v0.47.5/go.mod h1:EHwCeN9IXonsjKcjpS12MqeStdZvIdxt3VYXhus3G3c= +github.com/cosmos/cosmos-sdk v0.47.6/go.mod h1:xTc1chW8HyUWCfrgGbjS5jNu9RzlPVrBNfbL9RmZUio= github.com/cosmos/cosmos-sdk v0.50.1/go.mod h1:fsLSPGstCwn6MMsFDMAQWGJj8E4sYsN9Gnu1bGE5imA= github.com/cosmos/cosmos-sdk v0.50.7/go.mod h1:84xDDJEHttRT7NDGwBaUOLVOMN0JNE9x7NbsYIxXs1s= -github.com/cosmos/cosmos-sdk v0.50.8 h1:2UJHssUaGHTl4/dFp8xyREKAnfiRU6VVfqtKG9n8w5g= -github.com/cosmos/cosmos-sdk v0.50.8/go.mod h1:Zb+DgHtiByNwgj71IlJBXwOq6dLhtyAq3AgqpXm/jHo= +github.com/cosmos/cosmos-sdk/db v1.0.0-beta.1.0.20220726092710-f848e4300a8a/go.mod h1:c8IO23vgNxueCCJlSI9awQtcxsvc+buzaeThB85qfBU= +github.com/cosmos/gogoproto v1.4.1/go.mod h1:Ac9lzL4vFpBMcptJROQ6dQ4M3pOEK5Z/l0Q9p+LoCr4= github.com/cosmos/gogoproto v1.4.3/go.mod h1:0hLIG5TR7IvV1fme1HCFKjfzW9X2x0Mo+RooWXCnOWU= +github.com/cosmos/gogoproto v1.4.10/go.mod h1:3aAZzeRWpAwr+SS/LLkICX2/kDFyaYVzckBDzygIxek= github.com/cosmos/gogoproto v1.4.11/go.mod h1:/g39Mh8m17X8Q/GDEs5zYTSNaNnInBSohtaxzQnYq1Y= -github.com/cosmos/gogoproto v1.5.0 h1:SDVwzEqZDDBoslaeZg+dGE55hdzHfgUA40pEanMh52o= github.com/cosmos/gogoproto v1.5.0/go.mod h1:iUM31aofn3ymidYG6bUR5ZFrk+Om8p5s754eMUcyp8I= +github.com/cosmos/iavl v0.20.0/go.mod h1:WO7FyvaZJoH65+HFOsDir7xU9FWk2w9cHXNW1XHcl7A= github.com/cosmos/iavl v1.0.0/go.mod h1:CmTGqMnRnucjxbjduneZXT+0vPgNElYvdefjX2q9tYc= github.com/cosmos/iavl v1.1.1/go.mod h1:jLeUvm6bGT1YutCaL2fIar/8vGUE8cPZvh/gXEWDaDM= -github.com/cosmos/iavl v1.2.0 h1:kVxTmjTh4k0Dh1VNL046v6BXqKziqMDzxo93oh3kOfM= -github.com/cosmos/iavl v1.2.0/go.mod h1:HidWWLVAtODJqFD6Hbne2Y0q3SdxByJepHUOeoH4LiI= -github.com/cosmos/ibc-go/v8 v8.3.2 h1:8X1oHHKt2Bh9hcExWS89rntLaCKZp2EjFTUSxKlPhGI= -github.com/cosmos/ibc-go/v8 v8.3.2/go.mod h1:WVVIsG39jGrF9Cjggjci6LzySyWGloz194sjTxiGNIE= -github.com/cosmos/relayer/v2 v2.5.2 h1:AF0MOo1GvJo94QNB996fBHdKlH+vrIY3JcFNrIvZNP0= -github.com/cosmos/relayer/v2 v2.5.2/go.mod h1:h4Ng2QsVpxExIq5S+WvLr8slDb9MSBh82gQS4DeMwDo= +github.com/cosmos/ibc-go/modules/capability v1.0.0-rc1/go.mod h1:A+CxAQdn2j6ihDTbClpEEBdHthWgAUAcHbRAQPY8sl4= +github.com/cosmos/ibc-go/v7 v7.3.0 h1:QtGeVMi/3JeLWuvEuC60sBHpAF40Oenx/y+bP8+wRRw= +github.com/cosmos/ibc-go/v7 v7.3.0/go.mod h1:mUmaHFXpXrEdcxfdXyau+utZf14pGKVUiXwYftRZZfQ= +github.com/cosmos/ledger-cosmos-go v0.12.1/go.mod h1:dhO6kj+Y+AHIOgAe4L9HL/6NDdyyth4q238I9yFpD2g= +github.com/cosmos/relayer/v2 v2.4.2 h1:+hzUq+FuMvGVVffFz/eGjiyCiv7SSYiBA9CCUMcBgvY= +github.com/cosmos/relayer/v2 v2.4.2/go.mod h1:nSa4Dn2KQW/L2GGYw0kjoOlkTgP7BlECsfUlPwmxu78= +github.com/cosmos/rosetta-sdk-go v0.10.0 h1:E5RhTruuoA7KTIXUcMicL76cffyeoyvNybzUGSKFTcM= +github.com/cosmos/rosetta-sdk-go v0.10.0/go.mod h1:SImAZkb96YbwvoRkzSMQB6noNJXFgWl/ENIznEoYQI4= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c h1:uQYC5Z1mdLRPrZhHjHxufI8+2UG/i25QG92j0Er9p6I= -github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs= github.com/creachadair/atomicfile v0.3.1/go.mod h1:mwfrkRxFKwpNAflYZzytbSwxvbK6fdGRRlp0KEQc0qU= github.com/creachadair/command v0.0.0-20220916173946-56a74cdd66b6/go.mod h1:jN7ZJM5YSVtD3SHmkAdN/cOC1dXiqg2Y9K5Sr5a8Nxw= github.com/creachadair/jrpc2 v1.1.0/go.mod h1:5jN7MKwsm8qvgfTsTzLX3JIfidsAkZ1c8DZSQmp+g38= github.com/creachadair/mds v0.0.1/go.mod h1:caBACU+n1Q/rZ252FTzfnG0/H+ZUi+UnIQtEOraMv/g= github.com/creachadair/tomledit v0.0.24/go.mod h1:9qHbShRWQzSCcn617cMzg4eab1vbLCOjOshAWSzWr8U= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/cristalhq/acmd v0.8.1/go.mod h1:LG5oa43pE/BbxtfMoImHCQN++0Su7dzipdgBjMCBVDQ= github.com/cristalhq/acmd v0.11.1/go.mod h1:LG5oa43pE/BbxtfMoImHCQN++0Su7dzipdgBjMCBVDQ= github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= +github.com/daixiang0/gci v0.8.1/go.mod h1:EpVfrztufwVgQRXjnX4zuNinEpLj5OmMjtu/+MB0V0c= github.com/daixiang0/gci v0.10.1/go.mod h1:xtHP9N7AHdNvtRNfcx9gwTDfw7FRJx4bZUsiEfiNNAI= -github.com/danieljoos/wincred v1.2.1/go.mod h1:uGaFL9fDn3OLTvzCGulzE+SzjEe5NGlh5FdCcyfPwps= github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= -github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= -github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/base58 v1.0.4 h1:QJC6B0E0rXOPA8U/kw2rP+qiRJsUaE2Er+pYb3siUeA= github.com/decred/base58 v1.0.4/go.mod h1:jJswKPEdvpFpvf7dsDvFZyLT22xZ9lWqEByX38oGd9E= -github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v2 v2.0.1 h1:18HurQ6DfHeNvwIjvOmrgr44bPdtVaQAe/WWwHg9goM= github.com/decred/dcrd/dcrec/secp256k1/v2 v2.0.1/go.mod h1:XmyzkaXBy7ZvHdrTAlXAjpog8qKSAWa3ze7yqzWmgmc= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/denis-tingaikin/go-header v0.4.3/go.mod h1:0wOCWuN71D5qIgE2nz9KrKmuYBAC2Mra5RassOIQ2/c= github.com/denisenkom/go-mssqldb v0.12.0/go.mod h1:iiK0YP1ZeepvmBQk/QpLEhhTNJgfzrpArPY/aFvc9yU= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= -github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/djherbis/atime v1.1.0/go.mod h1:28OF6Y8s3NQWwacXc5eZTsEsiMzp7LF8MbXE+XJPdBE= github.com/djherbis/fscache v0.10.1/go.mod h1:yyPYtkNnnPXsW+81lAcQS6yab3G2CRfnPLotBvtbf0c= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/cli v23.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v24.0.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v20.10.19+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v23.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0= +github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0/go.mod h1:56wL82FO0bfMU5RvfXoIwSOP2ggqqxT+tAfNEIyxuHw= github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= @@ -645,26 +447,18 @@ github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/El github.com/emicklei/dot v1.4.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= github.com/emicklei/dot v1.6.0/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0= +github.com/envoyproxy/go-control-plane v0.13.0/go.mod h1:GRaKG3dwvFoTg4nj7aXdZnvMg4d7nvT/wl9WgVXn3Q8= github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= +github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcHcfgNWTk0= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= -github.com/ethereum/c-kzg-4844 v1.0.2/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/ethereum/go-ethereum v1.14.7 h1:EHpv3dE8evQmpVEQ/Ne2ahB06n2mQptdwqaMNhAT29g= -github.com/ethereum/go-ethereum v1.14.7/go.mod h1:Mq0biU2jbdmKSZoqOj29017ygFrMnB5/Rifwp980W4o= -github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 h1:KrE8I4reeVvf7C1tm8elRjj4BdscTYzz/WAbYyf/JI4= -github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0/go.mod h1:D9AJLVXSyZQXJQVk8oh1EwjISE+sJTn2duYIZC0dy3w= github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= -github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= -github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= @@ -675,105 +469,104 @@ github.com/firefart/nonamedreturns v1.0.4/go.mod h1:TDhe/tjI1BXo48CmYbUduTV7BdIg github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8= -github.com/fluent/fluent-logger-golang v1.9.0 h1:zUdY44CHX2oIUc7VTNZc+4m+ORuO/mldQDA7czhWXEg= -github.com/fluent/fluent-logger-golang v1.9.0/go.mod h1:2/HCT/jTy78yGyeNGQLGQsjF3zzzAuy6Xlk6FCMV5eU= github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/franela/goblin v0.0.0-20210519012713-85d372ac71e2/go.mod h1:VzmDKDJVZI3aJmnRI9VjAn9nJ8qPPsN1fqzr9dqInIo= github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fsouza/fake-gcs-server v1.49.0/go.mod h1:FJYZxdHQk2nGxrczFjLbDv8h6SnYXxSxcnM14eeespA= github.com/fsouza/slognil v0.4.0/go.mod h1:wsw8m+QX5kWJAQpq5NnOF2G+TzbF35Npb2xqHxgYdHM= github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= -github.com/gagliardetto/binary v0.8.0 h1:U9ahc45v9HW0d15LoN++vIXSJyqR/pWw8DDlhd7zvxg= -github.com/gagliardetto/binary v0.8.0/go.mod h1:2tfj51g5o9dnvsc+fL3Jxr22MuWzYXwx9wEoN0XQ7/c= -github.com/gagliardetto/solana-go v1.11.0 h1:g6mR7uRNVT0Y0LVR0bvJNfKV6TyO6oUzBYu03ZmkEmY= -github.com/gagliardetto/solana-go v1.11.0/go.mod h1:afBEcIRrDLJst3lvAahTr63m6W2Ns6dajZxe2irF7Jg= -github.com/gagliardetto/treeout v0.1.4 h1:ozeYerrLCmCubo1TcIjFiOWTTGteOOHND1twdFpgwaw= -github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89VZhmMOyCyqok= github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= -github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= +github.com/getsentry/sentry-go v0.23.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/getsentry/sentry-go v0.25.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= +github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-critic/go-critic v0.6.5/go.mod h1:ezfP/Lh7MA6dBNn4c6ab5ALv3sKnZVLx37tr00uuaOY= github.com/go-critic/go-critic v0.7.0/go.mod h1:moYzd7GdVXE2C2hYTwd7h0CPcqlUeclsyBRwMa38v64= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/liberation v0.3.2/go.mod h1:N0QsDLVUQPy3UYg9XAc3Uh3UDMp2Z7M1o4+X98dXkmI= github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.4.0/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg= github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-git-fixtures/v4 v4.3.1/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= +github.com/go-git/go-git/v5 v5.5.2/go.mod h1:BE5hUJ5yaV2YMxhmaP4l6RBQ08kMxKSPD4BlxtH7OjI= github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= +github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-latex/latex v0.0.0-20231108140139-5c1ce85aa4ea/go.mod h1:Y7Vld91/HRbTBm7JwoI7HejdDB0u+e9AUBO9MB7yuZk= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= -github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-pdf/fpdf v0.9.0/go.mod h1:oO8N111TkmKb9D7VvWGLvLJlaZUQVPM+6V42pp3iV4Y= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= -github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= -github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= -github.com/go-playground/validator/v10 v10.12.0/go.mod h1:hCAPuzYvKdP33pxWa+2+6AIKXEKqjIUyqsNCtbsSJrA= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU= +github.com/go-toolsmith/astcopy v1.0.2/go.mod h1:4TcEdbElGc9twQEYpVo/aieIXfHhiuLh4aLAck6dO7Y= github.com/go-toolsmith/astcopy v1.1.0/go.mod h1:hXM6gan18VA1T/daUEHCFcYiW8Ai1tIwIzHY6srfEAw= +github.com/go-toolsmith/astequal v1.0.2/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4= github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4= github.com/go-toolsmith/astequal v1.1.0/go.mod h1:sedf7VIdCL22LD8qIvv7Nn9MuWJruQA/ysswh64lffQ= github.com/go-toolsmith/astfmt v1.1.0/go.mod h1:OrcLlRwu0CuiIBp/8b5PYF9ktGVZUjlNMV634mhwuQ4= github.com/go-toolsmith/astp v1.1.0/go.mod h1:0T1xFGz9hicKs8Z5MfAqSUitoUYS30pDMsRVIDHs8CA= +github.com/go-toolsmith/pkgload v1.0.2-0.20220101231613-e814995d17c5/go.mod h1:3NAwwmD4uY/yggRxoEjk/S00MIV3A+H7rrE3i87eYxM= github.com/go-toolsmith/pkgload v1.2.2/go.mod h1:R2hxLNRKuAsiXCo2i5J6ZQPhnPMOVtU+f0arbFPWCus= github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ= +github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= +github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= github.com/gobuffalo/logger v1.0.6/go.mod h1:J31TBEHR1QLV2683OXTAItYIg8pv2JMHnF/quuAbMjs= github.com/gobuffalo/packd v1.0.2/go.mod h1:sUc61tDqGMXON80zpKGp92lDb86Km28jfvX7IAyxFT8= github.com/gobuffalo/packr/v2 v2.8.3/go.mod h1:0SahksCVcx4IMnigTjiFuyldmTrdTctXsOdiU5KwbKc= -github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= -github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/goccmack/gocc v0.0.0-20230228185258-2292f9e40198/go.mod h1:DTh/Y2+NbnOVVoypCCQrovMPDKUGp4yZpSbWg5D0XIM= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godror/godror v0.24.2/go.mod h1:wZv/9vPiUib6tkoDl+AZ/QLf5YZgMravZ7jxH2eQWAE= +github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188/go.mod h1:vXjM/+wXQnTPR4KqTKDgJukSZ6amVRtWMPEjE6sQoK8= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe/go.mod h1:gjqyPShc/m8pEMpk0a3SeagVb0kaqvhscv+i9jI5ZhQ= github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2/go.mod h1:9wOXstvyDRshQ9LggQuzBCGysxs3b6Uo/1MvYCR2NMs= +github.com/golangci/golangci-lint v1.50.1/go.mod h1:AQjHBopYS//oB8xs0y0M/dtxdKHkdhl0RvmjUct0/4w= github.com/golangci/golangci-lint v1.52.0/go.mod h1:wlTh+d/oVlgZC2yCe6nlxrxNAnuhEQC0Zdygoh72Uak= +github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= github.com/golangci/misspell v0.4.0/go.mod h1:W6O/bwV6lGDxUCChm2ykw9NQdd5bYd1Xkjo88UcWyJc= github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6/go.mod h1:0AKcRCkMoKvUvlf89F6O7H2LYdhr1zBh736mBItOdRs= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= @@ -782,68 +575,41 @@ github.com/gonum/floats v0.0.0-20181209220543-c233463c7e82/go.mod h1:PxC8OnwL11+ github.com/gonum/internal v0.0.0-20181124074243-f884aa714029/go.mod h1:Pu4dmpkhSyOzRwuXkOgAvijx4o+4YMUJJo9OvPYMkks= github.com/gonum/lapack v0.0.0-20181123203213-e4cdc5a0bff9/go.mod h1:XA3DeT6rxh2EAE789SSiSJNqxPaC0aE9J8NTOI0Jo/A= github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9/go.mod h1:0EXg4mc1CNP0HCqCz+K4ts155PXIlUywf0wqN+GfPZw= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-containerregistry v0.13.0/go.mod h1:J9FQ+eSS4a1aC2GNZxvNpbWhgp0487v+cgiilB4FqDo= github.com/google/go-github/v43 v43.0.0/go.mod h1:ZkTvvmCXBvsfPpTHXnH/d2hP9Y0cTbvN9kr5xqyXOIc= github.com/google/go-pkcs11 v0.2.1-0.20230907215043-c6f79328ddf9/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= github.com/google/go-querystring v0.0.0-20160401233042-9235644dd9e5/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gopacket v1.1.20-0.20210429153827-3eaba0894325/go.mod h1:riddUzxTSBpJXk3qBHtYr4qOhFhT6k/1c0E3qkQjQpA= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 h1:CqYfpuYIjnlNxM3msdyPRKabhXZWbKjf3Q8BWROFBso= github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4= +github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/safehtml v0.0.2/go.mod h1:L4KWwDsUJdECRAEpZoBn3O64bQaywRscowZjJAzjHnU= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/gax-go v0.0.0-20161107002406-da06d194a00e/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= -github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= -github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= -github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= -github.com/googleapis/gax-go/v2 v2.12.4 h1:9gWcmF85Wvq4ryPFvGFaOgPIs1AQX0d0bcbGw4Z96qg= -github.com/googleapis/gax-go/v2 v2.12.4/go.mod h1:KYEYLorsnIGDi/rPC8b5TdlB9kbKoFubselGIoBMCwI= -github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gookit/color v1.5.2/go.mod h1:w8h4bGiHeeBpvQVePTutdbERIUf3oJE5lZ8HM0UgXyg= +github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= -github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= +github.com/gostaticanalysis/analysisutil v0.1.0/go.mod h1:dMhHRU9KTiDcuLGdy87/2gTR8WruwYZrKdRq9m1O6uw= github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= +github.com/gostaticanalysis/comment v1.3.0/go.mod h1:xMicKDx7XRXYdVwY9f9wQpDJVnqWxw9wCauCMKp+IBI= github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado= github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM= github.com/gostaticanalysis/forcetypeassert v0.1.0/go.mod h1:qZEedyP/sY1lTGV1uJ3VhWZ2mqag3IkWsDHVbplHXak= @@ -851,21 +617,22 @@ github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU= github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= -github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is= -github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= -github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc= -github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= github.com/guptarohit/asciigraph v0.5.5/go.mod h1:dYl5wwK4gNsnFf9Zp+l06rFiDZ5YtXM6x7SRWZ3KGag= github.com/guregu/null v4.0.0+incompatible/go.mod h1:ePGpQaN9cw0tj45IR5E5ehMvsFlLlQZAkkOXZurJ3NM= +github.com/hashicorp/consul/api v1.14.0/go.mod h1:bcaw5CSZ7NE9qfOfKCI1xb7ZKjzu/MyvQkCLTfqLqxQ= github.com/hashicorp/consul/api v1.28.2/go.mod h1:KyzqzgMEya+IZPcD65YFoOVAgPpbfERu4I/tzG6/ueE= +github.com/hashicorp/consul/sdk v0.10.0/go.mod h1:yPkX5Q6CsxTFMjQQDJwzeNmUUF5NUGGbrDsv9wTb8cw= github.com/hashicorp/consul/sdk v0.16.0/go.mod h1:7pxqqhqoaPqnBnzXD1StKed62LqJeClzVsUEy85Zr0A= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-getter v1.7.1/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= github.com/hashicorp/go-getter v1.7.4/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= -github.com/hashicorp/go-getter v1.7.5 h1:dT58k9hQ/vbxNMwoI5+xFYAJuv6152UNvdHokfI5wE4= -github.com/hashicorp/go-getter v1.7.5/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.2.2/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-metrics v0.5.1/go.mod h1:KEjodfebIOuBYSAe/bHTm+HChmKSxAOXPBieMLYozDE= github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= @@ -874,16 +641,20 @@ github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR3 github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= -github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/memberlist v0.3.1/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/memberlist v0.4.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= +github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hashicorp/serf v0.10.0/go.mod h1:bXN03oZc5xlH46k/K1qTrpXb9ERKyY1/i/N5mxvgrZw= github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= -github.com/holiman/uint256 v1.3.0 h1:4wdcm/tnd0xXdu7iS3ruNvxkWwrb4aeBQv19ayYn8F4= -github.com/holiman/uint256 v1.3.0/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= +github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo= github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= @@ -892,12 +663,12 @@ github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47 github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/ianlancetaylor/demangle v0.0.0-20220517205856-0058ec4f073c/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= -github.com/icon-project/goloop v1.3.11 h1:Lry7rCM9QeZudiAqi7n7CqmoOsg7qNDwrw6O12j7vuo= -github.com/icon-project/goloop v1.3.11/go.mod h1:9PoWRb5kowidc9jYy0RLuLpay1zT5FXgEKijx7rDQjE= github.com/icza/dyno v0.0.0-20220812133438-f0b6f8a18845 h1:H+uM0Bv88eur3ZSsd2NGKg3YIiuXxwxtlN7HjE66UTU= github.com/icza/dyno v0.0.0-20220812133438-f0b6f8a18845/go.mod h1:c1tRKs5Tx7E2+uHGSyyncziFjvGpgv4H2HrqXeUQ/Uk= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/informalsystems/tm-load-test v1.3.0/go.mod h1:OQ5AQ9TbT5hKWBNIwsMjn6Bf4O0U4b1kRc+0qZlQJKw= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= @@ -911,19 +682,24 @@ github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrO github.com/iris-contrib/schema v0.0.6/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jdxcode/netrc v0.0.0-20210204082910-926c7f70242a/go.mod h1:Zi/ZFkEqFHTm7qkjyNJjaWH4LQA9LQhGJyF0lTYGpxw= github.com/jdxcode/netrc v0.0.0-20221124155335-4616370d1a84/go.mod h1:Zi/ZFkEqFHTm7qkjyNJjaWH4LQA9LQhGJyF0lTYGpxw= github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267/go.mod h1:h1nSAbGFqGVzn6Jyl1R/iCcBUHN4g+gW1u9CoBTrb9E= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jgautheron/goconst v1.5.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= +github.com/jhump/gopoet v0.0.0-20190322174617-17282ff210b3/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI= github.com/jhump/gopoet v0.1.0/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI= github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7UvLHRQ= +github.com/jhump/protocompile v0.0.0-20220216033700-d705409f108f/go.mod h1:qr2b5kx4HbFS7/g4uYO5qv9ei8303JMsC7ESbYiqr2Q= +github.com/jhump/protoreflect v1.11.0/go.mod h1:U7aMIjN0NWq9swDP7xDdoMfRHb35uiuTd3Z9nFXJf5E= +github.com/jhump/protoreflect v1.12.1-0.20220721211354-060cc04fc18b/go.mod h1:JytZfP5d0r8pVNLZvai7U/MCuTWITgrI4tTg7puQFKI= +github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= +github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jsternberg/zap-logfmt v1.3.0 h1:z1n1AOHVVydOOVuyphbOKyR4NICDQFiJMn1IK5hVQ5Y= -github.com/jsternberg/zap-logfmt v1.3.0/go.mod h1:N3DENp9WNmCZxvkBD/eReWwz1149BK6jEN9cQ4fNwZE= github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= @@ -948,25 +724,25 @@ github.com/kataras/tunnel v0.0.4/go.mod h1:9FkU4LaeifdMWqZu7o20ojmW4B7hdhv2CMLwf github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= +github.com/kisielk/errcheck v1.6.2/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw= github.com/kisielk/errcheck v1.6.3/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw= +github.com/kkHAIKE/contextcheck v1.1.3/go.mod h1:PG/cwd6c0705/LM0KTr1acO2gORUxkSVWyLJOFW5qoo= github.com/kkHAIKE/contextcheck v1.1.4/go.mod h1:1+i/gWqokIa+dm31mqGLZhZJ7Uh44DJGZVmr6QRBNJg= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.14.4/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= -github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= -github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= @@ -979,41 +755,42 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I= github.com/kunwardeep/paralleltest v1.0.6/go.mod h1:Y0Y0XISdZM5IKm3TREQMZ6iteqn1YuwCsJO/0kL9Zes= +github.com/kyoh86/exportloopref v0.1.8/go.mod h1:1tUcJeiioIs7VWe5gcOObrux3lb66+sBqGZrRkMwPgg= github.com/kyoh86/exportloopref v0.1.11/go.mod h1:qkV4UF1zGl6EkF1ox8L5t9SwyeBAZ3qLMd6up458uqA= github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= -github.com/labstack/echo/v4 v4.11.3 h1:Upyu3olaqSHkCjs1EJJwQ3WId8b8b1hxbogyommKktM= -github.com/labstack/echo/v4 v4.11.3/go.mod h1:UcGuQ8V6ZNRmSweBIJkPvGfwCMIlFmiqrPqiEBfPYws= -github.com/labstack/gommon v0.4.1 h1:gqEff0p/hTENGMABzezPoPSRtIh1Cvw0ueMOe0/dfOk= -github.com/labstack/gommon v0.4.1/go.mod h1:TyTrpPqxR5KMk8LKVtLmfMjeQ5FEkBYdxLYPw/WfrOM= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/ldez/gomoddirectives v0.2.3/go.mod h1:cpgBogWITnCfRq2qGoDkKMEVSaarhdBr6g8G04uz6d0= +github.com/ldez/tagliatelle v0.3.1/go.mod h1:8s6WJQwEYHbKZDsp/LjArytKOG8qaMrKQQ3mFukHs88= github.com/ldez/tagliatelle v0.4.0/go.mod h1:mNtTfrHy2haaBAw+VT7IBV6VXBThS7TCreYWbBcJ87I= github.com/leodido/go-urn v1.2.2/go.mod h1:kUaIbLZWttglzwNuG0pgsh5vuV6u2YcGBYz1hIPjtOQ= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/leonklingele/grouper v1.1.0/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY= github.com/leonklingele/grouper v1.1.1/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-libp2p v0.31.0 h1:LFShhP8F6xthWiBBq3euxbKjZsoRajVEyBS9snfHxYg= github.com/libp2p/go-libp2p v0.31.0/go.mod h1:W/FEK1c/t04PbRH3fA9i5oucu5YcgrG0JVoBWT1B7Eg= github.com/linxGnu/grocksdb v1.7.15/go.mod h1:pY55D0o+r8yUYLq70QmhdudxYvoDb9F+9puf4m3/W+U= +github.com/linxGnu/grocksdb v1.7.16/go.mod h1:JkS7pl5qWpGpuVb3bPqTz8nC12X3YtPZT+Xq7+QfQo4= +github.com/linxGnu/grocksdb v1.8.4/go.mod h1:xZCIb5Muw+nhbDK4Y5UJuOrin5MceOuiXkVUR7vp4WY= github.com/linxGnu/grocksdb v1.8.6/go.mod h1:xZCIb5Muw+nhbDK4Y5UJuOrin5MceOuiXkVUR7vp4WY= github.com/linxGnu/grocksdb v1.8.12/go.mod h1:xZCIb5Muw+nhbDK4Y5UJuOrin5MceOuiXkVUR7vp4WY= -github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= -github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE= +github.com/maratori/testpackage v1.1.0/go.mod h1:PeAhzU8qkCwdGEMTEupsHJNlQu2gZopMC6RjbhmHeDc= github.com/maratori/testpackage v1.1.1/go.mod h1:s4gRK/ym6AMrqpOa/kEbQTV4Q4jb7WeLZzVhVVVOQMc= github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc= github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +github.com/matoous/godox v0.0.0-20210227103229-6504466cf951/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= +github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs= github.com/mattbaird/elastigo v0.0.0-20170123220020-2fe47fd29e4b/go.mod h1:5MWrJXKRQyhQdUCF+vu6U5c4nQpg70vW3eHaU0/AYbU= @@ -1022,6 +799,7 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-oci8 v0.1.1/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= @@ -1034,6 +812,7 @@ github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go. github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= github.com/mediocregopher/radix/v3 v3.8.1/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg= +github.com/mgechev/revive v1.2.4/go.mod h1:iAWlQishqCuj4yhV24FTnKSXGpbAA+0SckXB8GQMX/Q= github.com/mgechev/revive v1.3.1/go.mod h1:YlD6TTWl2B8A103R9KWJSPVI9DrEf+oqr15q21Ld+5I= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/microcosm-cc/bluemonday v1.0.23/go.mod h1:mN70sk7UkkF8TUr2IGBpNN0jAgStuPzlK76QuruE/z4= @@ -1050,19 +829,21 @@ github.com/misko9/go-substrate-rpc-client/v4 v4.0.0-20230913220906-b988ea7da0c2 github.com/misko9/go-substrate-rpc-client/v4 v4.0.0-20230913220906-b988ea7da0c2/go.mod h1:Q5BxOd9FxJqYp4vCiLGVdetecPcWTmUQIu0bRigYosU= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/cli v1.1.5/go.mod h1:v8+iFts2sPIKUV1ltktPXMCC8fumSKFItNcD2cLtRR4= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mmcloughlin/avo v0.5.0/go.mod h1:ChHFdoV7ql95Wi7vuq2YT1bwCJqiWdZrQ1im3VujLYM= +github.com/moby/buildkit v0.10.4/go.mod h1:Yajz9vt1Zw5q9Pp4pdb3TCSUXJBIroIQGQ3TTs/sLug= github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= +github.com/moricho/tparallel v0.2.1/go.mod h1:fXEIZxG2vdfl0ZF8b42f5a78EhjjD5mX8qUplsoSU4k= github.com/moricho/tparallel v0.3.0/go.mod h1:leENX2cUv7Sv2qDgdi0D0fCftN8fRC67Bcn8pqzeYNI= -github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 h1:mPMvm6X6tf4w8y7j9YIt6V9jfWhL6QlbEc7CCmeQlWk= -github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1/go.mod h1:ye2e/VUEtE2BHE+G/QcKkcLQVAEJoYRFj5VUOQatCRE= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mozilla/tls-observatory v0.0.0-20210609171429-7bc42856d2e5/go.mod h1:FUqVoUPHSEdDR0MnFM3Dh8AU0pZHLXUD127SAJGER/s= -github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= @@ -1079,29 +860,35 @@ github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsC github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= +github.com/nats-io/jwt/v2 v2.2.1-0.20220330180145-442af02fd36a/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k= github.com/nats-io/jwt/v2 v2.3.0/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k= github.com/nats-io/jwt/v2 v2.4.1/go.mod h1:24BeQtRwxRV8ruvC4CojXlx/WQ/VjuwlYiH+vu/+ibI= github.com/nats-io/nats-server/v2 v2.5.0/go.mod h1:Kj86UtrXAL6LwYRA6H4RqzkHhK0Vcv2ZnKD5WbQ1t3g= +github.com/nats-io/nats-server/v2 v2.8.4/go.mod h1:8zZa+Al3WsESfmgSs98Fi06dRWLH5Bnq90m5bKD/eT4= github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= +github.com/nats-io/nats.go v1.15.0/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= github.com/nats-io/nats.go v1.34.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= +github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= +github.com/nats-io/nkeys v0.4.4/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64= github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8= -github.com/near/borsh-go v0.3.1 h1:ukNbhJlPKxfua0/nIuMZhggSU8zvtRP/VyC25LLqPUA= github.com/nelsam/hel/v2 v2.3.3/go.mod h1:1ZTGfU2PFTOd5mx22i5O0Lc2GY933lQ2wb/ggy+rL3w= +github.com/nishanths/exhaustive v0.8.3/go.mod h1:qj+zJJUgJ76tR92+25+03oYUhzF4R7/2Wk7fGTfCHmg= github.com/nishanths/exhaustive v0.9.5/go.mod h1:IbwrGdVMizvDcIxPYGVdQn5BqWJaOwpCvg4RGb8r/TA= github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= github.com/nunnatsa/ginkgolinter v0.9.0/go.mod h1:FHaMLURXP7qImeH6bvxWJUpyH+2tuqe5j4rW1gxJRmI= github.com/oasisprotocol/curve25519-voi v0.0.0-20220708102147-0a8a51822cae/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s= github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= +github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= +github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= +github.com/onsi/gomega v1.20.0/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= -github.com/opencontainers/runc v1.1.3/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE= -github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/ory/dockertest/v3 v3.9.1/go.mod h1:42Ir9hmvaAPm0Mgibk6mBPi7SFvTXxEcnztDYOJ//uM= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= @@ -1113,14 +900,14 @@ github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= +github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM= github.com/petermattis/goid v0.0.0-20221215004737-a150e88a970d/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20230317030725-371a4b8eda08/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/petermattis/goid v0.0.0-20230904192822-1876fd5063bc/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= -github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= -github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= @@ -1129,63 +916,69 @@ github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/xxHash v0.1.5 h1:n/jBpwTHiER4xYvK3/CdPVnLDPchj8eTJFFLUb4QHBo= github.com/pierrec/xxHash v0.1.5/go.mod h1:w2waW5Zoa/Wc4Yqe0wgrIYAGKqRMf7czn2HNKXmuL+I= +github.com/pjbgf/sha1cd v0.2.3/go.mod h1:HOK9QrgzdHpbc2Kzip0Q1yi3M2MFGPADtR6HjG65m5M= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= github.com/pkg/xattr v0.4.9/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pointlander/compress v1.1.1-0.20190518213731-ff44bd196cc3/go.mod h1:q5NXNGzqj5uPnVuhGkZfmgHqNUhf15VLi6L9kW0VEc0= github.com/pointlander/jetset v1.0.1-0.20190518214125-eee7eff80bd4/go.mod h1:RdR1j20Aj5pB6+fw6Y9Ur7lMHpegTEjY1vc19hEZL40= github.com/pointlander/peg v1.0.1/go.mod h1:5hsGDQR2oZI4QoWz0/Kdg3VSVEC31iJw/b7WjqCBGRI= +github.com/polyfloyd/go-errorlint v1.0.5/go.mod h1:APVvOesVSAnne5SClsPxPdfvZTVDojXh1/G3qb5wjGI= github.com/polyfloyd/go-errorlint v1.4.5/go.mod h1:sIZEbFoDOCnTYYZoVkjc4hTnM459tuWA9H/EkdXwsKk= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= -github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/common v0.50.0/go.mod h1:wHFBCEVWVmHMUpg7pYcOm2QUR/ocQdYSJVQJKnHc3xQ= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/exporter-toolkit v0.10.0/go.mod h1:+sVFzuvV5JDyw+Ih6p3zFxZNVnKQa3x5qPmDSiPu4ZY= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI= -github.com/prometheus/statsd_exporter v0.26.0 h1:SQl3M6suC6NWQYEzOvIv+EF6dAMYEqIuZy+o4H9F5Ig= -github.com/prometheus/statsd_exporter v0.26.0/go.mod h1:GXFLADOmBTVDrHc7b04nX8ooq3azG61pnECNqT7O5DM= github.com/protolambda/bls12-381-util v0.1.0/go.mod h1:cdkysJTRpeFeuUVx/TXGDQNMTiRAalk1vQw3TYTHcE4= github.com/protolambda/messagediff v1.4.0/go.mod h1:LboJp0EwIbJsePYpzh5Op/9G1/4mIztMRYzzwR0dR2M= github.com/protolambda/zrnt v0.32.2/go.mod h1:A0fezkp9Tt3GBLATSPIbuY4ywYESyAuc/FFmPKg8Lqs= github.com/protolambda/ztyp v0.2.2/go.mod h1:9bYgKGqg3wJqT9ac1gI2hnVb0STQq7p/1lapqrqY1dU= github.com/prysmaticlabs/gohashtree v0.0.1-alpha.0.20220714111606-acbb2962fb48/go.mod h1:4pWaT30XoEx1j8KNJf3TV+E3mQkaufn7mf+jRNb/Fuk= +github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30= +github.com/quasilyte/go-ruleguard v0.3.18/go.mod h1:lOIzcYlgxrQ2sGJ735EHXmf/e9MJ516j16K/Ifcttvs= github.com/quasilyte/go-ruleguard v0.4.0/go.mod h1:Eu76Z/R8IXtViWUIHkE3p8gdH3/PKk1eh3YGfaEof10= +github.com/quasilyte/go-ruleguard/dsl v0.3.0/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= +github.com/quasilyte/go-ruleguard/dsl v0.3.21/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/quasilyte/go-ruleguard/dsl v0.3.22/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= +github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1/go.mod h1:7JTjp89EGyU1d6XfBiXihJNG37wB2VRkd125Q1u7Plc= github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50= +github.com/quasilyte/gogrep v0.0.0-20220828223005-86e4605de09f/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= +github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= +github.com/rabbitmq/amqp091-go v1.2.0/go.mod h1:ogQDLSOACsLPsIq0NpbtiifNZi2YOz0VTJ0kHRghqbM= +github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= +github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= @@ -1193,96 +986,96 @@ github.com/remyoudompheng/go-dbus v0.0.0-20121104212943-b7232d34b1d5/go.mod h1:+ github.com/remyoudompheng/go-liblzma v0.0.0-20190506200333-81bf2d431b96/go.mod h1:90HvCY7+oHHUKkbeMCiHt1WuFR2/hPJ9QrljDG+v6ls= github.com/remyoudompheng/go-misc v0.0.0-20190427085024-2d6ac652a50e/go.mod h1:80FQABjoFzZ2M5uEa6FUaJYEmqU2UOKojlFVak1UAwI= github.com/rivo/tview v0.0.0-20220307222120-9994674d60a8/go.mod h1:WIfMkQNY+oq/mWwtsjOYHIZBuwthioY2srOmljJkTnk= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U= github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= -github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= -github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/rubenv/sql-migrate v1.5.2/go.mod h1:H38GW8Vqf8F0Su5XignRyaRcbXbJunSWxs+kmzlg0Is= github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= github.com/rwtodd/Go.Sed v0.0.0-20210816025313-55464686f9ef/go.mod h1:8AEUvGVi2uQ5b24BIhcr0GCcpd/RNAFWaN2CJFrWIIQ= +github.com/ryancurrah/gomodguard v1.2.4/go.mod h1:+Kem4VjWwvFpUJRJSwa16s1tBJe+vbv02+naTow2f6M= github.com/ryancurrah/gomodguard v1.3.0/go.mod h1:ggBxb3luypPEzqVtq33ee7YSN35V28XeGnid8dnni50= +github.com/ryanrolds/sqlclosecheck v0.3.0/go.mod h1:1gREqxyTGR3lVtpngyFo3hZAgk0KCtEdgEkHwDbigdA= github.com/ryanrolds/sqlclosecheck v0.4.0/go.mod h1:TBRRjzL31JONc9i4XMinicuo+s+E8yKZ5FN8X3G6CKQ= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.19.0/go.mod h1:c6vimRziqqERhtSe0MhIvzE1w54FrCHtrXb5NH/ja78= github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U= -github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0= github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U= +github.com/sanposhiho/wastedassign/v2 v2.0.6/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= +github.com/sashamelentyev/usestdlibvars v1.20.0/go.mod h1:0GaP+ecfZMXShS0A94CJn6aEuPRILv8h/VuWI9n1ygg= github.com/sashamelentyev/usestdlibvars v1.23.0/go.mod h1:YPwr/Y1LATzHI93CqoPUN/2BzGQ/6N/cl/KwgR0B/aU= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= +github.com/securego/gosec/v2 v2.13.1/go.mod h1:EO1sImBMBWFjOTFzMWfTRrZW6M15gm60ljzrmy/wtHo= github.com/securego/gosec/v2 v2.15.0/go.mod h1:VOjTrZOkUtSDt2QLSJmQBMWnvwiQPEjg0l+5juIqGk8= github.com/sergi/go-diff v0.0.0-20161205080420-83532ca1c1ca/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shamaton/msgpack/v2 v2.2.0 h1:IP1m01pHwCrMa6ZccP9B3bqxEMKMSmMVAVKk54g3L/Y= -github.com/shamaton/msgpack/v2 v2.2.0/go.mod h1:6khjYnkx73f7VQU7wjcFS9DFjs+59naVWJv1TB7qdOI= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= -github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= -github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil/v3 v3.23.2/go.mod h1:gv0aQw33GLo3pG8SiWKiQrbDzbRY1K80RyZJ7V4Th1M= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c/go.mod h1:owqhoLW1qZoYLZzLnBw+QkPP9WZnjlSWihhxAJC1+/M= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sivchari/containedctx v1.0.2/go.mod h1:PwZOeqm4/DLoJOqMSIJs3aKqXRX4YO+uXww087KZ7Bw= github.com/sivchari/nosnakecase v1.7.0/go.mod h1:CwDzrzPea40/GB6uynrNLiorAlgFRvRbFSgJx2Gs+QY= +github.com/sivchari/tenv v1.7.0/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg= github.com/sivchari/tenv v1.7.1/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg= +github.com/skeema/knownhosts v1.1.0/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXijpFO6roag= github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4= +github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4lqBjiZI= github.com/sonatard/noctx v0.0.2/go.mod h1:kzFz+CzWSjQ2OzIm46uJZoXuBpa2+0y3T36U18dWqIo= +github.com/sourcegraph/go-diff v0.6.1/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= github.com/spf13/afero v1.4.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As= github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI= github.com/spf13/viper v1.18.1/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= -github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= -github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8LHsN9N74I+PhRquPsxpL0I= -github.com/stellar/go v0.0.0-20240517163948-afd526d41b2d h1:6GjK/PKeInOLDu+2Gy15/2RIxnsFBmfIQB3WrO50CqU= -github.com/stellar/go v0.0.0-20240517163948-afd526d41b2d/go.mod h1:TuXKLL7WViqwrvpWno2I4UYGn2Ny9KZld1jUIN6fnK8= github.com/stellar/throttled v2.2.3-0.20190823235211-89d75816f59d+incompatible/go.mod h1:7CJ23pXirXBJq45DqvO6clzTEGM/l1SfKrgrzLry8b4= github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/strangelove-ventures/cometbft-client v0.1.0/go.mod h1:QzThgjzvsGgUNVNpGPitmxOWMIhp6a0oqf80nCRNt/0= github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= -github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091 h1:RN5mrigyirb8anBEtdjtHFIufXdacyTi6i4KBfeNXeo= -github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091/go.mod h1:VlduQ80JcGJSargkRU4Sg9Xo63wZD/l8A5NC/Uo1/uU= github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/supranational/blst v0.3.12/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c/go.mod h1:SbErYREK7xXdsRiigaQiQkI9McGRzYMvlKYaP3Nimdk= +github.com/tdakkota/asciicheck v0.1.1/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= github.com/tdakkota/asciicheck v0.2.0/go.mod h1:Qb7Y9EgjCLJGup51gDHFzbI08/gbGhL/UVhYIPWG2rg= github.com/tdewolff/minify/v2 v2.12.4/go.mod h1:h+SRvSIX3kwgwTFOpSckvSxgax3uy8kZTSF1Ojrr3bk= github.com/tdewolff/parse/v2 v2.6.4/go.mod h1:woz0cgbLwFdtbjJu8PIKxhW05KplTFQkOdX78o+Jgrs= @@ -1290,25 +1083,18 @@ github.com/tdewolff/test v1.0.7/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYq github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= -github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU= github.com/tetafro/godot v1.4.11/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8= +github.com/tidwall/btree v1.6.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= +github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= github.com/timakin/bodyclose v0.0.0-20221125081123-e39cf3fc478e/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ= +github.com/timonwong/loggercheck v0.9.3/go.mod h1:wUqnk9yAOIKtGA39l1KLE9Iz0QiTocu/YZoOf+OzFdw= github.com/timonwong/loggercheck v0.9.4/go.mod h1:caz4zlPcgvpEkXgVnAJGowHAMW2NwHaNlpS8xDbVhTg= -github.com/tinylib/msgp v1.1.9 h1:SHf3yoO2sGA0veCJeCBYLHuttAVFHGm2RHgNodW7wQU= -github.com/tinylib/msgp v1.1.9/go.mod h1:BCXGB54lDD8qUEPmiG0cQQUANC4IUQyB2ItS2UDlO/k= -github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4= -github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0= -github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY= +github.com/tomarrell/wrapcheck/v2 v2.7.0/go.mod h1:ao7l5p0aOlUNJKI0qVwB4Yjlqutd0IvAB9Rdwyilxvg= github.com/tomarrell/wrapcheck/v2 v2.8.1/go.mod h1:/n2Q3NZ4XFT50ho6Hbxg+RV1uyo2Uow/Vdm9NQcl5SE= github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= -github.com/tyler-smith/go-bip32 v1.0.0 h1:sDR9juArbUgX+bO/iblgZnMPeWY1KZMUC2AFUJdv5KE= -github.com/tyler-smith/go-bip32 v1.0.0/go.mod h1:onot+eHknzV4BVPwrzqY5OoVpyCvnwD7lMawL5aQupE= github.com/tyler-smith/go-bip39 v0.0.0-20180618194314-52158e4697b8/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= -github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= -github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/ultraware/whitespace v0.0.5/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= @@ -1318,26 +1104,17 @@ github.com/valyala/fasthttp v1.34.0/go.mod h1:epZA5N+7pY6ZaEKRmstzOuYJx9HI8DI1oa github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI= +github.com/vektra/mockery/v2 v2.14.0/go.mod h1:bnD1T8tExSgPD1ripLkDbr60JA9VtQeu12P3wgLZd7M= github.com/vektra/mockery/v2 v2.23.1/go.mod h1:Zh3Kv1ckKs6FokhlVLcCu6UTyzfS3M8mpROz1lBNp+w= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/vmihailenco/msgpack/v4 v4.3.13 h1:A2wsiTbvp63ilDaWmsk2wjx6xZdxQOvpiNlKBGKKXKI= -github.com/vmihailenco/msgpack/v4 v4.3.13/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= -github.com/vmihailenco/tagparser v0.1.2 h1:gnjoVuB/kljJ5wICEEOpx98oXMWPLj22G67Vbd1qPqc= -github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= -github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= -github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= -github.com/xeipuuv/gojsonpointer v0.0.0-20151027082146-e0fe6f683076/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20150808065054-e02fc20de94c/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v0.0.0-20161231055540-f06f290571ce/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xhit/go-str2duration v1.2.0/go.mod h1:3cPSlfZlUHVlneIVfePFWcJZsuwf+P1v2SRTV4cUmp4= github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= @@ -1345,93 +1122,96 @@ github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsT github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= github.com/yeya24/promlinter v0.2.0/go.mod h1:u54lkmBOZrpEbQQ6gox2zWKKLKu2SGe+2KOiextY+IA= github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +github.com/zondax/hid v0.9.1/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= +github.com/zondax/ledger-go v0.14.0/go.mod h1:fZ3Dqg6qcdXWSOJFKMG8GCTnD7slO/RL2feOQv8K320= gitlab.com/bosi/decorder v0.2.3/go.mod h1:9K1RB5+VPNQYtXtTDAzd2OEftsZb1oV0IrJrzChSdGE= go.einride.tech/aip v0.67.1/go.mod h1:ZGX4/zKw8dcgzdLsrvpOOGxfxI2QSk12SlP7d6c0/XI= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/api/v3 v3.5.12/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/pkg/v3 v3.5.12/go.mod h1:seTzl2d9APP8R5Y2hFL3NVlD6qC/dOT+3kvrqPyTas4= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.etcd.io/etcd/client/v2 v2.305.12/go.mod h1:aQ/yhsxMu+Oht1FOupSr60oBvcS9cKXHrzBpDsPTf9E= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= go.etcd.io/etcd/client/v3 v3.5.12/go.mod h1:tSbBCakoWmmddL+BKVAJHa9km+O/E+bumDe9mSbPiqw= go.etcd.io/gofail v0.1.0/go.mod h1:VZBCXYGZhHAinaBiiqYvuDynvahNsAyLFwB3kEHKz1M= -go.mongodb.org/mongo-driver v1.11.0 h1:FZKhBSTydeuffHj9CBjXlR8vQLee1cQyTWYPA6/tqiE= -go.mongodb.org/mongo-driver v1.11.0/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.36.3/go.mod h1:Dts42MGkzZne2yCru741+bFiTMWkIj/LLRizad7b9tw= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.51.0 h1:A3SayB3rNyt+1S6qpI9mHPkeHTZbD7XILEqWnYZb2l0= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.51.0/go.mod h1:27iA5uvhuRNmalO+iEUdVn5ZMj2qy10Mm+XRIpRmyuU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 h1:Xs2Ncz0gNihqu9iosIZ5SkBbWo5T8JhhLJFMQL1qmLI= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0/go.mod h1:vy+2G/6NvVMpwGX/NyLqcC41fxepnuKHk16E6IZUcJc= +go.opentelemetry.io/otel v1.11.0/go.mod h1:H2KtuEphyMvlhZ+F7tg9GRhAOe60moNx61Ex+WmiKkk= go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= +go.opentelemetry.io/otel/trace v1.11.0/go.mod h1:nyYjis9jy0gytE9LXGU+/m1sHTKbRY0fX0hulNNDP1U= go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/automaxprocs v1.5.2/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA= -go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg= -go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= -golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= -golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230307190834-24139beb5833/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -1444,232 +1224,141 @@ golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeap golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.0.0-20170207211851-4464e7848382/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/perf v0.0.0-20230113213139-801c7ef9e5c5/go.mod h1:UBKtEnL8aqnd+0JHqZ+2qoMDwtuy6cYhhKNoHLBiTQc= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220325203850-36772127a21f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220702020025-31831981b65f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220823224334-20c2bfdbfe24/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= +golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= -golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190307163923-6a08e3108db3/go.mod h1:25r3+/G6/xytQM8iWZKq3Hn0kr0rgFKPUNVEL/dr3z4= golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190916130336-e45ffcd953cc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200414032229-332987a829c3/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200622203043-20e05c1c8ffa/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200624225443-88f3c62a19ff/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200625211823-6506e20df31f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200812195022-5ae4c3c160a0/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200831203904-5a2aa26beb65/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201001104356-43ebab892c4c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201230224404-63754364767c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.9-0.20211228192929-ee1ca4ffc4da/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= @@ -1677,173 +1366,44 @@ golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= gonum.org/v1/gonum v0.12.0/go.mod h1:73TDxJfAAHeA8Mk9mf8NlIppyhQNo5GLTcYeqgo2lvY= +gonum.org/v1/gonum v0.15.1/go.mod h1:eZTZuRFrzu5pcyjN5wJhcIhnUdNijYxX1T2IcrOGY0o= gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= gonum.org/v1/plot v0.10.0/go.mod h1:JWIHJ7U20drSQb/aDpTetJzfC1KlAPldJLpkSy88dvQ= gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= +gonum.org/v1/plot v0.14.0/go.mod h1:MLdR9424SJed+5VqC6MsouEpig9pZX2VZ57H9ko2bXU= google.golang.org/api v0.0.0-20170206182103-3d017632ea10/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= -google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= -google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= -google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= -google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= -google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= -google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= -google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= google.golang.org/api v0.152.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY= google.golang.org/api v0.162.0/go.mod h1:6SulDkfoBIg4NFmCuZ39XeeAgSHCPecfSUuDyYlAHs0= google.golang.org/api v0.171.0/go.mod h1:Hnq5AHm4OTMt2BUVjael2CWZFD6vksJdWCWiUAmjC9o= google.golang.org/api v0.176.1/go.mod h1:j2MaSDYcvYV1lkZ1+SMW4IeF90SrEyFA+tluDYWRrFg= google.golang.org/api v0.178.0/go.mod h1:84/k2v8DFpDRebpGcooklv/lais3MEfqpaBLA12gl2U= -google.golang.org/api v0.180.0 h1:M2D87Yo0rGBPWpo1orwfCLehUUL6E7/TYe5gvMQWDh4= -google.golang.org/api v0.180.0/go.mod h1:51AiyoEg1MJPSZ9zvklA8VnRILPXxn1iVen9v25XHAE= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= -google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= -google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= -google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= -google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y= +google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= +google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97/go.mod h1:t1VqOqqvce95G3hIDCT5FeO3YUc6Q4Oe24L/+rNMxRk= google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI= google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= -google.golang.org/genproto v0.0.0-20240513163218-0867130af1f8 h1:XpH03M6PDRKTo1oGfZBXu2SzwcbfxUokgobVinuUZoU= -google.golang.org/genproto v0.0.0-20240513163218-0867130af1f8/go.mod h1:OLh2Ylz+WlYAJaSBRpJIJLP8iQP+8da+fpxbwNEAV/o= +google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= +google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= google.golang.org/genproto/googleapis/api v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:RdyHbowztCGQySiCvQPgWQWgWhGnouTdCflKoDBt32U= google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:SUBoKXbI1Efip18FClrQVGjWcyd0QZd8KkvdP34t7ww= google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= @@ -1853,9 +1413,9 @@ google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go. google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be/go.mod h1:dvdCTIoAGbkWbcIKBniID56/7XHTt6WfxXNMxuziJ+w= google.golang.org/genproto/googleapis/api v0.0.0-20240506185236-b8a5c65736ae/go.mod h1:FfiGhwUm6CJviekPrc0oJ+7h29e+DmWU6UtjX0ZvI7Y= google.golang.org/genproto/googleapis/api v0.0.0-20240509183442-62759503f434/go.mod h1:FfiGhwUm6CJviekPrc0oJ+7h29e+DmWU6UtjX0ZvI7Y= -google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8 h1:W5Xj/70xIA4x60O/IFyXivR5MGqblAb8R3w26pnD6No= -google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8/go.mod h1:vPrPUTsDCYxXWjP7clS81mZ6/803D8K4iM9Ma27VKas= google.golang.org/genproto/googleapis/bytestream v0.0.0-20240429193739-8cf5692501f6/go.mod h1:ULqtoQMxDLNRfW+pJbKA68wtIy1OiYjdIsJs3PMpzh8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0= google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE= @@ -1869,66 +1429,48 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go. google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240506185236-b8a5c65736ae/go.mod h1:I7Y+G38R2bu5j1aLzfFmQfTcU/WnFuqDwLZAbvKTKpM= google.golang.org/genproto/googleapis/rpc v0.0.0-20240509183442-62759503f434/go.mod h1:I7Y+G38R2bu5j1aLzfFmQfTcU/WnFuqDwLZAbvKTKpM= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 h1:mxSlqyb8ZAHsYDCfiXN1EDdNTdvjUJSLY+OnAUtYNYA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8/go.mod h1:I7Y+G38R2bu5j1aLzfFmQfTcU/WnFuqDwLZAbvKTKpM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240730163845-b1a4ccb954bf/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/grpc v0.0.0-20170208002647-2a6bf6142e96/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= +google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= +google.golang.org/grpc v1.58.0/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/grpc v1.60.0/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= +google.golang.org/protobuf v1.27.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/djherbis/atime.v1 v1.0.0/go.mod h1:hQIUStKmJfvf7xdh/wtK84qe+DsTV5LnA9lzxxtPpJ8= gopkg.in/djherbis/stream.v1 v1.3.1/go.mod h1:aEV8CBVRmSpLamVJfM903Npic1IKmb2qS30VAZ+sssg= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= -gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M= -gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= -gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= -gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tylerb/graceful.v1 v1.2.15/go.mod h1:yBhekWvR20ACXVObSSdD3u6S9DeSylanL2PAbAC/uJ8= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.2.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A= +gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= +honnef.co/go/tools v0.3.3/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw= honnef.co/go/tools v0.4.3/go.mod h1:36ZgoUOrqOk1GxwHhyryEkq8FQWkUO2xGuSMhUCcdvA= lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= @@ -1948,5 +1490,8 @@ modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE= mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ= +mvdan.cc/unparam v0.0.0-20220706161116-678bad134442/go.mod h1:F/Cxw/6mVrNKqrR2YjFf5CaW0Bw4RL8RfbEf4GRggJk= mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d/go.mod h1:IeHQjmn6TOD+e4Z3RFiZMMsLVL+A96Nvptar8Fj71is= +pgregory.net/rapid v0.5.5/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/scripts/execute-test.sh b/scripts/execute-test.sh index f7e003c4..bd0ba9de 100755 --- a/scripts/execute-test.sh +++ b/scripts/execute-test.sh @@ -29,6 +29,7 @@ clean_contracts() { find artifacts/archway -type f -exec rm {} \; find artifacts/evm -type f -exec rm {} \; find artifacts/sui -type f -exec rm {} \; + find artifacts/stacks -type f -exec rm {} \; } e2e_test() { diff --git a/scripts/optimize-xcall-build.sh b/scripts/optimize-xcall-build.sh index 0d41b3e8..99afae10 100755 --- a/scripts/optimize-xcall-build.sh +++ b/scripts/optimize-xcall-build.sh @@ -4,6 +4,7 @@ mkdir -p artifacts/icon mkdir -p artifacts/archway mkdir -p artifacts/evm mkdir -p artifacts/sui +mkdir -p artifacts/stacks LOCAL_X_CALL_REPO=".xcall-multi" LOCAL_ARTIFACT_XCALL_SUI="xcall" @@ -27,6 +28,7 @@ build_xCall_contracts() { cp artifacts/archway/*.wasm ../artifacts/archway/ cp artifacts/icon/*.jar ../artifacts/icon/ cp -R artifacts/evm/ ../artifacts/evm/ + cp -R contracts/stacks/*.clar ../artifacts/stacks/ cd - } diff --git a/test/sample-config.yaml b/test/sample-config.yaml index 3bb8292b..57d47bff 100644 --- a/test/sample-config.yaml +++ b/test/sample-config.yaml @@ -1,4 +1,31 @@ chains: + + - name: stacks + version: "3" + environment: remote + rpc_uri: https://tt.net.solidwallet.io/stacks-api + contracts_path: "$BASE_PATH/artifacts/stacks" + config_path: "$BASE_PATH/test/chains/stacks/data" + chain_config: + type: stacks + name: stacks + chain_id: stacks.local + image: + repository: blockstack/stacks-blockchain + version: latest + uid_gid: "" + bin: stx + bech32_prefix: ST + denom: stx + coin_type: 5757 + gas_prices: 0.001stx + gas_adjustment: 1.3 + trusting_period: 508h + no_host_mount: false + contracts: + xcall: "$BASE_PATH/artifacts/stacks/xcall.clar" + connection: "$BASE_PATH/artifacts/stacks/centralized_connection.clar" + dapp: "$BASE_PATH/artifacts/stacks/mock_dapp_multi.clar" - name: stellar version: "3" From 59d0d891a4cf2fb601cecfb901287bc4def57edc Mon Sep 17 00:00:00 2001 From: "Biru C. Sainju" Date: Fri, 8 Nov 2024 11:19:53 +0545 Subject: [PATCH 5/9] fix: fixed testsuite for stacks --- cmd/config.go | 4 ++++ test/testsuite/testsuite.go | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/cmd/config.go b/cmd/config.go index 65788f67..c76c4af0 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -10,6 +10,7 @@ import ( jsoniter "github.com/json-iterator/go" "github.com/icon-project/centralized-relay/relayer/chains/solana" + "github.com/icon-project/centralized-relay/relayer/chains/stacks" "github.com/icon-project/centralized-relay/relayer/chains/steller" "github.com/icon-project/centralized-relay/relayer/chains/sui" "github.com/icon-project/centralized-relay/relayer/chains/wasm" @@ -266,6 +267,8 @@ func (iw *ProviderConfigYAMLWrapper) UnmarshalYAML(n *yaml.Node) error { iw.Value = new(steller.Config) case "sui": iw.Value = new(sui.Config) + case "stacks": + iw.Value = new(stacks.Config) default: return fmt.Errorf("%s is an invalid chain type, check your config file", iw.Type) } @@ -280,6 +283,7 @@ func UnmarshalJSONProviderConfig(data []byte, customTypes map[string]reflect.Typ "evm": reflect.TypeOf(evm.Config{}), "cosmos": reflect.TypeOf(wasm.Config{}), "sui": reflect.TypeOf(sui.Config{}), + "stacks": reflect.TypeOf(stacks.Config{}), } if err := jsoniter.Unmarshal(data, &m); err != nil { return nil, err diff --git a/test/testsuite/testsuite.go b/test/testsuite/testsuite.go index 2c031dc5..5b2caaad 100644 --- a/test/testsuite/testsuite.go +++ b/test/testsuite/testsuite.go @@ -5,10 +5,12 @@ import ( "fmt" "strconv" + "github.com/icon-project/centralized-relay/relayer/kms" "github.com/icon-project/centralized-relay/test/chains/cosmos" "github.com/icon-project/centralized-relay/test/chains/evm" "github.com/icon-project/centralized-relay/test/chains/icon" "github.com/icon-project/centralized-relay/test/chains/solana" + "github.com/icon-project/centralized-relay/test/chains/stacks" "github.com/icon-project/centralized-relay/test/chains/stellar" "github.com/icon-project/centralized-relay/test/chains/sui" "github.com/icon-project/centralized-relay/test/interchaintest" @@ -283,6 +285,10 @@ func buildChain(log *zap.Logger, testName string, s *E2ETestSuite, cfg *testconf var ( chain chains.Chain ) + kmsProvider, err := kms.NewKMSConfig(context.Background(), &s.cfg.RelayerConfig.KMS_ID) + if err != nil { + fmt.Println("error getting kms", err) + } switch cfg.ChainConfig.Type { case "icon": chain = icon.NewIconRemotenet(testName, log, cfg.ChainConfig, s.DockerClient, s.network, cfg) @@ -302,6 +308,9 @@ func buildChain(log *zap.Logger, testName string, s *E2ETestSuite, cfg *testconf case "stellar": chain := stellar.NewStellarRemotenet(testName, log, cfg.ChainConfig, s.DockerClient, s.network, cfg) return chain, nil + case "stacks": + chain := stacks.NewStacksLocalnet(testName, log, cfg.ChainConfig, cfg, kmsProvider) + return chain, nil default: return nil, fmt.Errorf("unexpected error, unknown chain type: %s for chain: %s", cfg.ChainConfig.Type, cfg.Name) } From f5d69caaa1ecb96ae2f81013c66f96c8c420936a Mon Sep 17 00:00:00 2001 From: CyrusVorwald <90732384+CyrusVorwald@users.noreply.github.com> Date: Sun, 10 Nov 2024 17:57:22 -0500 Subject: [PATCH 6/9] feat: improve stacks listener --- go.mod | 2 +- go.sum | 4 +- relayer/chains/stacks/client.go | 165 +-- relayer/chains/stacks/client_test.go | 31 - relayer/chains/stacks/events/listener.go | 251 ++++ relayer/chains/stacks/events/processor.go | 76 ++ relayer/chains/stacks/events/store.go | 60 + relayer/chains/stacks/events/system.go | 55 + relayer/chains/stacks/events/types.go | 87 ++ relayer/chains/stacks/interfaces/client.go | 2 +- relayer/chains/stacks/listener.go | 85 +- relayer/chains/stacks/mocks/client_mock.go | 7 +- relayer/chains/stacks/provider.go | 7 +- relayer/chains/stacks/query.go | 126 ++- test/chains/icon/localnet.go | 4 +- test/chains/stacks/remotenet.go | 1196 +++++++++++++++++--- test/e2e/e2e_test.go | 3 + test/sample-config.yaml | 316 +++--- 18 files changed, 1894 insertions(+), 583 deletions(-) create mode 100644 relayer/chains/stacks/events/listener.go create mode 100644 relayer/chains/stacks/events/processor.go create mode 100644 relayer/chains/stacks/events/store.go create mode 100644 relayer/chains/stacks/events/system.go create mode 100644 relayer/chains/stacks/events/types.go diff --git a/go.mod b/go.mod index 42b4335c..88685439 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/gofrs/flock v0.8.1 github.com/gorilla/websocket v1.5.3 github.com/icon-project/goloop v1.3.11 - github.com/icon-project/stacks-go-sdk v0.3.1 + github.com/icon-project/stacks-go-sdk v0.3.2 github.com/json-iterator/go v1.1.12 github.com/jsternberg/zap-logfmt v1.3.0 github.com/near/borsh-go v0.3.1 diff --git a/go.sum b/go.sum index d6a8c6c8..9e8294f5 100644 --- a/go.sum +++ b/go.sum @@ -874,8 +874,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/icon-project/goloop v1.3.11 h1:Lry7rCM9QeZudiAqi7n7CqmoOsg7qNDwrw6O12j7vuo= github.com/icon-project/goloop v1.3.11/go.mod h1:9PoWRb5kowidc9jYy0RLuLpay1zT5FXgEKijx7rDQjE= -github.com/icon-project/stacks-go-sdk v0.3.1 h1:tw7sz9P6HICG+sclTCFs2wgYs1I5Xom3QZLhRXJOOIw= -github.com/icon-project/stacks-go-sdk v0.3.1/go.mod h1:yg4j/KACqhZ7+ZR0zpf3tE6Vw6HiZKBpFtVFzZlaGKw= +github.com/icon-project/stacks-go-sdk v0.3.2 h1:WzzhNxSQIMZg4PM+II8m+9mxjnJfTpbWeQ0/4GRrmKI= +github.com/icon-project/stacks-go-sdk v0.3.2/go.mod h1:yg4j/KACqhZ7+ZR0zpf3tE6Vw6HiZKBpFtVFzZlaGKw= github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= diff --git a/relayer/chains/stacks/client.go b/relayer/chains/stacks/client.go index 628eacdb..0a345133 100644 --- a/relayer/chains/stacks/client.go +++ b/relayer/chains/stacks/client.go @@ -8,10 +8,7 @@ import ( "math/big" "os" "strings" - "sync" - "time" - "github.com/gorilla/websocket" "github.com/icon-project/centralized-relay/relayer/chains/stacks/interfaces" "github.com/icon-project/stacks-go-sdk/pkg/abi" "github.com/icon-project/stacks-go-sdk/pkg/clarity" @@ -29,9 +26,6 @@ type Client struct { apiClient blockchainApiClient.APIClient rpcApiClient rpcClient.APIClient log *zap.Logger - mtx sync.Mutex - wsConn *websocket.Conn - idCursor int64 pendingRequests map[int64]chan *json.RawMessage network *stacks.StacksNetwork xCallProxyABI *abi.ABI @@ -98,6 +92,17 @@ func (c *Client) GetAccountBalance(ctx context.Context, address string) (*big.In return balance, nil } +func (c *Client) GetContractById(ctx context.Context, contractId string) (*blockchainApiClient.SmartContract, error) { + resp, httpResp, err := c.apiClient.SmartContractsAPI.GetContractById(ctx, contractId).Execute() + if err != nil { + if httpResp != nil && httpResp.StatusCode == 404 { + return nil, nil // Contract doesn't exist + } + return nil, err + } + return resp, nil +} + func (c *Client) GetAccountNonce(ctx context.Context, address string) (uint64, error) { principal := blockchainApiClient.GetFilteredEventsAddressParameter{ String: &address, @@ -465,157 +470,21 @@ func (c *Client) ExecuteRollback(ctx context.Context, contractAddress string, ar return txID, nil } -func (c *Client) SubscribeToEvents(ctx context.Context, eventTypes []string, callback interfaces.EventCallback) error { - wsURL, _ := c.apiClient.GetConfig().Servers.URL(0, make(map[string]string)) +func (c *Client) GetWebSocketURL() string { + baseURL, _ := c.apiClient.GetConfig().Servers.URL(0, make(map[string]string)) + wsURL := baseURL if strings.HasPrefix(wsURL, "http://") { wsURL = strings.Replace(wsURL, "http://", "ws://", 1) } else if strings.HasPrefix(wsURL, "https://") { wsURL = strings.Replace(wsURL, "https://", "wss://", 1) } + if !strings.HasSuffix(wsURL, "/") { wsURL += "/" } - wsURL += "extended/v1/ws" - - var err error - c.wsConn, _, err = websocket.DefaultDialer.Dial(wsURL, nil) - if err != nil { - return err - } - - go c.listenToMessages(ctx, callback) - - for _, eventType := range eventTypes { - if err := c.subscribe(eventType); err != nil { - return err - } - } - - return nil -} - -func (c *Client) sendRPCRequest(method string, params interface{}) (int64, error) { - c.mtx.Lock() - defer c.mtx.Unlock() - - c.idCursor++ - id := c.idCursor - - request := map[string]interface{}{ - "jsonrpc": "2.0", - "id": id, - "method": method, - "params": params, - } - - message, err := json.Marshal(request) - if err != nil { - return 0, err - } - - c.pendingRequests[id] = make(chan *json.RawMessage, 1) - err = c.wsConn.WriteMessage(websocket.TextMessage, message) - if err != nil { - delete(c.pendingRequests, id) - return 0, err - } - - return id, nil -} - -func (c *Client) subscribe(eventType string) error { - params := map[string]interface{}{ - "event": eventType, - } - id, err := c.sendRPCRequest("subscribe", params) - if err != nil { - return err - } - - responseChan := c.pendingRequests[id] - select { - case response := <-responseChan: - var resp struct { - Jsonrpc string `json:"jsonrpc"` - Id int64 `json:"id"` - Result map[string]interface{} `json:"result"` - Error map[string]interface{} `json:"error"` - } - err = json.Unmarshal(*response, &resp) - if err != nil { - return err - } - if resp.Error != nil { - return fmt.Errorf("subscription error: %v", resp.Error) - } - return nil - case <-time.After(5 * time.Second): - return fmt.Errorf("subscription timeout") - } -} - -func (c *Client) listenToMessages(ctx context.Context, callback interfaces.EventCallback) { - defer c.wsConn.Close() - for { - select { - case <-ctx.Done(): - return - default: - _, message, err := c.wsConn.ReadMessage() - if err != nil { - c.log.Error("WebSocket read error", zap.Error(err)) - return - } - - var parsedMessage map[string]interface{} - if err := json.Unmarshal(message, &parsedMessage); err != nil { - c.log.Error("Failed to parse message", zap.Error(err)) - continue - } - - c.handleMessage(parsedMessage, callback) - } - } -} - -func (c *Client) handleMessage(message map[string]interface{}, callback interfaces.EventCallback) { - if idVal, ok := message["id"]; ok { - idFloat, ok := idVal.(float64) - if !ok { - c.log.Error("Invalid id in response") - return - } - id := int64(idFloat) - - c.mtx.Lock() - responseChan, ok := c.pendingRequests[id] - c.mtx.Unlock() - if !ok { - c.log.Error("Received response for unknown request id", zap.Int64("id", id)) - return - } + wsURL += "extended/v1/ws" - rawMessage, err := json.Marshal(message) - if err != nil { - c.log.Error("Failed to marshal message", zap.Error(err)) - return - } - responseChan <- (*json.RawMessage)(&rawMessage) - - c.mtx.Lock() - delete(c.pendingRequests, id) - c.mtx.Unlock() - } else { - if method, ok := message["method"]; ok { - methodStr, _ := method.(string) - params := message["params"] - if err := callback(methodStr, params); err != nil { - c.log.Error("Callback error", zap.Error(err)) - } - } else { - c.log.Error("Unknown message format", zap.Any("message", message)) - } - } + return wsURL } diff --git a/relayer/chains/stacks/client_test.go b/relayer/chains/stacks/client_test.go index 6a2b2bba..fe334344 100644 --- a/relayer/chains/stacks/client_test.go +++ b/relayer/chains/stacks/client_test.go @@ -5,9 +5,7 @@ import ( "encoding/hex" "path/filepath" "strings" - "sync" "testing" - "time" "github.com/icon-project/centralized-relay/relayer/chains/stacks" "github.com/icon-project/stacks-go-sdk/pkg/clarity" @@ -178,32 +176,3 @@ func TestClient_SetAdmin(t *testing.T) { t.Logf("SetAdmin transaction ID: %s", txID) } - -func TestClient_SubscribeToEvents(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cancel() - - logger, _ := zap.NewDevelopment() - network := stacksSdk.NewStacksTestnet() - xcallAbiPath := filepath.Join("abi", "xcall-proxy-abi.json") - client, err := stacks.NewClient(logger, network, xcallAbiPath) - if err != nil { - t.Fatalf("Failed to create client: %v", err) - } - - var wg sync.WaitGroup - wg.Add(1) - - callback := func(eventType string, data interface{}) error { - t.Logf("Received event: %s, Data: %+v", eventType, data) - wg.Done() - return nil - } - - err = client.SubscribeToEvents(ctx, []string{"block"}, callback) - if err != nil { - t.Fatalf("Failed to subscribe to events: %v", err) - } - - wg.Wait() -} diff --git a/relayer/chains/stacks/events/listener.go b/relayer/chains/stacks/events/listener.go new file mode 100644 index 00000000..73b6d676 --- /dev/null +++ b/relayer/chains/stacks/events/listener.go @@ -0,0 +1,251 @@ +package events + +import ( + "context" + "encoding/json" + "fmt" + "sync" + "time" + + "container/ring" + + "github.com/cenkalti/backoff/v4" + "github.com/gorilla/websocket" + "go.uber.org/zap" +) + +type EventListener struct { + wsURL string + conn *websocket.Conn + eventChan chan *Event + processChan chan *Event + backlog *ring.Ring + maxBufferSize int + mu sync.RWMutex + log *zap.Logger + ctx context.Context + cancel context.CancelFunc +} + +func NewEventListener(ctx context.Context, wsURL string, bufferSize int, log *zap.Logger) *EventListener { + ctx, cancel := context.WithCancel(ctx) + return &EventListener{ + wsURL: wsURL, + eventChan: make(chan *Event, bufferSize), + processChan: make(chan *Event, bufferSize), + backlog: ring.New(bufferSize), + maxBufferSize: bufferSize, + log: log, + ctx: ctx, + cancel: cancel, + } +} + +func (l *EventListener) Start() error { + go l.maintainConnection() + go l.bufferEvents() + return nil +} + +func (l *EventListener) Stop() { + l.cancel() + if l.conn != nil { + l.conn.Close() + } + close(l.eventChan) + close(l.processChan) +} + +func (l *EventListener) maintainConnection() { + b := backoff.NewExponentialBackOff() + b.MaxElapsedTime = 0 // Retry forever + + for { + select { + case <-l.ctx.Done(): + return + default: + if err := l.connect(); err != nil { + l.log.Error("WebSocket connection failed", zap.Error(err)) + time.Sleep(b.NextBackOff()) + continue + } + b.Reset() + l.readMessages() + } + } +} + +func (l *EventListener) connect() error { + l.mu.Lock() + defer l.mu.Unlock() + + if l.conn != nil { + l.conn.Close() + } + + conn, _, err := websocket.DefaultDialer.Dial(l.wsURL, nil) + if err != nil { + return err + } + + l.conn = conn + + // Subscribe to all event types + for _, eventType := range []string{EmitMessage, CallMessage, RollbackMessage} { + if err := l.subscribe(eventType); err != nil { + l.conn.Close() + return fmt.Errorf("failed to subscribe to %s: %w", eventType, err) + } + } + + return nil +} + +func (l *EventListener) readMessages() { + for { + select { + case <-l.ctx.Done(): + return + default: + _, message, err := l.conn.ReadMessage() + if err != nil { + l.log.Error("Failed to read WebSocket message", zap.Error(err)) + return + } + + event, err := l.parseEvent(message) + if err != nil { + l.log.Error("Failed to parse event", zap.Error(err)) + continue + } + + if event == nil { + continue + } + + l.eventChan <- event + } + } +} + +func (l *EventListener) bufferEvents() { + for { + select { + case event := <-l.eventChan: + l.backlog.Value = event + l.backlog = l.backlog.Next() + l.processChan <- event + case <-l.ctx.Done(): + return + } + } +} + +func (l *EventListener) subscribe(eventType string) error { + request := WSRequest{ + JSONRPC: "2.0", + ID: time.Now().UnixNano(), + Method: "subscribe", + Params: map[string]interface{}{ + "event": eventType, + }, + } + + data, err := json.Marshal(request) + if err != nil { + return fmt.Errorf("failed to marshal subscription request: %w", err) + } + + l.mu.Lock() + defer l.mu.Unlock() + + if err := l.conn.WriteMessage(websocket.TextMessage, data); err != nil { + return fmt.Errorf("failed to send subscription request: %w", err) + } + + _, message, err := l.conn.ReadMessage() + if err != nil { + return fmt.Errorf("failed to read subscription response: %w", err) + } + + var response WSResponse + if err := json.Unmarshal(message, &response); err != nil { + return fmt.Errorf("failed to unmarshal subscription response: %w", err) + } + + if response.Error != nil { + return fmt.Errorf("subscription failed: %s", response.Error.Message) + } + + l.log.Info("Successfully subscribed to event", zap.String("type", eventType)) + return nil +} + +func (l *EventListener) parseEvent(message []byte) (*Event, error) { + var wsMsg WSMessage + if err := json.Unmarshal(message, &wsMsg); err != nil { + return nil, fmt.Errorf("failed to unmarshal WebSocket message: %w", err) + } + + if wsMsg.Method != "event" { + return nil, nil + } + + var smartContractLog SmartContractLogEvent + if err := json.Unmarshal(wsMsg.Params, &smartContractLog); err != nil { + return nil, fmt.Errorf("failed to unmarshal smart contract log: %w", err) + } + + if smartContractLog.EventType != "smart_contract_log" || + smartContractLog.ContractEvent.Topic != "print" { + return nil, nil + } + + var printValue struct { + Event string `json:"event"` + Data json.RawMessage `json:"data"` + } + if err := json.Unmarshal(smartContractLog.ContractEvent.Value, &printValue); err != nil { + return nil, fmt.Errorf("failed to unmarshal print value: %w", err) + } + + var eventData interface{} + switch printValue.Event { + case EmitMessage: + var data EmitMessageData + if err := json.Unmarshal(printValue.Data, &data); err != nil { + return nil, fmt.Errorf("failed to unmarshal emit message data: %w", err) + } + eventData = data + + case CallMessage: + var data CallMessageData + if err := json.Unmarshal(printValue.Data, &data); err != nil { + return nil, fmt.Errorf("failed to unmarshal call message data: %w", err) + } + eventData = data + + case RollbackMessage: + var data RollbackMessageData + if err := json.Unmarshal(printValue.Data, &data); err != nil { + return nil, fmt.Errorf("failed to unmarshal rollback message data: %w", err) + } + eventData = data + + default: + l.log.Debug("Ignoring unknown event type", zap.String("type", printValue.Event)) + return nil, nil + } + + event := &Event{ + ID: fmt.Sprintf("%s-%d", printValue.Event, time.Now().UnixNano()), + Type: printValue.Event, + Data: eventData, + BlockHeight: smartContractLog.BlockHeight, + Timestamp: time.Now(), + Raw: message, + } + + return event, nil +} diff --git a/relayer/chains/stacks/events/processor.go b/relayer/chains/stacks/events/processor.go new file mode 100644 index 00000000..a4b81964 --- /dev/null +++ b/relayer/chains/stacks/events/processor.go @@ -0,0 +1,76 @@ +package events + +import ( + "context" + + "go.uber.org/zap" +) + +type EventProcessor struct { + handlers []EventHandler + store EventStore + processChan chan *Event + maxWorkers int + workerTokens chan struct{} + log *zap.Logger + ctx context.Context + cancel context.CancelFunc +} + +func NewEventProcessor(ctx context.Context, store EventStore, processChan chan *Event, maxWorkers int, log *zap.Logger) *EventProcessor { + ctx, cancel := context.WithCancel(ctx) + return &EventProcessor{ + store: store, + processChan: processChan, + maxWorkers: maxWorkers, + workerTokens: make(chan struct{}, maxWorkers), + log: log, + ctx: ctx, + cancel: cancel, + } +} + +func (p *EventProcessor) AddHandler(handler EventHandler) { + p.handlers = append(p.handlers, handler) +} + +func (p *EventProcessor) Start() { + for i := 0; i < p.maxWorkers; i++ { + go p.worker() + } +} + +func (p *EventProcessor) Stop() { + p.cancel() +} + +func (p *EventProcessor) worker() { + for { + select { + case <-p.ctx.Done(): + return + case event := <-p.processChan: + p.workerTokens <- struct{}{} + p.processEvent(event) + <-p.workerTokens + } + } +} + +func (p *EventProcessor) processEvent(event *Event) { + if err := p.store.SaveEvent(event); err != nil { + p.log.Error("Failed to save event", zap.Error(err)) + return + } + + for _, handler := range p.handlers { + if err := handler(event); err != nil { + p.log.Error("Handler failed", zap.Error(err)) + continue + } + } + + if err := p.store.MarkProcessed(event.ID); err != nil { + p.log.Error("Failed to mark event as processed", zap.Error(err)) + } +} diff --git a/relayer/chains/stacks/events/store.go b/relayer/chains/stacks/events/store.go new file mode 100644 index 00000000..6e19bb9e --- /dev/null +++ b/relayer/chains/stacks/events/store.go @@ -0,0 +1,60 @@ +package events + +import ( + "sync" +) + +type MemoryEventStore struct { + events map[string]*Event + processedEvents map[string]bool + lastProcessedHeight uint64 + mu sync.RWMutex +} + +func NewMemoryEventStore() *MemoryEventStore { + return &MemoryEventStore{ + events: make(map[string]*Event), + processedEvents: make(map[string]bool), + } +} + +func (s *MemoryEventStore) SaveEvent(event *Event) error { + s.mu.Lock() + defer s.mu.Unlock() + + s.events[event.ID] = event + return nil +} + +func (s *MemoryEventStore) GetEvents(fromHeight uint64) ([]*Event, error) { + s.mu.RLock() + defer s.mu.RUnlock() + + var events []*Event + for _, event := range s.events { + if event.BlockHeight >= fromHeight { + events = append(events, event) + } + } + return events, nil +} + +func (s *MemoryEventStore) MarkProcessed(eventID string) error { + s.mu.Lock() + defer s.mu.Unlock() + + if event, exists := s.events[eventID]; exists { + s.processedEvents[eventID] = true + if event.BlockHeight > s.lastProcessedHeight { + s.lastProcessedHeight = event.BlockHeight + } + } + return nil +} + +func (s *MemoryEventStore) GetLastProcessedHeight() (uint64, error) { + s.mu.RLock() + defer s.mu.RUnlock() + + return s.lastProcessedHeight, nil +} diff --git a/relayer/chains/stacks/events/system.go b/relayer/chains/stacks/events/system.go new file mode 100644 index 00000000..bd6fb069 --- /dev/null +++ b/relayer/chains/stacks/events/system.go @@ -0,0 +1,55 @@ +package events + +import ( + "context" + + "go.uber.org/zap" +) + +type EventSystem struct { + listener *EventListener + processor *EventProcessor + store EventStore + log *zap.Logger + ctx context.Context + cancel context.CancelFunc +} + +func NewEventSystem(ctx context.Context, wsURL string, log *zap.Logger) *EventSystem { + ctx, cancel := context.WithCancel(ctx) + + store := NewMemoryEventStore() + listener := NewEventListener(ctx, wsURL, 1000, log) + processor := NewEventProcessor(ctx, store, listener.processChan, 5, log) + + return &EventSystem{ + listener: listener, + processor: processor, + store: store, + log: log, + ctx: ctx, + cancel: cancel, + } +} + +func (s *EventSystem) Start() error { + if err := s.listener.Start(); err != nil { + return err + } + s.processor.Start() + return nil +} + +func (s *EventSystem) Stop() { + s.cancel() + s.listener.Stop() + s.processor.Stop() +} + +func (s *EventSystem) OnEvent(handler EventHandler) { + s.processor.AddHandler(handler) +} + +func (s *EventSystem) GetLastProcessedHeight() (uint64, error) { + return s.store.GetLastProcessedHeight() +} diff --git a/relayer/chains/stacks/events/types.go b/relayer/chains/stacks/events/types.go new file mode 100644 index 00000000..84fe235c --- /dev/null +++ b/relayer/chains/stacks/events/types.go @@ -0,0 +1,87 @@ +package events + +import ( + "encoding/json" + "time" +) + +type Event struct { + ID string + Type string + Data interface{} + BlockHeight uint64 + Timestamp time.Time + Raw []byte +} + +type SmartContractLogEvent struct { + EventType string `json:"event_type"` + ContractEvent ContractEvent `json:"contract_event"` + TxID string `json:"tx_id"` + BlockHeight uint64 `json:"block_height"` +} + +type ContractEvent struct { + ContractID string `json:"contract_id"` + Topic string `json:"topic"` + Value json.RawMessage `json:"value"` +} + +type WSMessage struct { + JSONRPC string `json:"jsonrpc"` + Method string `json:"method"` + Params json.RawMessage `json:"params"` +} + +type WSEventParams struct { + Event string `json:"event"` + Data json.RawMessage `json:"data"` +} + +type WSRequest struct { + JSONRPC string `json:"jsonrpc"` + ID int64 `json:"id"` + Method string `json:"method"` + Params interface{} `json:"params"` +} + +type WSResponse struct { + JSONRPC string `json:"jsonrpc"` + ID int64 `json:"id"` + Result json.RawMessage `json:"result"` + Error *struct { + Code int `json:"code"` + Message string `json:"message"` + } `json:"error,omitempty"` +} + +type EmitMessageData struct { + TargetNetwork string `json:"targetNetwork"` + Sn string `json:"sn"` + Msg string `json:"msg"` +} + +type CallMessageData struct { + ReqID string `json:"req_id"` + Sn string `json:"sn"` + Data string `json:"data"` +} + +type RollbackMessageData struct { + Sn string `json:"sn"` +} + +const ( + EmitMessage = "message_event" + CallMessage = "call_message_event" + RollbackMessage = "rollback_message_event" +) + +type EventHandler func(event *Event) error + +type EventStore interface { + SaveEvent(event *Event) error + GetEvents(fromHeight uint64) ([]*Event, error) + MarkProcessed(eventID string) error + GetLastProcessedHeight() (uint64, error) +} diff --git a/relayer/chains/stacks/interfaces/client.go b/relayer/chains/stacks/interfaces/client.go index 6d29cdd5..2d341168 100644 --- a/relayer/chains/stacks/interfaces/client.go +++ b/relayer/chains/stacks/interfaces/client.go @@ -25,7 +25,7 @@ type IClient interface { ExecuteRollback(ctx context.Context, contractAddress string, args []clarity.ClarityValue, senderAddress string, senderKey []byte) (string, error) GetLatestBlock(ctx context.Context) (*blockchainApiClient.GetBlocks200ResponseResultsInner, error) CallReadOnlyFunction(ctx context.Context, contractAddress string, contractName string, functionName string, functionArgs []string) (*string, error) - SubscribeToEvents(ctx context.Context, eventTypes []string, callback EventCallback) error + GetWebSocketURL() string Log() *zap.Logger } diff --git a/relayer/chains/stacks/listener.go b/relayer/chains/stacks/listener.go index 807124a8..b857e013 100644 --- a/relayer/chains/stacks/listener.go +++ b/relayer/chains/stacks/listener.go @@ -2,33 +2,34 @@ package stacks import ( "context" - "time" + "fmt" + "github.com/icon-project/centralized-relay/relayer/chains/stacks/events" providerTypes "github.com/icon-project/centralized-relay/relayer/types" "go.uber.org/zap" ) func (p *Provider) Listener(ctx context.Context, lastProcessedTx providerTypes.LastProcessedTx, blockInfoChan chan *providerTypes.BlockInfo) error { - eventTypes := p.getSubscribedEventTypes() + p.log.Info("Starting Stacks event listener") - errChan := make(chan error, 1) + wsURL := p.client.GetWebSocketURL() + p.log.Debug("Using WebSocket URL", zap.String("url", wsURL)) - callback := func(eventType string, data interface{}) error { - msg, err := p.getRelayMessageFromEvent(eventType, data) - if err != nil { - p.log.Error("Failed to parse relay message from event", zap.Error(err)) + eventSystem := events.NewEventSystem(ctx, wsURL, p.log) - select { - case errChan <- err: - default: - } + eventSystem.OnEvent(func(event *events.Event) error { + msg, err := p.getRelayMessageFromEvent(event.Type, event.Data) + if err != nil { + p.log.Error("Failed to parse relay message from event", + zap.Error(err), + zap.String("eventType", event.Type)) return err } - blockHeight := uint64(0) + msg.MessageHeight = event.BlockHeight blockInfo := &providerTypes.BlockInfo{ - Height: blockHeight, + Height: event.BlockHeight, Messages: []*providerTypes.Message{msg}, } @@ -38,56 +39,16 @@ func (p *Provider) Listener(ctx context.Context, lastProcessedTx providerTypes.L case <-ctx.Done(): return ctx.Err() } - } - - for { - select { - case <-ctx.Done(): - p.log.Info("Listener context canceled") - return ctx.Err() - default: - p.log.Info("Subscribing to Stacks contract events") - err := p.client.SubscribeToEvents(ctx, eventTypes, callback) - if err != nil { - p.log.Error("Failed to subscribe to events", zap.Error(err)) - select { - case <-time.After(5 * time.Second): - p.log.Info("Retrying subscription to events") - case <-ctx.Done(): - p.log.Info("Listener context canceled during retry wait") - return ctx.Err() - } - continue - } + }) - select { - case err := <-errChan: - p.log.Error("Error received in event subscription", zap.Error(err)) - select { - case <-time.After(5 * time.Second): - p.log.Info("Re-subscribing to events after error") - case <-ctx.Done(): - p.log.Info("Listener context canceled during resubscription wait") - return ctx.Err() - } - case <-ctx.Done(): - p.log.Info("Listener context canceled") - return ctx.Err() - } - } + if err := eventSystem.Start(); err != nil { + return fmt.Errorf("failed to start event system: %w", err) } -} -func (p *Provider) getSubscribedEventTypes() []string { - eventTypeSet := make(map[string]struct{}) - for _, eventMap := range p.contracts { - for _, eventType := range eventMap.SigType { - eventTypeSet[eventType] = struct{}{} - } - } - eventTypes := make([]string, 0, len(eventTypeSet)) - for et := range eventTypeSet { - eventTypes = append(eventTypes, et) - } - return eventTypes + p.log.Info("Stacks event listener started successfully") + + <-ctx.Done() + p.log.Info("Stopping Stacks event listener") + eventSystem.Stop() + return ctx.Err() } diff --git a/relayer/chains/stacks/mocks/client_mock.go b/relayer/chains/stacks/mocks/client_mock.go index 43b00141..b0ea95c9 100644 --- a/relayer/chains/stacks/mocks/client_mock.go +++ b/relayer/chains/stacks/mocks/client_mock.go @@ -4,7 +4,6 @@ import ( "context" "math/big" - "github.com/icon-project/centralized-relay/relayer/chains/stacks/interfaces" "github.com/icon-project/stacks-go-sdk/pkg/clarity" blockchainApiClient "github.com/icon-project/stacks-go-sdk/pkg/stacks_blockchain_api_client" "github.com/stretchr/testify/mock" @@ -90,9 +89,9 @@ func (m *MockClient) ExecuteRollback(ctx context.Context, contractAddress string return mockArgs.String(0), mockArgs.Error(1) } -func (m *MockClient) SubscribeToEvents(ctx context.Context, eventTypes []string, callback interfaces.EventCallback) error { - args := m.Called(ctx, eventTypes, callback) - return args.Error(0) +func (m *MockClient) GetWebSocketURL() string { + mockArgs := m.Called() + return mockArgs.String(0) } func (m *MockClient) Log() *zap.Logger { diff --git a/relayer/chains/stacks/provider.go b/relayer/chains/stacks/provider.go index efc2e865..0b1c6ae6 100644 --- a/relayer/chains/stacks/provider.go +++ b/relayer/chains/stacks/provider.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "math/big" + "os" "path/filepath" "sync" "time" @@ -50,7 +51,11 @@ func (c *Config) NewProvider(ctx context.Context, log *zap.Logger, homepath stri return nil, fmt.Errorf("no network found for nid: %v", c.NID) } - xcallAbiPath := filepath.Join("abi", "xcall-proxy-abi.json") + dir, err := os.Getwd() + if err != nil { + fmt.Println("Error:", err) + } + xcallAbiPath := filepath.Join(dir, "relayer/chains/stacks", "abi", "xcall-proxy-abi.json") client, err := NewClient(log, network, xcallAbiPath) if err != nil { return nil, fmt.Errorf("failed to create Stacks client: %v", err) diff --git a/relayer/chains/stacks/query.go b/relayer/chains/stacks/query.go index ca8debc1..8771ba43 100644 --- a/relayer/chains/stacks/query.go +++ b/relayer/chains/stacks/query.go @@ -4,15 +4,13 @@ import ( "context" "fmt" "reflect" - "time" - "github.com/icon-project/centralized-relay/relayer/events" + "github.com/icon-project/centralized-relay/relayer/chains/stacks/events" providerTypes "github.com/icon-project/centralized-relay/relayer/types" + blockchainApiClient "github.com/icon-project/stacks-go-sdk/pkg/stacks_blockchain_api_client" "go.uber.org/zap" ) -const eventListeningTimeout = 30 * time.Second - func (p *Provider) ShouldReceiveMessage(ctx context.Context, message *providerTypes.Message) (bool, error) { return true, nil } @@ -72,6 +70,43 @@ func (p *Provider) QueryLatestHeight(ctx context.Context) (uint64, error) { } func GetReceipt(tx interface{}) (*providerTypes.Receipt, error) { + if response, ok := tx.(*blockchainApiClient.GetTransactionById200Response); ok { + if mempool := response.GetMempoolTransactionList200ResponseResultsInner; mempool != nil { + if mempool.ContractCallMempoolTransaction1 != nil { + txStatus := mempool.ContractCallMempoolTransaction1.TxStatus.String + if txStatus == nil { + return nil, fmt.Errorf("nil tx status for contract call mempool transaction") + } + + return &providerTypes.Receipt{ + TxHash: mempool.ContractCallMempoolTransaction1.TxId, + Height: 0, + Status: *txStatus == "success", + }, nil + } + if mempool.SmartContractMempoolTransaction1 != nil { + txStatus := mempool.SmartContractMempoolTransaction1.TxStatus.String + if txStatus == nil { + return nil, fmt.Errorf("nil tx status for smart contract mempool transaction") + } + + return &providerTypes.Receipt{ + TxHash: mempool.SmartContractMempoolTransaction1.TxId, + Height: 0, + Status: *txStatus == "success", + }, nil + } + } + + if confirmed := response.GetTransactionList200ResponseResultsInner; confirmed != nil { + return getConfirmedReceipt(confirmed) + } + } + + return nil, fmt.Errorf("unsupported transaction response type") +} + +func getConfirmedReceipt(tx interface{}) (*providerTypes.Receipt, error) { val := reflect.ValueOf(tx).Elem() typ := val.Type() @@ -139,42 +174,74 @@ func GetReceipt(tx interface{}) (*providerTypes.Receipt, error) { } func (p *Provider) GenerateMessages(ctx context.Context, fromHeight uint64, toHeight uint64) ([]*providerTypes.Message, error) { - p.log.Info("Generating messages", zap.Uint64("fromHeight", fromHeight), zap.Uint64("toHeight", toHeight)) + p.log.Info("Generating messages", + zap.Uint64("fromHeight", fromHeight), + zap.Uint64("toHeight", toHeight)) + + ctx, cancel := context.WithTimeout(ctx, MAX_WAIT_TIME) + defer cancel() - eventTypes := p.getSubscribedEventTypes() var messages []*providerTypes.Message - errChan := make(chan error, 1) + messageChan := make(chan *providerTypes.Message) + errorChan := make(chan error, 1) + + wsURL := p.client.GetWebSocketURL() + eventSystem := events.NewEventSystem(ctx, wsURL, p.log) - callback := func(eventType string, data interface{}) error { - msg, err := p.getRelayMessageFromEvent(eventType, data) + eventSystem.OnEvent(func(event *events.Event) error { + if event.BlockHeight < fromHeight || event.BlockHeight > toHeight { + return nil + } + + msg, err := p.getRelayMessageFromEvent(event.Type, event.Data) if err != nil { - p.log.Error("Failed to parse relay message from event", zap.Error(err)) - return err + return fmt.Errorf("failed to parse relay message from event: %w", err) } - msg.MessageHeight = fromHeight - messages = append(messages, msg) - return nil - } + msg.MessageHeight = event.BlockHeight - ctxWithTimeout, cancel := context.WithTimeout(ctx, eventListeningTimeout) - defer cancel() + select { + case messageChan <- msg: + return nil + case <-ctx.Done(): + return ctx.Err() + } + }) - err := p.client.SubscribeToEvents(ctxWithTimeout, eventTypes, callback) - if err != nil { - return nil, fmt.Errorf("failed to subscribe to events: %w", err) - } + go func() { + defer close(messageChan) - select { - case err := <-errChan: - return nil, fmt.Errorf("error occurred while processing events: %w", err) - case <-ctxWithTimeout.Done(): - if len(messages) == 0 { - return nil, fmt.Errorf("no messages generated within the timeout period") + if err := eventSystem.Start(); err != nil { + errorChan <- fmt.Errorf("failed to start event system: %w", err) + return } - } - return messages, nil + <-ctx.Done() + eventSystem.Stop() + + if ctx.Err() == context.DeadlineExceeded { + p.log.Info("Event collection completed due to timeout") + } + }() + + for { + select { + case msg, ok := <-messageChan: + if !ok { + return messages, nil + } + messages = append(messages, msg) + + case err := <-errorChan: + return nil, err + + case <-ctx.Done(): + if len(messages) == 0 { + return nil, fmt.Errorf("no messages generated within the timeout period") + } + return messages, nil + } + } } func (p *Provider) FetchTxMessages(ctx context.Context, txHash string) ([]*providerTypes.Message, error) { @@ -185,6 +252,5 @@ func (p *Provider) FetchTxMessages(ctx context.Context, txHash string) ([]*provi return nil, fmt.Errorf("failed to get transaction receipt: %w", err) } - // Pass the same height for both from and to since we're looking at a specific transaction return p.GenerateMessages(ctx, receipt.Height, receipt.Height) } diff --git a/test/chains/icon/localnet.go b/test/chains/icon/localnet.go index aca8070c..4801d408 100644 --- a/test/chains/icon/localnet.go +++ b/test/chains/icon/localnet.go @@ -120,7 +120,7 @@ func (in *IconRemotenet) GetRelayConfig(ctx context.Context, rlyHome string, key NID: in.Config().ChainID, RPCURL: in.GetRPCAddress(), StartHeight: 0, - NetworkID: 0x3, + NetworkID: 0x2, Contracts: contracts, BlockInterval: "6s", Address: in.testconfig.RelayWalletAddress, @@ -418,7 +418,7 @@ func (in *IconRemotenet) NodeCommand(command ...string) []string { command = in.BinCommand(command...) return append(command, "--uri", in.GetRPCAddress(), //fmt.Sprintf("http://%s/api/v3", in.HostRPCPort), - "--nid", "0x3", + "--nid", "0x2", ) } diff --git a/test/chains/stacks/remotenet.go b/test/chains/stacks/remotenet.go index 12bf7177..2785ec7f 100644 --- a/test/chains/stacks/remotenet.go +++ b/test/chains/stacks/remotenet.go @@ -2,12 +2,14 @@ package stacks import ( "context" + "encoding/hex" "fmt" "os" "strings" "time" stacksClient "github.com/icon-project/centralized-relay/relayer/chains/stacks" + "github.com/icon-project/centralized-relay/relayer/chains/stacks/events" "github.com/icon-project/centralized-relay/relayer/kms" "github.com/icon-project/centralized-relay/test/chains" "github.com/icon-project/centralized-relay/test/interchaintest/relayer/centralized" @@ -20,6 +22,15 @@ import ( "gopkg.in/yaml.v3" ) +const BLOCK_TIME = 5 * time.Second +const MAX_WAIT_TIME = 200 * BLOCK_TIME + +type contextKey string + +const ( + snContextKey contextKey = "sn" +) + type StacksLocalnet struct { log *zap.Logger testName string @@ -33,8 +44,8 @@ type StacksLocalnet struct { } func NewStacksLocalnet(testName string, log *zap.Logger, chainConfig chains.ChainConfig, testconfig *testconfig.Chain, kms kms.KMS) chains.Chain { - network := stacks.NewStacksLocalnet() - client, err := stacksClient.NewClient(log, network, testconfig.Contracts["xcall"]) + network := stacks.NewStacksTestnet() + client, err := stacksClient.NewClient(log, network, testconfig.Contracts["xcall-abi"]) if err != nil { log.Error("Failed to create Stacks client", zap.Error(err)) return nil @@ -67,7 +78,7 @@ func (s *StacksLocalnet) Height(ctx context.Context) (uint64, error) { func (s *StacksLocalnet) GetRelayConfig(ctx context.Context, rlyHome string, keyName string) ([]byte, error) { contracts := make(map[string]string) - contracts["xcall"] = s.GetContractAddress("xcall") + contracts["xcall-proxy"] = s.GetContractAddress("xcall-proxy") contracts["connection"] = s.GetContractAddress("connection") config := ¢ralized.StacksRelayerChainConfig{ @@ -95,7 +106,7 @@ func (s *StacksLocalnet) GetContractAddress(key string) string { func (s *StacksLocalnet) SetupXCall(ctx context.Context) error { if s.testconfig.Environment == "preconfigured" { testcase := ctx.Value("testcase").(string) - s.IBCAddresses["xcall"] = "STXCALLPROXYADDRESS" + s.IBCAddresses["xcall-proxy"] = "STXCALLPROXYADDRESS" s.IBCAddresses["connection"] = "STXCONNECTIONADDRESS" s.IBCAddresses[fmt.Sprintf("dapp-%s", testcase)] = "STXDAPPADDRESS" return nil @@ -106,34 +117,456 @@ func (s *StacksLocalnet) SetupXCall(ctx context.Context) error { return fmt.Errorf("failed to load deployer's private key: %w", err) } - xcallContractName := "xcall-proxy" - codeBody, err := os.ReadFile(s.testconfig.Contracts["xcall"]) + deployments := []struct { + name string // Contract name for deployment + contract string // Key in testconfig.Contracts + wait bool // Whether to wait for confirmation + postDeploy func(contractAddress string) error // Optional post-deployment initialization + }{ + {"xcall-common-trait", "common-trait", true, nil}, + {"xcall-receiver-trait", "receiver-trait", true, nil}, + {"xcall-impl-trait", "impl-trait", true, nil}, + {"xcall-proxy-trait", "proxy-trait", true, nil}, + + {"util", "util", true, nil}, + {"rlp-encode", "rlp-encode", true, nil}, + {"rlp-decode", "rlp-decode", true, nil}, + + {"xcall-proxy", "xcall-proxy", true, nil}, + + {"centralized-connection", "connection", true, nil}, + + {"xcall-impl-v3", "xcall-impl", true, func(proxyAddr string) error { + implAddr := senderAddress + ".xcall-impl-v3" + implPrincipal, err := clarity.StringToPrincipal(implAddr) + if err != nil { + return fmt.Errorf("failed to convert implementation address to principal: %w", err) + } + + upgradeTx, err := transaction.MakeContractCall( + senderAddress, + "xcall-proxy", + "upgrade", + []clarity.ClarityValue{ + implPrincipal, + clarity.NewOptionNone(), + }, + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create upgrade transaction: %w", err) + } + + txID, err := transaction.BroadcastTransaction(upgradeTx, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast upgrade transaction: %w", err) + } + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return fmt.Errorf("failed to confirm upgrade transaction: %w", err) + } + + err = s.initializeXCallImpl(ctx, privateKey, senderAddress) + if err != nil { + return fmt.Errorf("failed to initialize xcall-impl: %w", err) + } + + err = s.setAdminXCallImpl(ctx, privateKey, senderAddress) + if err != nil { + return fmt.Errorf("failed to set admin for xcall-impl: %w", err) + } + + err = s.setDefaultConnection(ctx, privateKey, senderAddress) + if err != nil { + return fmt.Errorf("failed to set default connection: %w", err) + } + + err = s.setProtocolFeeHandler(ctx, privateKey, senderAddress) + if err != nil { + return fmt.Errorf("failed to set protocol fee handler: %w", err) + } + + err = s.setConnectionFees(ctx, privateKey, senderAddress) + if err != nil { + return fmt.Errorf("failed to set connection fees: %w", err) + } + + err = s.setProtocolFee(ctx, privateKey, senderAddress) + if err != nil { + return fmt.Errorf("failed to set protocol fee: %w", err) + } + + s.log.Info("Initialized proxy with implementation", + zap.String("proxy", proxyAddr), + zap.String("implementation", implAddr)) + + return nil + }}, + } + + connectionContractName := "centralized-connection" + implContractName := "xcall-impl-v3" + proxyContractName := "xcall-impl-v3" + + s.IBCAddresses["xcall-proxy"] = senderAddress + "." + proxyContractName + s.IBCAddresses["xcall-impl"] = senderAddress + "." + implContractName + s.IBCAddresses["connection"] = senderAddress + "." + connectionContractName + + deployedContracts := make(map[string]string) + + for _, deployment := range deployments { + contractAddress := senderAddress + "." + deployment.name + deployedContracts[deployment.name] = contractAddress + + contract, err := s.client.GetContractById(ctx, contractAddress) + if err != nil { + return fmt.Errorf("failed to check contract existence for %s: %w", deployment.name, err) + } + if contract != nil { + txResp, err := s.client.GetTransactionById(ctx, contract.TxId) + if err == nil { + receipt, err := stacksClient.GetReceipt(txResp) + if err == nil && receipt.Status { + s.log.Info("Contract already successfully deployed, skipping", + zap.String("contract", deployment.name), + zap.String("address", contractAddress)) + continue + } + } + } + + codeBody, err := os.ReadFile(s.testconfig.Contracts[deployment.contract]) + if err != nil { + return fmt.Errorf("failed to read contract code for %s: %w", deployment.name, err) + } + + tx, err := transaction.MakeContractDeploy( + deployment.name, + string(codeBody), + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create contract deploy transaction for %s: %w", deployment.name, err) + } + + txID, err := transaction.BroadcastTransaction(tx, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast transaction for %s: %w", deployment.name, err) + } + + s.log.Info("Deployed contract", + zap.String("contract", deployment.name), + zap.String("txID", txID)) + + if deployment.wait { + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return fmt.Errorf("failed to confirm transaction for %s: %w", deployment.name, err) + } + } + + if deployment.postDeploy != nil { + if err := deployment.postDeploy(contractAddress); err != nil { + return fmt.Errorf("post-deployment initialization failed for %s: %w", deployment.name, err) + } + } + } + + s.IBCAddresses["xcall-proxy"] = deployedContracts["xcall-proxy"] + s.IBCAddresses["xcall-impl"] = deployedContracts["xcall-impl-v3"] + s.IBCAddresses["connection"] = deployedContracts["centralized-connection"] + + return nil +} + +func (s *StacksLocalnet) setDefaultConnection(ctx context.Context, privateKey []byte, senderAddress string) error { + nid := "test" + connectionAddress := senderAddress + "." + "centralized-connection" + + nidArg, err := clarity.NewStringASCII(nid) if err != nil { - return fmt.Errorf("failed to read xcall contract code: %w", err) + return fmt.Errorf("failed to create nid argument: %w", err) } - tx, err := transaction.MakeContractDeploy( - xcallContractName, - string(codeBody), + connArg, err := clarity.NewStringASCII(connectionAddress) + if err != nil { + return fmt.Errorf("failed to create connection address argument: %w", err) + } + + implAddr := senderAddress + "." + "xcall-impl-v3" + implPrincipal, err := clarity.StringToPrincipal(implAddr) + if err != nil { + return fmt.Errorf("failed to convert implementation address to principal: %w", err) + } + + args := []clarity.ClarityValue{ + nidArg, + connArg, + implPrincipal, + } + + txCall, err := transaction.MakeContractCall( + senderAddress, + "xcall-proxy", + "set-default-connection", + args, *s.network, senderAddress, privateKey, nil, nil, ) + if err != nil { - return fmt.Errorf("failed to create contract deploy transaction: %w", err) + return fmt.Errorf("failed to create set-default-connection transaction: %w", err) } - txID, err := transaction.BroadcastTransaction(tx, s.network) + txID, err := transaction.BroadcastTransaction(txCall, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast set-default-connection transaction: %w", err) + } + + s.log.Info("Set default connection in xcall-impl", zap.String("txID", txID)) + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return err + } + + return nil +} + +func (s *StacksLocalnet) initializeXCallImpl(ctx context.Context, privateKey []byte, senderAddress string) error { + nid := s.cfg.ChainID + addr := senderAddress + + nidArg, err := clarity.NewStringASCII(nid) + if err != nil { + return fmt.Errorf("failed to create nid argument: %w", err) + } + + addrArg, err := clarity.NewStringASCII(addr) + if err != nil { + return fmt.Errorf("failed to create addr argument: %w", err) + } + + args := []clarity.ClarityValue{nidArg, addrArg} + + txCall, err := transaction.MakeContractCall( + senderAddress, + "xcall-impl-v3", + "init", + args, + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create init transaction: %w", err) + } + + txID, err := transaction.BroadcastTransaction(txCall, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast init transaction: %w", err) + } + + s.log.Info("Initialized xcall-impl contract", zap.String("txID", txID)) + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return err + } + + return nil +} + +func (s *StacksLocalnet) setConnectionFees(ctx context.Context, privateKey []byte, senderAddress string) error { + networks := []string{"stacks_testnet", "test"} + messageFees := map[string]uint64{"stacks_testnet": 500000, "test": 1000000} + responseFees := map[string]uint64{"stacks_testnet": 250000, "test": 500000} + + for _, nid := range networks { + nidArg, err := clarity.NewStringASCII(nid) + if err != nil { + return fmt.Errorf("failed to create nid argument: %w", err) + } + + messageFeeArg, _ := clarity.NewUInt(messageFees[nid]) + responseFeeArg, _ := clarity.NewUInt(responseFees[nid]) + + args := []clarity.ClarityValue{ + nidArg, + messageFeeArg, + responseFeeArg, + } + + txCall, err := transaction.MakeContractCall( + senderAddress, + "centralized-connection", + "set-fee", + args, + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create set-fee transaction: %w", err) + } + + txID, err := transaction.BroadcastTransaction(txCall, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast set-fee transaction: %w", err) + } + + s.log.Info("Set fee in centralized-connection", zap.String("txID", txID), zap.String("nid", nid)) + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return err + } + } + + return nil +} + +func (s *StacksLocalnet) setProtocolFee(ctx context.Context, privateKey []byte, senderAddress string) error { + protocolFee := uint64(100000) + protocolFeeClarity, _ := clarity.NewUInt(protocolFee) + + implAddr := s.IBCAddresses["xcall-impl"] + implPrincipal, err := clarity.StringToPrincipal(implAddr) + if err != nil { + return fmt.Errorf("failed to convert implPrincipal to principal: %w", err) + } + + args := []clarity.ClarityValue{ + protocolFeeClarity, + implPrincipal, + } + + txCall, err := transaction.MakeContractCall( + senderAddress, + "xcall-proxy", + "set-protocol-fee", + args, + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create set-protocol-fee transaction: %w", err) + } + + txID, err := transaction.BroadcastTransaction(txCall, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast set-protocol-fee transaction: %w", err) + } + + s.log.Info("Set protocol fee in xcall-proxy", zap.String("txID", txID)) + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return err + } + + return nil +} + +func (s *StacksLocalnet) setAdminXCallImpl(ctx context.Context, privateKey []byte, senderAddress string) error { + senderPrincipal, err := clarity.StringToPrincipal(senderAddress) + if err != nil { + return fmt.Errorf("failed to convert senderAddress to principal: %w", err) + } + + args := []clarity.ClarityValue{ + senderPrincipal, + } + + txCall, err := transaction.MakeContractCall( + senderAddress, + "xcall-impl-v3", + "set-admin", + args, + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create set-admin transaction: %w", err) + } + + txID, err := transaction.BroadcastTransaction(txCall, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast set-admin transaction: %w", err) + } + + s.log.Info("Set admin for xcall-impl", zap.String("txID", txID)) + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return err + } + + return nil +} + +func (s *StacksLocalnet) setProtocolFeeHandler(ctx context.Context, privateKey []byte, senderAddress string) error { + connAddr := s.IBCAddresses["connection"] + connPrincipal, err := clarity.StringToPrincipal(connAddr) + if err != nil { + return fmt.Errorf("failed to create connection principal: %w", err) + } + + implAddr := s.IBCAddresses["xcall-impl"] + + implPrincipal, err := clarity.StringToPrincipal(implAddr) + if err != nil { + return fmt.Errorf("failed to convert implPrincipal to principal: %w", err) + } + + args := []clarity.ClarityValue{ + connPrincipal, + implPrincipal, + } + + txCall, err := transaction.MakeContractCall( + senderAddress, + "xcall-proxy", + "set-protocol-fee-handler", + args, + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create set-protocol-fee-handler transaction: %w", err) + } + + txID, err := transaction.BroadcastTransaction(txCall, s.network) if err != nil { - return fmt.Errorf("failed to broadcast transaction: %w", err) + return fmt.Errorf("failed to broadcast set-protocol-fee-handler transaction: %w", err) } - s.log.Info("Deployed xcall-proxy contract", zap.String("txID", txID)) - - contractAddress := senderAddress + "." + xcallContractName - s.IBCAddresses["xcall"] = contractAddress + s.log.Info("Set protocol fee handler in xcall-proxy", zap.String("txID", txID)) err = s.waitForTransactionConfirmation(ctx, txID) if err != nil { @@ -154,6 +587,23 @@ func (s *StacksLocalnet) SetupConnection(ctx context.Context, target chains.Chai } connectionContractName := "centralized-connection" + contractAddress := senderAddress + "." + connectionContractName + + contract, err := s.client.GetContractById(ctx, contractAddress) + if err == nil && contract != nil { + txResp, err := s.client.GetTransactionById(ctx, contract.TxId) + if err == nil { + receipt, err := stacksClient.GetReceipt(txResp) + if err == nil && receipt.Status { + s.log.Info("Connection contract already successfully deployed, skipping deployment", + zap.String("address", contractAddress)) + + s.IBCAddresses["connection"] = contractAddress + return s.initializeConnection(ctx, privateKey, senderAddress) + } + } + } + codeBody, err := os.ReadFile(s.testconfig.Contracts["connection"]) if err != nil { return fmt.Errorf("failed to read connection contract code: %w", err) @@ -178,8 +628,6 @@ func (s *StacksLocalnet) SetupConnection(ctx context.Context, target chains.Chai } s.log.Info("Deployed centralized-connection contract", zap.String("txID", txID)) - - contractAddress := senderAddress + "." + connectionContractName s.IBCAddresses["connection"] = contractAddress err = s.waitForTransactionConfirmation(ctx, txID) @@ -187,7 +635,64 @@ func (s *StacksLocalnet) SetupConnection(ctx context.Context, target chains.Chai return err } - xcallAddress := s.IBCAddresses["xcall"] + return s.initializeConnection(ctx, privateKey, senderAddress) +} + +func (s *StacksLocalnet) isConnectionInitialized(ctx context.Context, contractAddress string) (bool, error) { + parts := strings.Split(contractAddress, ".") + if len(parts) != 2 { + return false, fmt.Errorf("invalid contract ID format: %s", contractAddress) + } + contractAddress = parts[0] + contractName := parts[1] + + result, err := s.client.CallReadOnlyFunction( + ctx, + contractAddress, + contractName, + "get-xcall", + []string{}, + ) + if err != nil { + return false, fmt.Errorf("failed to check connection initialization: %w", err) + } + + byteResult, err := hex.DecodeString(strings.TrimPrefix(*result, "0x")) + if err != nil { + return false, fmt.Errorf("failed to hex decode get-xcall response: %w", err) + } + + clarityValue, err := clarity.DeserializeClarityValue(byteResult) + if err != nil { + return false, fmt.Errorf("failed to deserialize get-xcall response: %w", err) + } + + responseValue, ok := clarityValue.(*clarity.ResponseOk) + if !ok { + return false, fmt.Errorf("unexpected response type: %T", clarityValue) + } + + _, ok = responseValue.Value.(*clarity.OptionNone) + if ok { + return false, nil + } + + return true, nil +} + +func (s *StacksLocalnet) initializeConnection(ctx context.Context, privateKey []byte, senderAddress string) error { + contractAddress := s.IBCAddresses["connection"] + initialized, err := s.isConnectionInitialized(ctx, contractAddress) + if err != nil { + return fmt.Errorf("failed to check connection initialization status: %w", err) + } + + if initialized { + s.log.Info("Connection contract already initialized, skipping initialization") + return nil + } + + xcallAddress := s.IBCAddresses["xcall-proxy"] relayerAddress := s.testconfig.RelayWalletAddress xcallPrincipal, err := clarity.StringToPrincipal(xcallAddress) @@ -203,7 +708,7 @@ func (s *StacksLocalnet) SetupConnection(ctx context.Context, target chains.Chai txCall, err := transaction.MakeContractCall( senderAddress, - connectionContractName, + "centralized-connection", "initialize", args, *s.network, @@ -216,7 +721,7 @@ func (s *StacksLocalnet) SetupConnection(ctx context.Context, target chains.Chai return fmt.Errorf("failed to create contract call transaction: %w", err) } - txID, err = transaction.BroadcastTransaction(txCall, s.network) + txID, err := transaction.BroadcastTransaction(txCall, s.network) if err != nil { return fmt.Errorf("failed to broadcast transaction: %w", err) } @@ -231,22 +736,63 @@ func (s *StacksLocalnet) SetupConnection(ctx context.Context, target chains.Chai return nil } +func shortenContractName(testcase string) string { + // Stacks has a contract name limit defined in SIP-003 + maxLength := 30 + prefix := "x-dapp-" + + cleaned := strings.Map(func(r rune) rune { + if r >= 'a' && r <= 'z' || r >= '0' && r <= '9' || r == '-' { + return r + } + return '-' + }, strings.ToLower(testcase)) + + totalLen := len(prefix) + len(cleaned) + if totalLen > maxLength { + remaining := maxLength - len(prefix) + if remaining > 0 { + cleaned = cleaned[:remaining] + } else { + cleaned = "" + } + } + return prefix + cleaned +} + func (s *StacksLocalnet) DeployXCallMockApp(ctx context.Context, keyName string, connections []chains.XCallConnection) error { if s.testconfig.Environment == "preconfigured" { return nil } testcase := ctx.Value("testcase").(string) - appContractName := "xcall-mock-app-" + testcase + appContractName := shortenContractName(testcase) - codeBody, err := os.ReadFile(s.testconfig.Contracts["dapp"]) + privateKey, senderAddress, err := s.loadPrivateKey(s.testconfig.KeystoreFile, s.testconfig.KeystorePassword) if err != nil { - return fmt.Errorf("failed to read dapp contract code: %w", err) + return fmt.Errorf("failed to load deployer's private key: %w", err) } - privateKey, senderAddress, err := s.loadPrivateKey(s.testconfig.KeystoreFile, s.testconfig.KeystorePassword) + contractAddress := senderAddress + "." + appContractName + + contract, err := s.client.GetContractById(ctx, contractAddress) + if err == nil && contract != nil { + txResp, err := s.client.GetTransactionById(ctx, contract.TxId) + if err == nil { + receipt, err := stacksClient.GetReceipt(txResp) + if err == nil && receipt.Status { + s.log.Info("XCall mock app contract already successfully deployed, skipping deployment", + zap.String("address", contractAddress)) + + s.IBCAddresses[fmt.Sprintf("dapp-%s", testcase)] = contractAddress + return nil + } + } + } + + codeBody, err := os.ReadFile(s.testconfig.Contracts["dapp"]) if err != nil { - return fmt.Errorf("failed to load deployer's private key: %w", err) + return fmt.Errorf("failed to read dapp contract code: %w", err) } tx, err := transaction.MakeContractDeploy( @@ -267,9 +813,10 @@ func (s *StacksLocalnet) DeployXCallMockApp(ctx context.Context, keyName string, return fmt.Errorf("failed to broadcast transaction: %w", err) } - s.log.Info("Deployed xcall mock app contract", zap.String("txID", txID)) + s.log.Info("Deployed xcall mock app contract", + zap.String("txID", txID), + zap.String("contractName", appContractName)) - contractAddress := senderAddress + "." + appContractName s.IBCAddresses[fmt.Sprintf("dapp-%s", testcase)] = contractAddress err = s.waitForTransactionConfirmation(ctx, txID) @@ -277,7 +824,7 @@ func (s *StacksLocalnet) DeployXCallMockApp(ctx context.Context, keyName string, return err } - xcallAddress := s.IBCAddresses["xcall"] + xcallAddress := s.IBCAddresses["xcall-proxy"] xcallPrincipal, err := clarity.StringToPrincipal(xcallAddress) if err != nil { return fmt.Errorf("invalid xcall address: %w", err) @@ -313,61 +860,190 @@ func (s *StacksLocalnet) DeployXCallMockApp(ctx context.Context, keyName string, } for _, connection := range connections { - connPrincipal, err := clarity.StringToPrincipal(s.IBCAddresses[connection.Connection]) + s.log.Debug("Setting up connection", + zap.String("nid", connection.Nid), + zap.String("destination", connection.Destination)) + err := s.addConnection(ctx, senderAddress, appContractName, privateKey, connection) if err != nil { - s.log.Error("Invalid connection address", zap.Error(err), zap.String("address", s.IBCAddresses[connection.Connection])) + s.log.Error("Failed to add connection", + zap.Error(err), + zap.String("nid", connection.Nid)) continue } + } - nidArg, err := clarity.NewStringASCII(connection.Nid) - if err != nil { - s.log.Error("Failed to create nid argument", zap.Error(err)) - continue - } + return nil +} - destArg, err := clarity.NewStringASCII(connection.Destination) - if err != nil { - s.log.Error("Failed to create destination argument", zap.Error(err)) - continue - } +func (s *StacksLocalnet) isConnectionExists(ctx context.Context, contractAddress, contractName, nid, source, destination string) (bool, error) { + sourcesResult, err := s.client.CallReadOnlyFunction( + ctx, + contractAddress, + contractName, + "get-sources", + []string{ + fmt.Sprintf("0x%s", hex.EncodeToString([]byte(nid))), + }, + ) + if err != nil { + return false, fmt.Errorf("failed to check sources: %w", err) + } - args := []clarity.ClarityValue{ - nidArg, - connPrincipal, - destArg, - } + destsResult, err := s.client.CallReadOnlyFunction( + ctx, + contractAddress, + contractName, + "get-destinations", + []string{ + fmt.Sprintf("0x%s", hex.EncodeToString([]byte(nid))), + }, + ) + if err != nil { + return false, fmt.Errorf("failed to check destinations: %w", err) + } - txCall, err := transaction.MakeContractCall( - senderAddress, - appContractName, - "add-connection", - args, - *s.network, - senderAddress, - privateKey, - nil, - nil, - ) - if err != nil { - s.log.Error("Failed to create contract call transaction", zap.Error(err)) - continue + sourceBytes, err := hex.DecodeString(strings.TrimPrefix(*sourcesResult, "0x")) + if err != nil { + return false, fmt.Errorf("failed to decode sources response: %w", err) + } + + sourcesValue, err := clarity.DeserializeClarityValue(sourceBytes) + if err != nil { + return false, fmt.Errorf("failed to deserialize sources: %w", err) + } + + destBytes, err := hex.DecodeString(strings.TrimPrefix(*destsResult, "0x")) + if err != nil { + return false, fmt.Errorf("failed to decode destinations response: %w", err) + } + + destsValue, err := clarity.DeserializeClarityValue(destBytes) + if err != nil { + return false, fmt.Errorf("failed to deserialize destinations: %w", err) + } + + sourcesList, ok := sourcesValue.(*clarity.List) + if !ok { + return false, fmt.Errorf("unexpected sources type: %T", sourcesValue) + } + + destsList, ok := destsValue.(*clarity.List) + if !ok { + return false, fmt.Errorf("unexpected destinations type: %T", destsValue) + } + + sourceExists := false + for _, item := range sourcesList.Values { + if stringVal, ok := item.(*clarity.StringASCII); ok { + if stringVal.Data == source { + sourceExists = true + break + } } + } - txID, err = transaction.BroadcastTransaction(txCall, s.network) - if err != nil { - s.log.Error("Failed to broadcast transaction", zap.Error(err)) - continue + destExists := false + for _, item := range destsList.Values { + if stringVal, ok := item.(*clarity.StringASCII); ok { + if stringVal.Data == destination { + destExists = true + break + } } + } - s.log.Info("Added connection to xcall mock app", zap.String("txID", txID)) + s.log.Debug("Connection check result", + zap.String("nid", nid), + zap.String("source", source), + zap.String("destination", destination), + zap.Bool("sourceExists", sourceExists), + zap.Bool("destExists", destExists)) - err = s.waitForTransactionConfirmation(ctx, txID) - if err != nil { - s.log.Error("Failed to confirm transaction", zap.Error(err)) - continue - } + return sourceExists && destExists, nil +} + +func (s *StacksLocalnet) addConnection(ctx context.Context, senderAddress, appContractName string, privateKey []byte, connection chains.XCallConnection) error { + connAddress := s.IBCAddresses[connection.Connection] + + connArg, err := clarity.NewStringASCII(connAddress) + if err != nil { + return fmt.Errorf("failed to create connection argument: %w", err) + } + + destArg, err := clarity.NewStringASCII(connection.Destination) + if err != nil { + return fmt.Errorf("failed to create destination argument: %w", err) + } + + nidArg, err := clarity.NewStringASCII(connection.Nid) + if err != nil { + return fmt.Errorf("failed to create nid argument: %w", err) } + args := []clarity.ClarityValue{ + nidArg, + connArg, + destArg, + } + + parts := strings.Split(connAddress, ".") + if len(parts) != 2 { + return fmt.Errorf("invalid connection address format: %s", connAddress) + } + contractName := parts[1] + + exists, err := s.isConnectionExists(ctx, senderAddress, appContractName, + connection.Nid, contractName, connection.Destination) + if err != nil { + s.log.Warn("Failed to check existing connection", + zap.Error(err), + zap.String("nid", connection.Nid)) + } + + if exists { + s.log.Info("Connection already exists, skipping", + zap.String("nid", connection.Nid), + zap.String("source", contractName), + zap.String("destination", connection.Destination)) + return nil + } + + txCall, err := transaction.MakeContractCall( + senderAddress, + appContractName, + "add-connection", + args, + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create contract call transaction: %w", err) + } + + txID, err := transaction.BroadcastTransaction(txCall, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast transaction: %w", err) + } + + s.log.Info("Adding new connection to xcall mock app", + zap.String("txID", txID), + zap.String("nid", connection.Nid), + zap.String("source", contractName), + zap.String("destination", connection.Destination)) + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return fmt.Errorf("failed to confirm transaction: %w", err) + } + + s.log.Info("Successfully added new connection", + zap.String("nid", connection.Nid), + zap.String("source", contractName), + zap.String("destination", connection.Destination)) + return nil } @@ -387,17 +1063,135 @@ func (s *StacksLocalnet) SendPacketXCall(ctx context.Context, keyName, _to strin } dataArg := clarity.NewBuffer(data) - rollbackArg := clarity.NewBuffer(rollback) + var rollbackArg clarity.ClarityValue + if len(rollback) > 0 { + rollbackArg = clarity.NewOptionSome(clarity.NewBuffer(rollback)) + } else { + rollbackArg = clarity.NewOptionNone() + } + + implAddr := s.IBCAddresses["xcall-impl"] + implResult, err := s.client.CallReadOnlyFunction( + ctx, + "ST1FTM84RHDZ3AB21MNYKA3XQEFB090HZBB81DSFE", + "xcall-proxy", + "get-current-implementation", + []string{}, + ) + if err != nil { + return nil, fmt.Errorf("failed to get current implementation: %w", err) + } + s.log.Debug("Current implementation", zap.String("result", *implResult)) + + implPrincipal, err := clarity.StringToPrincipal(implAddr) + if err != nil { + return nil, fmt.Errorf("failed to create implementation argument: %w", err) + } args := []clarity.ClarityValue{ toArg, dataArg, rollbackArg, + implPrincipal, + } + + parts := strings.Split(dappAddress, ".") + if len(parts) != 2 { + return nil, fmt.Errorf("invalid dapp address format: %s", dappAddress) + } + contractName := parts[1] + + s.log.Debug("Contract addresses", + zap.String("dapp", dappAddress), + zap.String("impl", s.IBCAddresses["xcall-impl"]), + zap.String("proxy", s.IBCAddresses["xcall-proxy"]), + zap.String("connection", s.IBCAddresses["connection"])) + + if len(parts) != 2 { + return nil, fmt.Errorf("invalid dapp address format: %s", dappAddress) + } + contractAddr := parts[0] + + network := strings.Split(_to, "/")[0] + + s.log.Debug("Checking network sources/destinations", + zap.String("network", network)) + + networkArg, err := clarity.NewStringASCII(network) + if err != nil { + return nil, fmt.Errorf("failed to create network argument: %w", err) + } + + networkBytes, err := networkArg.Serialize() + if err != nil { + return nil, fmt.Errorf("failed to serialize network argument: %w", err) + } + + hexEncodedNetwork := hex.EncodeToString(networkBytes) + + sourcesResult, err := s.client.CallReadOnlyFunction( + ctx, + contractAddr, + contractName, + "get-sources", + []string{hexEncodedNetwork}, + ) + if err != nil { + s.log.Error("Failed to get sources", + zap.Error(err), + zap.String("contractAddr", contractAddr), + zap.String("contractName", contractName), + zap.String("network", network), + zap.String("networkArg", hexEncodedNetwork)) + } else { + sourceBytes, err := hex.DecodeString(strings.TrimPrefix(*sourcesResult, "0x")) + if err != nil { + s.log.Error("Failed to decode sources result", zap.Error(err)) + } else { + sourcesValue, err := clarity.DeserializeClarityValue(sourceBytes) + if err != nil { + s.log.Error("Failed to deserialize sources", zap.Error(err)) + } else { + s.log.Debug("Sources for network", + zap.String("network", network), + zap.Any("sources", sourcesValue)) + } + } + } + + destsResult, err := s.client.CallReadOnlyFunction( + ctx, + contractAddr, + contractName, + "get-destinations", + []string{hexEncodedNetwork}, + ) + if err != nil { + s.log.Error("Failed to get destinations", + zap.Error(err), + zap.String("contractAddr", contractAddr), + zap.String("contractName", contractName), + zap.String("network", network), + zap.String("networkArg", hexEncodedNetwork)) + } else { + destBytes, err := hex.DecodeString(strings.TrimPrefix(*destsResult, "0x")) + if err != nil { + s.log.Error("Failed to decode destinations result", zap.Error(err)) + } else { + destsValue, err := clarity.DeserializeClarityValue(destBytes) + if err != nil { + s.log.Error("Failed to deserialize destinations", zap.Error(err)) + } else { + s.log.Debug("Destinations for network", + zap.String("network", network), + zap.Any("destinations", destsValue)) + } + } } txCall, err := transaction.MakeContractCall( senderAddress, - dappAddress, + contractName, "send-message", args, *s.network, @@ -422,145 +1216,234 @@ func (s *StacksLocalnet) SendPacketXCall(ctx context.Context, keyName, _to strin return nil, err } - // TODO: Extract 'sn' (serial number) from transaction events - // For now, we return the txID in context - ctx = context.WithValue(ctx, "txID", txID) + sn, err := s.extractSnFromTransaction(ctx, txID) + if err != nil { + return nil, fmt.Errorf("failed to extract serial number: %w", err) + } + + ctx = context.WithValue(ctx, snContextKey, sn) return ctx, nil } +func (s *StacksLocalnet) extractSnFromTransaction(ctx context.Context, txID string) (string, error) { + tx, err := s.client.GetTransactionById(ctx, txID) + if err != nil { + return "", fmt.Errorf("failed to get transaction by ID: %w", err) + } + + if confirmed := tx.GetTransactionList200ResponseResultsInner; confirmed != nil { + if contractCall := confirmed.ContractCallTransaction; contractCall != nil { + for _, event := range contractCall.Events { + if event.SmartContractLogTransactionEvent != nil { + contractLog := event.SmartContractLogTransactionEvent.ContractLog + if contractLog.Topic == "print" { + repr := contractLog.Value.Repr + if strings.Contains(repr, "CallMessageSent") { + startIdx := strings.Index(repr, "(sn u") + if startIdx != -1 { + startIdx += 5 // Move past "(sn u" + endIdx := strings.Index(repr[startIdx:], ")") + if endIdx != -1 { + sn := repr[startIdx : startIdx+endIdx] + return sn, nil + } + } + } + } + } + } + } + } + + return "", fmt.Errorf("serial number 'sn' not found in transaction events") +} + func (s *StacksLocalnet) FindCallMessage(ctx context.Context, startHeight uint64, from, to, sn string) (string, string, error) { - foundChan := make(chan struct { + ctx, cancel := context.WithTimeout(ctx, 2*time.Minute) + defer cancel() + + resultChan := make(chan struct { txID string data string }, 1) - callback := func(eventType string, data interface{}) error { - if eventType == stacksClient.CallMessage { - if callMsg, ok := data.(stacksClient.CallMessageEvent); ok { - if callMsg.Sn == sn { - foundChan <- struct { - txID string - data string - }{ - txID: callMsg.ReqID, - data: callMsg.Data, - } + wsURL := s.client.GetWebSocketURL() + eventSystem := events.NewEventSystem(ctx, wsURL, s.log) + + eventSystem.OnEvent(func(event *events.Event) error { + if event.Type != stacksClient.CallMessage { + return nil + } + + if data, ok := event.Data.(events.CallMessageData); ok { + if data.Sn == sn { + select { + case resultChan <- struct { + txID string + data string + }{ + txID: data.ReqID, + data: data.Data, + }: + case <-ctx.Done(): } } } return nil - } + }) - err := s.client.SubscribeToEvents(ctx, []string{stacksClient.CallMessage}, callback) - if err != nil { - return "", "", fmt.Errorf("failed to subscribe to events: %w", err) + if err := eventSystem.Start(); err != nil { + return "", "", fmt.Errorf("failed to start event system: %w", err) } + defer eventSystem.Stop() select { - case found := <-foundChan: - return found.txID, found.data, nil - case <-time.After(2 * time.Minute): - return "", "", fmt.Errorf("find call message timed out") + case result := <-resultChan: + return result.txID, result.data, nil case <-ctx.Done(): + if ctx.Err() == context.DeadlineExceeded { + return "", "", fmt.Errorf("find call message timed out") + } return "", "", ctx.Err() } } func (s *StacksLocalnet) FindCallResponse(ctx context.Context, startHeight uint64, sn string) (string, error) { - foundChan := make(chan string, 1) + ctx, cancel := context.WithTimeout(ctx, 2*time.Minute) + defer cancel() - callback := func(eventType string, data interface{}) error { - if eventType == stacksClient.CallMessage { - if callMsg, ok := data.(stacksClient.CallMessageEvent); ok { - if callMsg.Sn == sn { - foundChan <- callMsg.ReqID + resultChan := make(chan string, 1) + + wsURL := s.client.GetWebSocketURL() + eventSystem := events.NewEventSystem(ctx, wsURL, s.log) + + eventSystem.OnEvent(func(event *events.Event) error { + if event.Type != stacksClient.CallMessage { + return nil + } + + if data, ok := event.Data.(events.CallMessageData); ok { + if data.Sn == sn { + select { + case resultChan <- data.ReqID: + case <-ctx.Done(): } } } return nil - } + }) - err := s.client.SubscribeToEvents(ctx, []string{stacksClient.CallMessage}, callback) - if err != nil { - return "", fmt.Errorf("failed to subscribe to events: %w", err) + if err := eventSystem.Start(); err != nil { + return "", fmt.Errorf("failed to start event system: %w", err) } + defer eventSystem.Stop() select { - case txID := <-foundChan: + case txID := <-resultChan: return txID, nil - case <-time.After(2 * time.Minute): - return "", fmt.Errorf("find call response timed out") case <-ctx.Done(): + if ctx.Err() == context.DeadlineExceeded { + return "", fmt.Errorf("find call response timed out") + } return "", ctx.Err() } } func (s *StacksLocalnet) FindRollbackExecutedMessage(ctx context.Context, startHeight uint64, sn string) (string, error) { - foundChan := make(chan string, 1) + ctx, cancel := context.WithTimeout(ctx, 2*time.Minute) + defer cancel() + + resultChan := make(chan string, 1) - callback := func(eventType string, data interface{}) error { - if eventType == stacksClient.RollbackMessage { - if rollbackMsg, ok := data.(stacksClient.RollbackMessageEvent); ok { - if rollbackMsg.Sn == sn { - foundChan <- rollbackMsg.Sn + wsURL := s.client.GetWebSocketURL() + eventSystem := events.NewEventSystem(ctx, wsURL, s.log) + + eventSystem.OnEvent(func(event *events.Event) error { + if event.Type != stacksClient.RollbackMessage { + return nil + } + + if data, ok := event.Data.(events.RollbackMessageData); ok { + if data.Sn == sn { + select { + case resultChan <- data.Sn: + case <-ctx.Done(): } } } return nil - } + }) - err := s.client.SubscribeToEvents(ctx, []string{stacksClient.RollbackMessage}, callback) - if err != nil { - return "", fmt.Errorf("failed to subscribe to events: %w", err) + if err := eventSystem.Start(); err != nil { + return "", fmt.Errorf("failed to start event system: %w", err) } + defer eventSystem.Stop() select { - case txID := <-foundChan: + case txID := <-resultChan: return txID, nil - case <-time.After(2 * time.Minute): - return "", fmt.Errorf("find rollback message timed out") case <-ctx.Done(): + if ctx.Err() == context.DeadlineExceeded { + return "", fmt.Errorf("find rollback message timed out") + } return "", ctx.Err() } } func (s *StacksLocalnet) FindTargetXCallMessage(ctx context.Context, target chains.Chain, height uint64, to string) (*chains.XCallResponse, error) { - foundChan := make(chan *chains.XCallResponse, 1) - - callback := func(eventType string, data interface{}) error { - if eventType == stacksClient.EmitMessage { - if emitMsg, ok := data.(stacksClient.EmitMessageEvent); ok { - if emitMsg.TargetNetwork == to { - foundChan <- &chains.XCallResponse{ - SerialNo: emitMsg.Sn, - Data: emitMsg.Msg, - // RequestID isn't in EmitMessageEvent, will be empty + ctx, cancel := context.WithTimeout(ctx, 2*time.Minute) + defer cancel() + + resultChan := make(chan *chains.XCallResponse, 1) + + wsURL := s.client.GetWebSocketURL() + eventSystem := events.NewEventSystem(ctx, wsURL, s.log) + + eventSystem.OnEvent(func(event *events.Event) error { + var response *chains.XCallResponse + + switch event.Type { + case stacksClient.EmitMessage: + if data, ok := event.Data.(events.EmitMessageData); ok { + if data.TargetNetwork == to { + response = &chains.XCallResponse{ + SerialNo: data.Sn, + Data: data.Msg, } } } - } else if eventType == stacksClient.CallMessage { - if callMsg, ok := data.(stacksClient.CallMessageEvent); ok { - foundChan <- &chains.XCallResponse{ - SerialNo: callMsg.Sn, - RequestID: callMsg.ReqID, - Data: callMsg.Data, + + case stacksClient.CallMessage: + if data, ok := event.Data.(events.CallMessageData); ok { + response = &chains.XCallResponse{ + SerialNo: data.Sn, + RequestID: data.ReqID, + Data: data.Data, } } } + + if response != nil { + select { + case resultChan <- response: + case <-ctx.Done(): + } + } return nil - } + }) - err := s.client.SubscribeToEvents(ctx, []string{stacksClient.EmitMessage, stacksClient.CallMessage}, callback) - if err != nil { - return nil, fmt.Errorf("failed to subscribe to events: %w", err) + if err := eventSystem.Start(); err != nil { + return nil, fmt.Errorf("failed to start event system: %w", err) } + defer eventSystem.Stop() select { - case response := <-foundChan: + case response := <-resultChan: return response, nil - case <-time.After(2 * time.Minute): - return nil, fmt.Errorf("find target message timed out") case <-ctx.Done(): + if ctx.Err() == context.DeadlineExceeded { + return nil, fmt.Errorf("find target message timed out") + } return nil, ctx.Err() } } @@ -610,12 +1493,27 @@ func (s *StacksLocalnet) XCall(ctx context.Context, targetChain chains.Chain, ke return nil, err } - return s.FindTargetXCallMessage(ctx, targetChain, height, strings.Split(_to, "/")[1]) + sn := ctx.Value(snContextKey).(string) + testcase := ctx.Value("testcase").(string) + dappKey := fmt.Sprintf("dapp-%s", testcase) + from := s.cfg.ChainID + "/" + s.GetContractAddress(dappKey) + toAddress := strings.Split(_to, "/")[1] + + reqID, destData, err := targetChain.FindCallMessage(ctx, height, from, toAddress, sn) + if err != nil { + return nil, err + } + + return &chains.XCallResponse{ + SerialNo: sn, + RequestID: reqID, + Data: destData, + }, nil } func (s *StacksLocalnet) waitForTransactionConfirmation(ctx context.Context, txID string) error { - timeout := time.After(2 * time.Minute) - ticker := time.NewTicker(2 * time.Second) + timeout := time.After(MAX_WAIT_TIME) + ticker := time.NewTicker(BLOCK_TIME) defer ticker.Stop() for { @@ -642,7 +1540,7 @@ func (s *StacksLocalnet) waitForTransactionConfirmation(ctx context.Context, txI s.log.Debug("Transaction not yet confirmed", zap.String("txID", txID)) case <-timeout: - return fmt.Errorf("transaction confirmation timed out after 2 minutes") + return fmt.Errorf("transaction confirmation timed out after %v seconds", MAX_WAIT_TIME) case <-ctx.Done(): return ctx.Err() } diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 0c67b5d9..ca0f2607 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -2,6 +2,7 @@ package e2e_test import ( "context" + "os" "testing" "github.com/icon-project/centralized-relay/test/e2e/tests" @@ -20,6 +21,8 @@ type E2ETest struct { func (s *E2ETest) TestE2E_all() { // go panicOnTimeout(10 * time.Hour) // custom timeout + os.Setenv("AWS_ENDPOINT_URL", "http://localhost:8088/") + t := s.T() testcase := "xcall" ctx := context.WithValue(context.TODO(), "testcase", testcase) diff --git a/test/sample-config.yaml b/test/sample-config.yaml index 57d47bff..f7169a56 100644 --- a/test/sample-config.yaml +++ b/test/sample-config.yaml @@ -3,13 +3,16 @@ chains: - name: stacks version: "3" environment: remote - rpc_uri: https://tt.net.solidwallet.io/stacks-api + rpc_uri: https://api.testnet.hiro.so contracts_path: "$BASE_PATH/artifacts/stacks" config_path: "$BASE_PATH/test/chains/stacks/data" + keystore_file: /Users/cyrusvorwald/.centralized-relay/keystore/stacks_testnet/ST1FTM84RHDZ3AB21MNYKA3XQEFB090HZBB81DSFE + keystore_password: changeme + relay_wallet: ST1FTM84RHDZ3AB21MNYKA3XQEFB090HZBB81DSFE chain_config: type: stacks name: stacks - chain_id: stacks.local + chain_id: stacks_testnet image: repository: blockstack/stacks-blockchain version: latest @@ -23,43 +26,52 @@ chains: trusting_period: 508h no_host_mount: false contracts: - xcall: "$BASE_PATH/artifacts/stacks/xcall.clar" - connection: "$BASE_PATH/artifacts/stacks/centralized_connection.clar" - dapp: "$BASE_PATH/artifacts/stacks/mock_dapp_multi.clar" + xcall-proxy: "$BASE_PATH/artifacts/stacks/contracts/xcall/xcall-proxy.clar" + xcall-abi: "$BASE_PATH/relayer/chains/stacks/abi/xcall-proxy-abi.json" + connection: "$BASE_PATH/artifacts/stacks/contracts/connections/centralized-connection.clar" + dapp: "$BASE_PATH/artifacts/stacks/tests/mocks/mock-dapp.clar" + common-trait: "$BASE_PATH/artifacts/stacks/contracts/xcall/xcall-common-trait.clar" + receiver-trait: "$BASE_PATH/artifacts/stacks/contracts/xcall/xcall-receiver-trait.clar" + impl-trait: "$BASE_PATH/artifacts/stacks/contracts/xcall/xcall-impl-trait.clar" + proxy-trait: "$BASE_PATH/artifacts/stacks/contracts/xcall/xcall-proxy-trait.clar" + util: "$BASE_PATH/artifacts/stacks/contracts/util.clar" + rlp-encode: "$BASE_PATH/artifacts/stacks/lib/rlp/rlp-encode.clar" + rlp-decode: "$BASE_PATH/artifacts/stacks/lib/rlp/rlp-decode.clar" + xcall-impl: "$BASE_PATH/artifacts/stacks/contracts/xcall/xcall-impl.clar" - - name: stellar - version: "3" - environment: remote - rpc_uri: https://tt.net.solidwallet.io/stellar-rpc/rpc - websocket_uri: https://tt.net.solidwallet.io/stellar-rpc - relay_wallet : GCX3TODZ2KEHYGD6HOQDRZVOUWNSQWP6OLYBIQ3XNPFKQ47G42H7WCGA - keystore_password: "Standalone Network ; February 2017" - keystore_file: SDFOICJI3PHUWHFARICCQS2A3W6BNGQVWQ6JDNYPH62VW6GWDBHDH7GE - contracts_path: "$BASE_PATH/artifacts/stellar" - chain_config: - type: stellar - name: stellar - chain_id: stellar.local - image: - repository: esteblock/soroban-preview - version: 21.0.1 - uid_gid: "" - bin: soroban - bech32_prefix: 0x - denom: xlm - coin_type: 118 - gas_prices: 0.001xlm - gas_adjustment: 1.3 - trusting_period: 508h - no_host_mount: false - contracts: - xcall: "$BASE_PATH/artifacts/stellar/xcall.wasm" - connection: "$BASE_PATH/artifacts/stellar/centralized_connection.wasm" - dapp: "$BASE_PATH/artifacts/stellar/mock_dapp_multi.wasm" + # - name: stellar + # version: "3" + # environment: remote + # rpc_uri: https://tt.net.solidwallet.io/stellar-rpc/rpc + # websocket_uri: https://tt.net.solidwallet.io/stellar-rpc + # relay_wallet : GCX3TODZ2KEHYGD6HOQDRZVOUWNSQWP6OLYBIQ3XNPFKQ47G42H7WCGA + # keystore_password: "Standalone Network ; February 2017" + # keystore_file: SDFOICJI3PHUWHFARICCQS2A3W6BNGQVWQ6JDNYPH62VW6GWDBHDH7GE + # contracts_path: "$BASE_PATH/artifacts/stellar" + # chain_config: + # type: stellar + # name: stellar + # chain_id: stellar.local + # image: + # repository: esteblock/soroban-preview + # version: 21.0.1 + # uid_gid: "" + # bin: soroban + # bech32_prefix: 0x + # denom: xlm + # coin_type: 118 + # gas_prices: 0.001xlm + # gas_adjustment: 1.3 + # trusting_period: 508h + # no_host_mount: false + # contracts: + # xcall: "$BASE_PATH/artifacts/stellar/xcall.wasm" + # connection: "$BASE_PATH/artifacts/stellar/centralized_connection.wasm" + # dapp: "$BASE_PATH/artifacts/stellar/mock_dapp_multi.wasm" - name: icon version: "3" environment: remote - rpc_uri: https://tt.net.solidwallet.io/jvm-rpc/api/v3/ + rpc_uri: https://lisbon.net.solidwallet.io/api/v3 keystore_file: godwallet.json keystore_password: gochain relay_wallet : hxb6b5791be0b5ef67063b3c10b840fb81514db2fd @@ -70,7 +82,7 @@ chains: chain_config: type: icon name: icon - chain_id: icon.local + chain_id: test bech32_prefix: hx bin: "/goloop/bin/goloop" image: @@ -81,124 +93,124 @@ chains: xcall: "$BASE_PATH/artifacts/icon/xcall-latest.jar" connection: "$BASE_PATH/artifacts/icon/centralized-connection-latest.jar" dapp: "$BASE_PATH/artifacts/icon/dapp-multi-protocol-latest.jar" - - name: foundry - version: "3" - environment: remote - rpc_uri: https://tt.net.solidwallet.io/hardhat-rpc - websocket_uri: wss://tt.net.solidwallet.io/hardhat-rpc - relay_wallet : 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 - keystore_password: ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 - chain_config: - type: evm - name: foundry - chain_id: emv.local - image: - repository: ghcr.io/foundry-rs/foundry - version: latest - uid_gid: "" - bin: cast - bech32_prefix: 0x - denom: gwei - coin_type: 118 - gas_prices: 0.001gwei - gas_adjustment: 1.3 - trusting_period: 508h - no_host_mount: false - contracts: - xcall: "$BASE_PATH/artifacts/evm/CallService" - connection: "$BASE_PATH/artifacts/evm/CentralizedConnection" - dapp: "$BASE_PATH/artifacts/evm/MultiProtocolSampleDapp" - - name: sui - version: "3" - environment: remote - rpc_uri: https://tt.net.solidwallet.io:443/sui-rpc - websocket_uri: ws://tt.net.solidwallet.io:443 - relay_wallet : 0xe847098636459aa93f4da105414edca4790619b291ffdac49419f5adc19c4d21 - keystore_password: ALWS4mKTtggWc8gH+a5bFLFQ0AeNbZpUdDI//3OpAVys - contracts_path: "$BASE_PATH/artifacts/sui/xcall/contracts/sui" - config_path: "$BASE_PATH/test/chains/sui/data" - chain_config: - type: sui - name: sui - chain_id: sui - image: - repository: mysten/sui-tools-w-git - version: devnet - uid_gid: "" - bin: sui - bech32_prefix: 0x - denom: arch - coin_type: 118 - gas_prices: 0.001sui - gas_adjustment: 1.3 - trusting_period: 508h - no_host_mount: false - contracts: - xcall: "$BASE_PATH/artifacts/sui/xcall/contracts/sui/xcall" - sui_rlp: "$BASE_PATH/artifacts/sui/xcall/contracts/sui/libs/sui_rlp" - dapp: "$BASE_PATH/artifacts/sui/xcall/contracts/sui/mock_dapp" + # - name: foundry + # version: "3" + # environment: remote + # rpc_uri: https://tt.net.solidwallet.io/hardhat-rpc + # websocket_uri: wss://tt.net.solidwallet.io/hardhat-rpc + # relay_wallet : 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 + # keystore_password: ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 + # chain_config: + # type: evm + # name: foundry + # chain_id: emv.local + # image: + # repository: ghcr.io/foundry-rs/foundry + # version: latest + # uid_gid: "" + # bin: cast + # bech32_prefix: 0x + # denom: gwei + # coin_type: 118 + # gas_prices: 0.001gwei + # gas_adjustment: 1.3 + # trusting_period: 508h + # no_host_mount: false + # contracts: + # xcall: "$BASE_PATH/artifacts/evm/CallService" + # connection: "$BASE_PATH/artifacts/evm/CentralizedConnection" + # dapp: "$BASE_PATH/artifacts/evm/MultiProtocolSampleDapp" + # - name: sui + # version: "3" + # environment: remote + # rpc_uri: https://tt.net.solidwallet.io:443/sui-rpc + # websocket_uri: ws://tt.net.solidwallet.io:443 + # relay_wallet : 0xe847098636459aa93f4da105414edca4790619b291ffdac49419f5adc19c4d21 + # keystore_password: ALWS4mKTtggWc8gH+a5bFLFQ0AeNbZpUdDI//3OpAVys + # contracts_path: "$BASE_PATH/artifacts/sui/xcall/contracts/sui" + # config_path: "$BASE_PATH/test/chains/sui/data" + # chain_config: + # type: sui + # name: sui + # chain_id: sui + # image: + # repository: mysten/sui-tools-w-git + # version: devnet + # uid_gid: "" + # bin: sui + # bech32_prefix: 0x + # denom: arch + # coin_type: 118 + # gas_prices: 0.001sui + # gas_adjustment: 1.3 + # trusting_period: 508h + # no_host_mount: false + # contracts: + # xcall: "$BASE_PATH/artifacts/sui/xcall/contracts/sui/xcall" + # sui_rlp: "$BASE_PATH/artifacts/sui/xcall/contracts/sui/libs/sui_rlp" + # dapp: "$BASE_PATH/artifacts/sui/xcall/contracts/sui/mock_dapp" - - name: archway - version: "3" - environment: remote - contracts_path: "$BASE_PATH/artifacts/archway" - config_path: "$BASE_PATH/test/chains/cosmos/data" - rpc_uri: https://tt.net.solidwallet.io:443/archway-rpc - relay_wallet: archway1x394ype3x8nt9wz0j78m8c8kcezpslrcnvs6ef - grpc_uri: tt.net.solidwallet.io:443 - # for testing with local chains with self signed certs - # cert_path: /Users/home/centralized-relay/rootCA/ - keystore_file: relayer - chain_config: - type: wasm - name: archway - chain_id: localnet-1 - bin: archwayd - image: - repository: ghcr.io/archway-network/archwayd-dev - version: v6.0.1-amd64 - uid_gid: "" - bech32_prefix: archway - denom: arch - coin_type: 118 - gas_prices: 0.000arch - gas_adjustment: 1.3 - trusting_period: 508h - no_host_mount: false - nid: localnet-1 - contracts: - xcall: "$BASE_PATH/artifacts/archway/cw_xcall_latest.wasm" - connection: "$BASE_PATH/artifacts/archway/cw_centralized_connection.wasm" - dapp: "$BASE_PATH/artifacts/archway/cw_mock_dapp_multi.wasm" + # - name: archway + # version: "3" + # environment: remote + # contracts_path: "$BASE_PATH/artifacts/archway" + # config_path: "$BASE_PATH/test/chains/cosmos/data" + # rpc_uri: https://tt.net.solidwallet.io:443/archway-rpc + # relay_wallet: archway1x394ype3x8nt9wz0j78m8c8kcezpslrcnvs6ef + # grpc_uri: tt.net.solidwallet.io:443 + # # for testing with local chains with self signed certs + # # cert_path: /Users/home/centralized-relay/rootCA/ + # keystore_file: relayer + # chain_config: + # type: wasm + # name: archway + # chain_id: localnet-1 + # bin: archwayd + # image: + # repository: ghcr.io/archway-network/archwayd-dev + # version: v6.0.1-amd64 + # uid_gid: "" + # bech32_prefix: archway + # denom: arch + # coin_type: 118 + # gas_prices: 0.000arch + # gas_adjustment: 1.3 + # trusting_period: 508h + # no_host_mount: false + # nid: localnet-1 + # contracts: + # xcall: "$BASE_PATH/artifacts/archway/cw_xcall_latest.wasm" + # connection: "$BASE_PATH/artifacts/archway/cw_centralized_connection.wasm" + # dapp: "$BASE_PATH/artifacts/archway/cw_mock_dapp_multi.wasm" - - name: solana - version: "3" - environment: remote - rpc_uri: https://solana-rpc.venture23.xyz - relay_wallet : 2V6UQFu9BZL6eKj2EFjtbCvtS1poXJNyJoWogk6gbGsS - keystore_file: id.json - contracts_path: "$BASE_PATH/artifacts/solana/xcall/contracts/solana" - config_path: "$BASE_PATH/test/chains/solana/data/" - chain_config: - type: solana - name: solana - chain_id: solana.local - image: - repository: backpackapp/build - version: v0.30.1 - uid_gid: "" - bin: anchor - bech32_prefix: 0x - denom: sol - coin_type: 118 - gas_prices: 0.001sol - gas_adjustment: 1.3 - trusting_period: 508h - no_host_mount: false - contracts: - xcall: "$BASE_PATH/artifacts/solana/xcall/contracts/solana/programs/xcall" - sui_rlp: "$BASE_PATH/artifacts/solana/xcall/contracts/solana/centralized-connection" - dapp: "$BASE_PATH/artifacts/solana/xcall/contracts/solana/mock-dapp-multi" + # - name: solana + # version: "3" + # environment: remote + # rpc_uri: https://solana-rpc.venture23.xyz + # relay_wallet : 2V6UQFu9BZL6eKj2EFjtbCvtS1poXJNyJoWogk6gbGsS + # keystore_file: id.json + # contracts_path: "$BASE_PATH/artifacts/solana/xcall/contracts/solana" + # config_path: "$BASE_PATH/test/chains/solana/data/" + # chain_config: + # type: solana + # name: solana + # chain_id: solana.local + # image: + # repository: backpackapp/build + # version: v0.30.1 + # uid_gid: "" + # bin: anchor + # bech32_prefix: 0x + # denom: sol + # coin_type: 118 + # gas_prices: 0.001sol + # gas_adjustment: 1.3 + # trusting_period: 508h + # no_host_mount: false + # contracts: + # xcall: "$BASE_PATH/artifacts/solana/xcall/contracts/solana/programs/xcall" + # sui_rlp: "$BASE_PATH/artifacts/solana/xcall/contracts/solana/centralized-connection" + # dapp: "$BASE_PATH/artifacts/solana/xcall/contracts/solana/mock-dapp-multi" relayer: image: centralized-relay tag: stellar-dev-amd From fe6536367e4e801564b99bcd090a8d10f9b23f0e Mon Sep 17 00:00:00 2001 From: CyrusVorwald <90732384+CyrusVorwald@users.noreply.github.com> Date: Sun, 10 Nov 2024 23:54:58 -0500 Subject: [PATCH 7/9] fix: relay nid and abi --- .../stacks/abi/centralized-connection.abi | 457 ----------- .../chains/stacks/abi/xcall-proxy-abi.json | 733 ------------------ relayer/chains/stacks/client.go | 16 +- relayer/chains/stacks/client_test.go | 22 +- relayer/chains/stacks/events/listener.go | 16 +- relayer/chains/stacks/provider.go | 19 +- test/chains/stacks/remotenet.go | 110 +-- .../centralized/centralized_relayer.go | 1 + test/sample-config.yaml | 3 +- 9 files changed, 51 insertions(+), 1326 deletions(-) delete mode 100644 relayer/chains/stacks/abi/centralized-connection.abi delete mode 100644 relayer/chains/stacks/abi/xcall-proxy-abi.json diff --git a/relayer/chains/stacks/abi/centralized-connection.abi b/relayer/chains/stacks/abi/centralized-connection.abi deleted file mode 100644 index b97898ae..00000000 --- a/relayer/chains/stacks/abi/centralized-connection.abi +++ /dev/null @@ -1,457 +0,0 @@ -{ - "maps": [ - { - "key": { - "tuple": [ - { - "name": "network-id", - "type": { - "string-ascii": { - "length": 128 - } - } - } - ] - }, - "name": "message-fees", - "value": "uint128" - }, - { - "key": { - "tuple": [ - { - "name": "conn-sn", - "type": "int128" - }, - { - "name": "network-id", - "type": { - "string-ascii": { - "length": 128 - } - } - } - ] - }, - "name": "receipts", - "value": "bool" - }, - { - "key": { - "tuple": [ - { - "name": "network-id", - "type": { - "string-ascii": { - "length": 128 - } - } - } - ] - }, - "name": "response-fees", - "value": "uint128" - } - ], - "epoch": "Epoch30", - "functions": [ - { - "args": [ - { - "name": "to", - "type": { - "string-ascii": { - "length": 128 - } - } - }, - { - "name": "sn", - "type": "int128" - }, - { - "name": "msg", - "type": { - "buffer": { - "length": 2048 - } - } - } - ], - "name": "emit-message-event", - "access": "private", - "outputs": { - "type": { - "tuple": [ - { - "name": "event", - "type": { - "string-ascii": { - "length": 7 - } - } - }, - { - "name": "msg", - "type": { - "buffer": { - "length": 2048 - } - } - }, - { - "name": "sn", - "type": "int128" - }, - { - "name": "to", - "type": { - "string-ascii": { - "length": 128 - } - } - } - ] - } - } - }, - { - "args": [], - "name": "is-admin", - "access": "private", - "outputs": { - "type": "bool" - } - }, - { - "args": [], - "name": "is-xcall", - "access": "private", - "outputs": { - "type": "bool" - } - }, - { - "args": [], - "name": "claim-fees", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "bool", - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "xcall-contract", - "type": "principal" - }, - { - "name": "admin-address", - "type": "principal" - } - ], - "name": "initialize", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "bool", - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "src-network-id", - "type": { - "string-ascii": { - "length": 128 - } - } - }, - { - "name": "conn-sn-in", - "type": "int128" - }, - { - "name": "msg", - "type": { - "buffer": { - "length": 2048 - } - } - }, - { - "name": "implementation", - "type": "trait_reference" - } - ], - "name": "recv-message", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "bool", - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "to", - "type": { - "string-ascii": { - "length": 128 - } - } - }, - { - "name": "svc", - "type": { - "string-ascii": { - "length": 128 - } - } - }, - { - "name": "sn", - "type": "int128" - }, - { - "name": "msg", - "type": { - "buffer": { - "length": 2048 - } - } - }, - { - "name": "implementation", - "type": "trait_reference" - } - ], - "name": "send-message", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "int128", - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "new-admin", - "type": "principal" - } - ], - "name": "set-admin", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "bool", - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "network-id", - "type": { - "string-ascii": { - "length": 128 - } - } - }, - { - "name": "message-fee", - "type": "uint128" - }, - { - "name": "response-fee", - "type": "uint128" - } - ], - "name": "set-fee", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "bool", - "error": "uint128" - } - } - } - }, - { - "args": [], - "name": "get-admin", - "access": "read_only", - "outputs": { - "type": { - "response": { - "ok": "principal", - "error": "none" - } - } - } - }, - { - "args": [], - "name": "get-conn-sn", - "access": "read_only", - "outputs": { - "type": { - "response": { - "ok": "int128", - "error": "none" - } - } - } - }, - { - "args": [ - { - "name": "to", - "type": { - "string-ascii": { - "length": 128 - } - } - }, - { - "name": "response", - "type": "bool" - } - ], - "name": "get-fee", - "access": "read_only", - "outputs": { - "type": { - "response": { - "ok": "uint128", - "error": "none" - } - } - } - }, - { - "args": [ - { - "name": "src-network", - "type": { - "string-ascii": { - "length": 128 - } - } - }, - { - "name": "conn-sn-in", - "type": "int128" - } - ], - "name": "get-receipt", - "access": "read_only", - "outputs": { - "type": { - "response": { - "ok": "bool", - "error": "none" - } - } - } - }, - { - "args": [], - "name": "get-xcall", - "access": "read_only", - "outputs": { - "type": { - "response": { - "ok": { - "optional": "principal" - }, - "error": "none" - } - } - } - } - ], - "variables": [ - { - "name": "ERR_DUPLICATE_MESSAGE", - "type": { - "response": { - "ok": "none", - "error": "uint128" - } - }, - "access": "constant" - }, - { - "name": "ERR_INVALID_FEE", - "type": { - "response": { - "ok": "none", - "error": "uint128" - } - }, - "access": "constant" - }, - { - "name": "ERR_UNAUTHORIZED", - "type": { - "response": { - "ok": "none", - "error": "uint128" - } - }, - "access": "constant" - }, - { - "name": "ERR_XCALL_NOT_SET", - "type": { - "response": { - "ok": "none", - "error": "uint128" - } - }, - "access": "constant" - }, - { - "name": "admin", - "type": "principal", - "access": "variable" - }, - { - "name": "conn-sn", - "type": "int128", - "access": "variable" - }, - { - "name": "xcall", - "type": { - "optional": "principal" - }, - "access": "variable" - } - ], - "clarity_version": "Clarity2", - "fungible_tokens": [], - "non_fungible_tokens": [] - } \ No newline at end of file diff --git a/relayer/chains/stacks/abi/xcall-proxy-abi.json b/relayer/chains/stacks/abi/xcall-proxy-abi.json deleted file mode 100644 index 4da39712..00000000 --- a/relayer/chains/stacks/abi/xcall-proxy-abi.json +++ /dev/null @@ -1,733 +0,0 @@ -{ - "maps": [ - { - "key": { - "string-ascii": { - "length": 16 - } - }, - "name": "data-storage", - "value": { - "buffer": { - "length": 2048 - } - } - } - ], - "epoch": "Epoch30", - "functions": [ - { - "args": [ - { - "name": "req-id", - "type": "uint128" - }, - { - "name": "data", - "type": { - "buffer": { - "length": 2048 - } - } - }, - { - "name": "receiver", - "type": "trait_reference" - }, - { - "name": "common", - "type": "trait_reference" - }, - { - "name": "implementation", - "type": "trait_reference" - } - ], - "name": "execute-call", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "bool", - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "sn", - "type": "uint128" - }, - { - "name": "receiver", - "type": "trait_reference" - }, - { - "name": "common", - "type": "trait_reference" - }, - { - "name": "implementation", - "type": "trait_reference" - } - ], - "name": "execute-rollback", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "bool", - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "net", - "type": { - "string-ascii": { - "length": 128 - } - } - }, - { - "name": "rollback", - "type": "bool" - }, - { - "name": "sources", - "type": { - "optional": { - "list": { - "type": { - "string-ascii": { - "length": 128 - } - }, - "length": 10 - } - } - } - }, - { - "name": "implementation", - "type": "trait_reference" - } - ], - "name": "get-fee", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "uint128", - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "implementation", - "type": "trait_reference" - } - ], - "name": "get-network-address", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": { - "string-ascii": { - "length": 128 - } - }, - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "implementation", - "type": "trait_reference" - } - ], - "name": "get-network-id", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": { - "string-ascii": { - "length": 128 - } - }, - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "implementation", - "type": "trait_reference" - } - ], - "name": "get-protocol-fee", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "uint128", - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "sn", - "type": "uint128" - }, - { - "name": "implementation", - "type": "trait_reference" - } - ], - "name": "handle-error", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "bool", - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "source-network", - "type": { - "string-ascii": { - "length": 128 - } - } - }, - { - "name": "message", - "type": { - "buffer": { - "length": 2048 - } - } - }, - { - "name": "implementation", - "type": "trait_reference" - } - ], - "name": "handle-message", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "bool", - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "to", - "type": { - "string-ascii": { - "length": 128 - } - } - }, - { - "name": "data", - "type": { - "buffer": { - "length": 2048 - } - } - }, - { - "name": "implementation", - "type": "trait_reference" - } - ], - "name": "send-call", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "uint128", - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "to", - "type": { - "string-ascii": { - "length": 128 - } - } - }, - { - "name": "data", - "type": { - "buffer": { - "length": 2048 - } - } - }, - { - "name": "rollback", - "type": { - "optional": { - "buffer": { - "length": 1024 - } - } - } - }, - { - "name": "sources", - "type": { - "optional": { - "list": { - "type": { - "string-ascii": { - "length": 128 - } - }, - "length": 10 - } - } - } - }, - { - "name": "destinations", - "type": { - "optional": { - "list": { - "type": { - "string-ascii": { - "length": 128 - } - }, - "length": 10 - } - } - } - }, - { - "name": "implementation", - "type": "trait_reference" - } - ], - "name": "send-call-message", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "uint128", - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "new-admin", - "type": "principal" - }, - { - "name": "implementation", - "type": "trait_reference" - } - ], - "name": "set-admin", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "bool", - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "new-owner", - "type": "principal" - } - ], - "name": "set-contract-owner", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "bool", - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "key", - "type": { - "string-ascii": { - "length": 16 - } - } - }, - { - "name": "value", - "type": { - "buffer": { - "length": 2048 - } - } - } - ], - "name": "set-data", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "bool", - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "nid", - "type": { - "string-ascii": { - "length": 128 - } - } - }, - { - "name": "connection", - "type": { - "string-ascii": { - "length": 128 - } - } - }, - { - "name": "implementation", - "type": "trait_reference" - } - ], - "name": "set-default-connection", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "bool", - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "fee", - "type": "uint128" - }, - { - "name": "implementation", - "type": "trait_reference" - } - ], - "name": "set-protocol-fee", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "bool", - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "handler", - "type": "principal" - }, - { - "name": "implementation", - "type": "trait_reference" - } - ], - "name": "set-protocol-fee-handler", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "bool", - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "nid", - "type": { - "string-ascii": { - "length": 128 - } - } - }, - { - "name": "protocols", - "type": { - "list": { - "type": { - "string-ascii": { - "length": 128 - } - }, - "length": 10 - } - } - }, - { - "name": "implementation", - "type": "trait_reference" - } - ], - "name": "set-trusted-protocols", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "bool", - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "new-implementation", - "type": "trait_reference" - }, - { - "name": "new-proxy", - "type": { - "optional": "principal" - } - } - ], - "name": "upgrade", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "bool", - "error": "uint128" - } - } - } - }, - { - "args": [ - { - "name": "sn", - "type": "uint128" - }, - { - "name": "implementation", - "type": "trait_reference" - } - ], - "name": "verify-success", - "access": "public", - "outputs": { - "type": { - "response": { - "ok": "bool", - "error": "uint128" - } - } - } - }, - { - "args": [], - "name": "get-contract-owner", - "access": "read_only", - "outputs": { - "type": "principal" - } - }, - { - "args": [], - "name": "get-current-implementation", - "access": "read_only", - "outputs": { - "type": { - "response": { - "ok": "principal", - "error": "none" - } - } - } - }, - { - "args": [], - "name": "get-current-proxy", - "access": "read_only", - "outputs": { - "type": { - "response": { - "ok": { - "optional": "principal" - }, - "error": "none" - } - } - } - }, - { - "args": [ - { - "name": "key", - "type": { - "string-ascii": { - "length": 16 - } - } - } - ], - "name": "get-data", - "access": "read_only", - "outputs": { - "type": { - "optional": { - "buffer": { - "length": 2048 - } - } - } - } - }, - { - "args": [ - { - "name": "who", - "type": "principal" - } - ], - "name": "is-contract-owner", - "access": "read_only", - "outputs": { - "type": "bool" - } - }, - { - "args": [ - { - "name": "implementation", - "type": "principal" - } - ], - "name": "is-current-implementation", - "access": "read_only", - "outputs": { - "type": { - "response": { - "ok": "bool", - "error": "none" - } - } - } - } - ], - "variables": [ - { - "name": "CONTRACT_NAME", - "type": { - "string-ascii": { - "length": 11 - } - }, - "access": "constant" - }, - { - "name": "err-not-current-implementation", - "type": { - "response": { - "ok": "none", - "error": "uint128" - } - }, - "access": "constant" - }, - { - "name": "err-not-owner", - "type": { - "response": { - "ok": "none", - "error": "uint128" - } - }, - "access": "constant" - }, - { - "name": "contract-owner", - "type": "principal", - "access": "variable" - }, - { - "name": "current-logic-implementation", - "type": "principal", - "access": "variable" - }, - { - "name": "current-proxy", - "type": { - "optional": "principal" - }, - "access": "variable" - } - ], - "clarity_version": "Clarity2", - "fungible_tokens": [], - "non_fungible_tokens": [] - } \ No newline at end of file diff --git a/relayer/chains/stacks/client.go b/relayer/chains/stacks/client.go index 0a345133..17d90bf3 100644 --- a/relayer/chains/stacks/client.go +++ b/relayer/chains/stacks/client.go @@ -6,11 +6,9 @@ import ( "encoding/json" "fmt" "math/big" - "os" "strings" "github.com/icon-project/centralized-relay/relayer/chains/stacks/interfaces" - "github.com/icon-project/stacks-go-sdk/pkg/abi" "github.com/icon-project/stacks-go-sdk/pkg/clarity" rpcClient "github.com/icon-project/stacks-go-sdk/pkg/rpc_client" "github.com/icon-project/stacks-go-sdk/pkg/stacks" @@ -28,10 +26,9 @@ type Client struct { log *zap.Logger pendingRequests map[int64]chan *json.RawMessage network *stacks.StacksNetwork - xCallProxyABI *abi.ABI } -func NewClient(logger *zap.Logger, network *stacks.StacksNetwork, xcallAbiPath string) (*Client, error) { +func NewClient(logger *zap.Logger, network *stacks.StacksNetwork) (*Client, error) { cfg := blockchainApiClient.NewConfiguration() cfg.Servers = blockchainApiClient.ServerConfigurations{ { @@ -49,23 +46,12 @@ func NewClient(logger *zap.Logger, network *stacks.StacksNetwork, xcallAbiPath s } rpcApiClient := rpcClient.NewAPIClient(rpcCfg) - xCallProxyABIBytes, err := os.ReadFile(xcallAbiPath) - if err != nil { - return nil, fmt.Errorf("failed to read xcall-proxy ABI: %w", err) - } - - var xCallProxyABI abi.ABI - if err := json.Unmarshal(xCallProxyABIBytes, &xCallProxyABI); err != nil { - return nil, fmt.Errorf("failed to parse xcall-proxy ABI: %w", err) - } - return &Client{ apiClient: *apiClient, rpcApiClient: *rpcApiClient, log: logger, pendingRequests: make(map[int64]chan *json.RawMessage), network: network, - xCallProxyABI: &xCallProxyABI, }, nil } diff --git a/relayer/chains/stacks/client_test.go b/relayer/chains/stacks/client_test.go index fe334344..a4a9ac20 100644 --- a/relayer/chains/stacks/client_test.go +++ b/relayer/chains/stacks/client_test.go @@ -3,7 +3,6 @@ package stacks_test import ( "context" "encoding/hex" - "path/filepath" "strings" "testing" @@ -19,8 +18,7 @@ func TestClient_GetAccountBalance(t *testing.T) { ctx := context.Background() logger, _ := zap.NewDevelopment() network := stacksSdk.NewStacksTestnet() - xcallAbiPath := filepath.Join("abi", "xcall-proxy-abi.json") - client, err := stacks.NewClient(logger, network, xcallAbiPath) + client, err := stacks.NewClient(logger, network) if err != nil { t.Fatalf("Failed to create client: %v", err) } @@ -38,8 +36,7 @@ func TestClient_GetAccountNonce(t *testing.T) { ctx := context.Background() logger, _ := zap.NewDevelopment() network := stacksSdk.NewStacksTestnet() - xcallAbiPath := filepath.Join("abi", "xcall-proxy-abi.json") - client, err := stacks.NewClient(logger, network, xcallAbiPath) + client, err := stacks.NewClient(logger, network) if err != nil { t.Fatalf("Failed to create client: %v", err) } @@ -57,8 +54,7 @@ func TestClient_GetBlockByHeightOrHash(t *testing.T) { ctx := context.Background() logger, _ := zap.NewDevelopment() network := stacksSdk.NewStacksTestnet() - xcallAbiPath := filepath.Join("abi", "xcall-proxy-abi.json") - client, err := stacks.NewClient(logger, network, xcallAbiPath) + client, err := stacks.NewClient(logger, network) if err != nil { t.Fatalf("Failed to create client: %v", err) } @@ -85,8 +81,7 @@ func TestClient_GetLatestBlock(t *testing.T) { ctx := context.Background() logger, _ := zap.NewDevelopment() network := stacksSdk.NewStacksTestnet() - xcallAbiPath := filepath.Join("abi", "xcall-proxy-abi.json") - client, err := stacks.NewClient(logger, network, xcallAbiPath) + client, err := stacks.NewClient(logger, network) if err != nil { t.Fatalf("Failed to create client: %v", err) } @@ -103,8 +98,7 @@ func TestClient_CallReadOnlyFunction(t *testing.T) { ctx := context.Background() logger, _ := zap.NewDevelopment() network := stacksSdk.NewStacksTestnet() - xcallAbiPath := filepath.Join("abi", "xcall-proxy-abi.json") - client, err := stacks.NewClient(logger, network, xcallAbiPath) + client, err := stacks.NewClient(logger, network) if err != nil { t.Fatalf("Failed to create client: %v", err) } @@ -138,8 +132,7 @@ func TestClient_GetCurrentImplementation(t *testing.T) { ctx := context.Background() logger, _ := zap.NewDevelopment() network := stacksSdk.NewStacksTestnet() - xcallAbiPath := filepath.Join("abi", "xcall-proxy-abi.json") - client, err := stacks.NewClient(logger, network, xcallAbiPath) + client, err := stacks.NewClient(logger, network) assert.NoError(t, err, "Failed to create client") contractAddress := "ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH" @@ -155,8 +148,7 @@ func TestClient_SetAdmin(t *testing.T) { ctx := context.Background() logger, _ := zap.NewDevelopment() network := stacksSdk.NewStacksTestnet() - xcallAbiPath := filepath.Join("abi", "xcall-proxy-abi.json") - client, err := stacks.NewClient(logger, network, xcallAbiPath) + client, err := stacks.NewClient(logger, network) assert.NoError(t, err, "Failed to create client") contractAddress := "ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH.xcall-proxy" diff --git a/relayer/chains/stacks/events/listener.go b/relayer/chains/stacks/events/listener.go index 73b6d676..ff6e9166 100644 --- a/relayer/chains/stacks/events/listener.go +++ b/relayer/chains/stacks/events/listener.go @@ -81,17 +81,29 @@ func (l *EventListener) connect() error { defer l.mu.Unlock() if l.conn != nil { + l.log.Debug("Closing existing connection") l.conn.Close() } - conn, _, err := websocket.DefaultDialer.Dial(l.wsURL, nil) + l.log.Info("Attempting WebSocket connection", zap.String("url", l.wsURL)) + + conn, resp, err := websocket.DefaultDialer.Dial(l.wsURL, nil) if err != nil { + if resp != nil { + l.log.Error("WebSocket connection failed", + zap.Error(err), + zap.Int("status", resp.StatusCode), + zap.String("status_text", resp.Status)) + } else { + l.log.Error("WebSocket connection failed with no response", + zap.Error(err)) + } return err } l.conn = conn + l.log.Info("WebSocket connection established") - // Subscribe to all event types for _, eventType := range []string{EmitMessage, CallMessage, RollbackMessage} { if err := l.subscribe(eventType); err != nil { l.conn.Close() diff --git a/relayer/chains/stacks/provider.go b/relayer/chains/stacks/provider.go index 0b1c6ae6..f7c64946 100644 --- a/relayer/chains/stacks/provider.go +++ b/relayer/chains/stacks/provider.go @@ -4,9 +4,6 @@ import ( "context" "fmt" "math/big" - "os" - "path/filepath" - "sync" "time" "go.uber.org/zap" @@ -14,7 +11,6 @@ import ( "github.com/icon-project/centralized-relay/relayer/chains/stacks/interfaces" "github.com/icon-project/centralized-relay/relayer/kms" "github.com/icon-project/centralized-relay/relayer/provider" - "github.com/icon-project/centralized-relay/relayer/types" providerTypes "github.com/icon-project/centralized-relay/relayer/types" "github.com/icon-project/stacks-go-sdk/pkg/stacks" ) @@ -34,7 +30,6 @@ type Provider struct { privateKey []byte contracts map[string]providerTypes.EventMap LastSavedHeightFunc func() uint64 - routerMutex sync.Mutex } func (c *Config) NewProvider(ctx context.Context, log *zap.Logger, homepath string, debug bool, chainName string) (provider.ChainProvider, error) { @@ -42,6 +37,11 @@ func (c *Config) NewProvider(ctx context.Context, log *zap.Logger, homepath stri return nil, err } + log.Info("Initializing Stacks provider", + zap.String("nid", c.NID), + zap.String("chainName", chainName), + zap.String("rpcUrl", c.RPCUrl)) + var network *stacks.StacksNetwork if c.NID == "stacks" { network = stacks.NewStacksMainnet() @@ -51,12 +51,7 @@ func (c *Config) NewProvider(ctx context.Context, log *zap.Logger, homepath stri return nil, fmt.Errorf("no network found for nid: %v", c.NID) } - dir, err := os.Getwd() - if err != nil { - fmt.Println("Error:", err) - } - xcallAbiPath := filepath.Join(dir, "relayer/chains/stacks", "abi", "xcall-proxy-abi.json") - client, err := NewClient(log, network, xcallAbiPath) + client, err := NewClient(log, network) if err != nil { return nil, fmt.Errorf("failed to create Stacks client: %v", err) } @@ -167,7 +162,7 @@ func (p *Provider) SetAdmin(ctx context.Context, newAdmin string) error { return nil } -func (p *Provider) waitForTransactionConfirmation(ctx context.Context, txID string, timeoutDuration time.Duration) (*types.Receipt, error) { +func (p *Provider) waitForTransactionConfirmation(ctx context.Context, txID string, timeoutDuration time.Duration) (*providerTypes.Receipt, error) { timeout := time.After(timeoutDuration) ticker := time.NewTicker(time.Second) defer ticker.Stop() diff --git a/test/chains/stacks/remotenet.go b/test/chains/stacks/remotenet.go index 2785ec7f..b8e7ec00 100644 --- a/test/chains/stacks/remotenet.go +++ b/test/chains/stacks/remotenet.go @@ -45,12 +45,17 @@ type StacksLocalnet struct { func NewStacksLocalnet(testName string, log *zap.Logger, chainConfig chains.ChainConfig, testconfig *testconfig.Chain, kms kms.KMS) chains.Chain { network := stacks.NewStacksTestnet() - client, err := stacksClient.NewClient(log, network, testconfig.Contracts["xcall-abi"]) + client, err := stacksClient.NewClient(log, network) if err != nil { log.Error("Failed to create Stacks client", zap.Error(err)) return nil } + log.Debug("Creating Stacks chain", + zap.String("chainID", chainConfig.ChainID), + zap.String("name", chainConfig.Name), + zap.String("type", chainConfig.Type)) + return &StacksLocalnet{ testName: testName, cfg: chainConfig, @@ -84,6 +89,7 @@ func (s *StacksLocalnet) GetRelayConfig(ctx context.Context, rlyHome string, key config := ¢ralized.StacksRelayerChainConfig{ Type: "stacks", Value: centralized.StacksRelayerChainConfigValue{ + NID: s.testconfig.NID, RPCURL: s.testconfig.RPCUri, StartHeight: 0, Contracts: contracts, @@ -1071,18 +1077,6 @@ func (s *StacksLocalnet) SendPacketXCall(ctx context.Context, keyName, _to strin } implAddr := s.IBCAddresses["xcall-impl"] - implResult, err := s.client.CallReadOnlyFunction( - ctx, - "ST1FTM84RHDZ3AB21MNYKA3XQEFB090HZBB81DSFE", - "xcall-proxy", - "get-current-implementation", - []string{}, - ) - if err != nil { - return nil, fmt.Errorf("failed to get current implementation: %w", err) - } - s.log.Debug("Current implementation", zap.String("result", *implResult)) - implPrincipal, err := clarity.StringToPrincipal(implAddr) if err != nil { return nil, fmt.Errorf("failed to create implementation argument: %w", err) @@ -1110,84 +1104,6 @@ func (s *StacksLocalnet) SendPacketXCall(ctx context.Context, keyName, _to strin if len(parts) != 2 { return nil, fmt.Errorf("invalid dapp address format: %s", dappAddress) } - contractAddr := parts[0] - - network := strings.Split(_to, "/")[0] - - s.log.Debug("Checking network sources/destinations", - zap.String("network", network)) - - networkArg, err := clarity.NewStringASCII(network) - if err != nil { - return nil, fmt.Errorf("failed to create network argument: %w", err) - } - - networkBytes, err := networkArg.Serialize() - if err != nil { - return nil, fmt.Errorf("failed to serialize network argument: %w", err) - } - - hexEncodedNetwork := hex.EncodeToString(networkBytes) - - sourcesResult, err := s.client.CallReadOnlyFunction( - ctx, - contractAddr, - contractName, - "get-sources", - []string{hexEncodedNetwork}, - ) - if err != nil { - s.log.Error("Failed to get sources", - zap.Error(err), - zap.String("contractAddr", contractAddr), - zap.String("contractName", contractName), - zap.String("network", network), - zap.String("networkArg", hexEncodedNetwork)) - } else { - sourceBytes, err := hex.DecodeString(strings.TrimPrefix(*sourcesResult, "0x")) - if err != nil { - s.log.Error("Failed to decode sources result", zap.Error(err)) - } else { - sourcesValue, err := clarity.DeserializeClarityValue(sourceBytes) - if err != nil { - s.log.Error("Failed to deserialize sources", zap.Error(err)) - } else { - s.log.Debug("Sources for network", - zap.String("network", network), - zap.Any("sources", sourcesValue)) - } - } - } - - destsResult, err := s.client.CallReadOnlyFunction( - ctx, - contractAddr, - contractName, - "get-destinations", - []string{hexEncodedNetwork}, - ) - if err != nil { - s.log.Error("Failed to get destinations", - zap.Error(err), - zap.String("contractAddr", contractAddr), - zap.String("contractName", contractName), - zap.String("network", network), - zap.String("networkArg", hexEncodedNetwork)) - } else { - destBytes, err := hex.DecodeString(strings.TrimPrefix(*destsResult, "0x")) - if err != nil { - s.log.Error("Failed to decode destinations result", zap.Error(err)) - } else { - destsValue, err := clarity.DeserializeClarityValue(destBytes) - if err != nil { - s.log.Error("Failed to deserialize destinations", zap.Error(err)) - } else { - s.log.Debug("Destinations for network", - zap.String("network", network), - zap.Any("destinations", destsValue)) - } - } - } txCall, err := transaction.MakeContractCall( senderAddress, @@ -1221,6 +1137,11 @@ func (s *StacksLocalnet) SendPacketXCall(ctx context.Context, keyName, _to strin return nil, fmt.Errorf("failed to extract serial number: %w", err) } + s.log.Info("Successfully sent packet", + zap.String("txID", txID), + zap.String("sn", sn), + zap.String("to", _to)) + ctx = context.WithValue(ctx, snContextKey, sn) return ctx, nil } @@ -1238,13 +1159,20 @@ func (s *StacksLocalnet) extractSnFromTransaction(ctx context.Context, txID stri contractLog := event.SmartContractLogTransactionEvent.ContractLog if contractLog.Topic == "print" { repr := contractLog.Value.Repr + s.log.Debug("Found event log", + zap.String("repr", repr), + zap.String("topic", contractLog.Topic)) if strings.Contains(repr, "CallMessageSent") { + s.log.Debug("Found CallMessageSent event", + zap.String("full_event", repr)) startIdx := strings.Index(repr, "(sn u") if startIdx != -1 { startIdx += 5 // Move past "(sn u" endIdx := strings.Index(repr[startIdx:], ")") if endIdx != -1 { sn := repr[startIdx : startIdx+endIdx] + s.log.Info("Successfully extracted sn", + zap.String("sn", sn)) return sn, nil } } diff --git a/test/interchaintest/relayer/centralized/centralized_relayer.go b/test/interchaintest/relayer/centralized/centralized_relayer.go index c70d75f2..3a992e79 100644 --- a/test/interchaintest/relayer/centralized/centralized_relayer.go +++ b/test/interchaintest/relayer/centralized/centralized_relayer.go @@ -155,6 +155,7 @@ type SolanaRelayerChainConfigValue struct { } type StacksRelayerChainConfigValue struct { + NID string `yaml:"nid" json:"nid"` RPCURL string `yaml:"rpc-url"` StartHeight int `yaml:"start-height"` Contracts map[string]string `yaml:"contracts"` diff --git a/test/sample-config.yaml b/test/sample-config.yaml index f7169a56..863d42ab 100644 --- a/test/sample-config.yaml +++ b/test/sample-config.yaml @@ -1,6 +1,7 @@ chains: - name: stacks + nid: stacks_testnet version: "3" environment: remote rpc_uri: https://api.testnet.hiro.so @@ -13,6 +14,7 @@ chains: type: stacks name: stacks chain_id: stacks_testnet + nid: stacks_testnet image: repository: blockstack/stacks-blockchain version: latest @@ -27,7 +29,6 @@ chains: no_host_mount: false contracts: xcall-proxy: "$BASE_PATH/artifacts/stacks/contracts/xcall/xcall-proxy.clar" - xcall-abi: "$BASE_PATH/relayer/chains/stacks/abi/xcall-proxy-abi.json" connection: "$BASE_PATH/artifacts/stacks/contracts/connections/centralized-connection.clar" dapp: "$BASE_PATH/artifacts/stacks/tests/mocks/mock-dapp.clar" common-trait: "$BASE_PATH/artifacts/stacks/contracts/xcall/xcall-common-trait.clar" From 3c6916ac8071e2c8ffe9f43cc2d5d09feb878c98 Mon Sep 17 00:00:00 2001 From: CyrusVorwald <90732384+CyrusVorwald@users.noreply.github.com> Date: Wed, 13 Nov 2024 20:41:20 -0500 Subject: [PATCH 8/9] feat: CallMessageSent calls protocols send-message --- relayer/chains/stacks/client.go | 22 + relayer/chains/stacks/client_test.go | 88 ---- relayer/chains/stacks/events/handlers.go | 127 +++++ relayer/chains/stacks/events/handlers_test.go | 467 ++++++++++++++++++ relayer/chains/stacks/events/listener.go | 19 +- relayer/chains/stacks/events/listener_test.go | 136 +++++ relayer/chains/stacks/events/processor.go | 59 ++- .../chains/stacks/events/processor_test.go | 271 ++++++++++ relayer/chains/stacks/events/store_test.go | 116 +++++ relayer/chains/stacks/events/system.go | 5 +- relayer/chains/stacks/events/types.go | 32 +- relayer/chains/stacks/interfaces/client.go | 3 + relayer/chains/stacks/listener.go | 2 +- relayer/chains/stacks/mocks/client_mock.go | 19 + relayer/chains/stacks/provider_test.go | 259 ---------- relayer/chains/stacks/query.go | 6 +- relayer/chains/stacks/stacks_test.go | 79 --- test/chains/stacks/remotenet.go | 332 +++++++------ test/sample-config.yaml | 2 +- 19 files changed, 1426 insertions(+), 618 deletions(-) create mode 100644 relayer/chains/stacks/events/handlers.go create mode 100644 relayer/chains/stacks/events/handlers_test.go create mode 100644 relayer/chains/stacks/events/listener_test.go create mode 100644 relayer/chains/stacks/events/processor_test.go create mode 100644 relayer/chains/stacks/events/store_test.go delete mode 100644 relayer/chains/stacks/stacks_test.go diff --git a/relayer/chains/stacks/client.go b/relayer/chains/stacks/client.go index 17d90bf3..33f3e3b8 100644 --- a/relayer/chains/stacks/client.go +++ b/relayer/chains/stacks/client.go @@ -89,6 +89,28 @@ func (c *Client) GetContractById(ctx context.Context, contractId string) (*block return resp, nil } +func (c *Client) GetContractEvents(ctx context.Context, contractId string, limit, offset int32) (*blockchainApiClient.GetContractEventsById200Response, error) { + req := c.apiClient.SmartContractsAPI.GetContractEventsById(ctx, contractId) + + if limit > 0 { + req = req.Limit(limit) + } + + if offset > 0 { + req = req.Offset(offset) + } + + resp, httpResp, err := req.Execute() + if err != nil { + if httpResp != nil { + return nil, fmt.Errorf("failed to get contract events (status %d): %w", httpResp.StatusCode, err) + } + return nil, fmt.Errorf("failed to get contract events: %w", err) + } + + return resp, nil +} + func (c *Client) GetAccountNonce(ctx context.Context, address string) (uint64, error) { principal := blockchainApiClient.GetFilteredEventsAddressParameter{ String: &address, diff --git a/relayer/chains/stacks/client_test.go b/relayer/chains/stacks/client_test.go index a4a9ac20..c675b207 100644 --- a/relayer/chains/stacks/client_test.go +++ b/relayer/chains/stacks/client_test.go @@ -8,30 +8,11 @@ import ( "github.com/icon-project/centralized-relay/relayer/chains/stacks" "github.com/icon-project/stacks-go-sdk/pkg/clarity" - "github.com/icon-project/stacks-go-sdk/pkg/crypto" stacksSdk "github.com/icon-project/stacks-go-sdk/pkg/stacks" "github.com/stretchr/testify/assert" "go.uber.org/zap" ) -func TestClient_GetAccountBalance(t *testing.T) { - ctx := context.Background() - logger, _ := zap.NewDevelopment() - network := stacksSdk.NewStacksTestnet() - client, err := stacks.NewClient(logger, network) - if err != nil { - t.Fatalf("Failed to create client: %v", err) - } - - address := "ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH" - balance, err := client.GetAccountBalance(ctx, address) - if err != nil { - t.Fatalf("Failed to get account balance: %v", err) - } - - t.Logf("Balance for address %s: %s", address, balance.String()) -} - func TestClient_GetAccountNonce(t *testing.T) { ctx := context.Background() logger, _ := zap.NewDevelopment() @@ -50,50 +31,6 @@ func TestClient_GetAccountNonce(t *testing.T) { t.Logf("Nonce for address %s: %d", address, nonce) } -func TestClient_GetBlockByHeightOrHash(t *testing.T) { - ctx := context.Background() - logger, _ := zap.NewDevelopment() - network := stacksSdk.NewStacksTestnet() - client, err := stacks.NewClient(logger, network) - if err != nil { - t.Fatalf("Failed to create client: %v", err) - } - - block, err := client.GetLatestBlock(ctx) - if err != nil { - t.Fatalf("Failed to get latest blocks: %v", err) - } - if block == nil { - t.Fatalf("No blocks found") - } - - blockHeight := block.Height - - block, err = client.GetBlockByHeightOrHash(ctx, uint64(blockHeight)) - if err != nil { - t.Fatalf("Failed to get block by height: %v", err) - } - - t.Logf("Block at height %d: %+v", blockHeight, block) -} - -func TestClient_GetLatestBlock(t *testing.T) { - ctx := context.Background() - logger, _ := zap.NewDevelopment() - network := stacksSdk.NewStacksTestnet() - client, err := stacks.NewClient(logger, network) - if err != nil { - t.Fatalf("Failed to create client: %v", err) - } - - block, err := client.GetLatestBlock(ctx) - if err != nil { - t.Fatalf("Failed to get latest blocks: %v", err) - } - - t.Logf("Latest block: %+v", block) -} - func TestClient_CallReadOnlyFunction(t *testing.T) { ctx := context.Background() logger, _ := zap.NewDevelopment() @@ -143,28 +80,3 @@ func TestClient_GetCurrentImplementation(t *testing.T) { t.Logf("Current implementation: %s", impl) } - -func TestClient_SetAdmin(t *testing.T) { - ctx := context.Background() - logger, _ := zap.NewDevelopment() - network := stacksSdk.NewStacksTestnet() - client, err := stacks.NewClient(logger, network) - assert.NoError(t, err, "Failed to create client") - - contractAddress := "ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH.xcall-proxy" - newAdmin := "ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH" - - currentImplementation, _ := client.GetCurrentImplementation(ctx, contractAddress) - senderAddress := "ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH" - mnemonic := "vapor unhappy gather snap project ball gain puzzle comic error avocado bounce letter anxiety wheel provide canyon promote sniff improve figure daughter mansion baby" - senderKey, err := crypto.DeriveStxPrivateKey(mnemonic, 0) - if err != nil { - t.Fatalf("Failed to derive sender key: %v", err) - } - - txID, err := client.SetAdmin(ctx, contractAddress, newAdmin, currentImplementation, senderAddress, senderKey) - assert.NoError(t, err, "Failed to set admin") - assert.NotEmpty(t, txID, "Transaction ID should not be empty") - - t.Logf("SetAdmin transaction ID: %s", txID) -} diff --git a/relayer/chains/stacks/events/handlers.go b/relayer/chains/stacks/events/handlers.go new file mode 100644 index 00000000..beedc1c1 --- /dev/null +++ b/relayer/chains/stacks/events/handlers.go @@ -0,0 +1,127 @@ +package events + +import ( + "fmt" + "strings" + + "go.uber.org/zap" + + "github.com/icon-project/stacks-go-sdk/pkg/clarity" +) + +func (p *EventProcessor) handleCallMessageSentEvent(event *Event) error { + data, ok := event.Data.(CallMessageSentData) + if !ok { + return fmt.Errorf("invalid event data type for CallMessageSent") + } + + p.log.Info("Processing CallMessageSent event", + zap.String("from", data.From), + zap.String("to", data.To), + zap.Uint64("sn", data.Sn), + zap.Strings("sources", data.Sources), + zap.Strings("destinations", data.Destinations), + ) + + for _, source := range data.Sources { + if err := p.callSendMessageFunction(source, data.To, data.Sn, data.Data); err != nil { + p.log.Error("Failed to call send-message", zap.Error(err), zap.String("source", source)) + return err + } + } + + return nil +} + +func (p *EventProcessor) handleCallMessageEvent(event *Event) error { + data, ok := event.Data.(CallMessageData) + if !ok { + return fmt.Errorf("invalid event data type for CallMessage") + } + + p.log.Info("Processing CallMessage event", + zap.String("from", data.From), + zap.String("to", data.To), + zap.Uint64("sn", data.Sn), + zap.Uint64("req-id", data.ReqID), + ) + + return nil +} + +func (p *EventProcessor) handleResponseMessageEvent(event *Event) error { + data, ok := event.Data.(ResponseMessageData) + if !ok { + return fmt.Errorf("invalid event data type for ResponseMessage") + } + + p.log.Info("Processing ResponseMessage event", + zap.Uint64("sn", data.Sn), + zap.Uint64("code", data.Code), + zap.String("msg", data.Msg), + ) + + return nil +} + +func (p *EventProcessor) handleRollbackMessageEvent(event *Event) error { + data, ok := event.Data.(RollbackMessageData) + if !ok { + return fmt.Errorf("invalid event data type for RollbackMessage") + } + + p.log.Info("Processing RollbackMessage event", + zap.Uint64("sn", data.Sn), + ) + + return nil +} + +func (p *EventProcessor) callSendMessageFunction(sourceContract string, to string, sn uint64, msg string) error { + parts := strings.Split(sourceContract, ".") + if len(parts) != 2 { + return fmt.Errorf("invalid source contract format: %s", sourceContract) + } + sourceContractAddress := parts[0] + sourceContractName := parts[1] + + cvTo, err := clarity.NewStringASCII(to) + if err != nil { + return fmt.Errorf("failed to create to address clarity value: %w", err) + } + + cvSn, err := clarity.NewUInt(sn) + if err != nil { + return fmt.Errorf("failed to create sn clarity value: %w", err) + } + + cvBuffer := clarity.NewBuffer([]byte(msg)) + + args := []clarity.ClarityValue{ + cvTo, + cvSn, + cvBuffer, + } + + tx, err := p.client.MakeContractCall( + p.ctx, + sourceContractAddress, + sourceContractName, + "send-message", + args, + p.senderAddress, + p.senderKey, + ) + if err != nil { + return fmt.Errorf("failed to create contract call transaction: %w", err) + } + + txID, err := p.client.BroadcastTransaction(p.ctx, tx) + if err != nil { + return fmt.Errorf("failed to broadcast transaction: %w", err) + } + + p.log.Info("send-message transaction sent", zap.String("txID", txID), zap.String("source", sourceContract)) + + return nil +} diff --git a/relayer/chains/stacks/events/handlers_test.go b/relayer/chains/stacks/events/handlers_test.go new file mode 100644 index 00000000..d6c2d067 --- /dev/null +++ b/relayer/chains/stacks/events/handlers_test.go @@ -0,0 +1,467 @@ +package events + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "go.uber.org/zap" + + "github.com/icon-project/centralized-relay/relayer/chains/stacks/mocks" + "github.com/icon-project/stacks-go-sdk/pkg/clarity" + "github.com/icon-project/stacks-go-sdk/pkg/transaction" +) + +func TestEventProcessor_handleCallMessageSentEvent(t *testing.T) { + ctx := context.Background() + log := zap.NewNop() + mockClient := new(mocks.MockClient) + store := NewMemoryEventStore() + + processor := NewEventProcessor(ctx, store, make(chan *Event, 10), 1, log, mockClient, "senderAddress", []byte("senderKey")) + + tests := []struct { + name string + event *Event + setupMocks func() + expectError bool + }{ + { + name: "successful call message sent", + event: &Event{ + ID: "event1", + Type: CallMessageSent, + Data: CallMessageSentData{ + From: "fromAddr", + To: "toAddr", + Sn: 123, + Data: "test data", + Sources: []string{"ST1.contract1", "ST2.contract2"}, + Destinations: []string{"dest1"}, + }, + }, + setupMocks: func() { + mockTx := &transaction.ContractCallTransaction{} + mockClient.On("MakeContractCall", + mock.Anything, + "ST1", + "contract1", + "send-message", + mock.MatchedBy(func(args []clarity.ClarityValue) bool { + return len(args) == 3 + }), + "senderAddress", + []byte("senderKey"), + ).Return(mockTx, nil).Once() + + mockClient.On("MakeContractCall", + mock.Anything, + "ST2", + "contract2", + "send-message", + mock.MatchedBy(func(args []clarity.ClarityValue) bool { + return len(args) == 3 + }), + "senderAddress", + []byte("senderKey"), + ).Return(mockTx, nil).Once() + + mockClient.On("BroadcastTransaction", + mock.Anything, + mockTx, + ).Return("tx-id", nil).Twice() + }, + expectError: false, + }, + { + name: "invalid source contract format", + event: &Event{ + ID: "event2", + Type: CallMessageSent, + Data: CallMessageSentData{ + From: "fromAddr", + To: "toAddr", + Sn: 123, + Data: "test data", + Sources: []string{"invalid-format"}, + Destinations: []string{"dest1"}, + }, + }, + setupMocks: func() {}, + expectError: true, + }, + { + name: "invalid data type", + event: &Event{ + ID: "event3", + Type: CallMessageSent, + Data: "invalid data type", + }, + setupMocks: func() {}, + expectError: true, + }, + { + name: "contract call fails", + event: &Event{ + ID: "event4", + Type: CallMessageSent, + Data: CallMessageSentData{ + From: "fromAddr", + To: "toAddr", + Sn: 123, + Data: "test data", + Sources: []string{"ST1.contract1"}, + Destinations: []string{"dest1"}, + }, + }, + setupMocks: func() { + mockTx := &transaction.ContractCallTransaction{} + mockClient.On("MakeContractCall", + mock.Anything, + "ST1", + "contract1", + "send-message", + mock.MatchedBy(func(args []clarity.ClarityValue) bool { + return len(args) == 3 + }), + "senderAddress", + []byte("senderKey"), + ).Return(mockTx, fmt.Errorf("contract call failed")).Once() + }, + expectError: true, + }, + { + name: "broadcast fails", + event: &Event{ + ID: "event5", + Type: CallMessageSent, + Data: CallMessageSentData{ + From: "fromAddr", + To: "toAddr", + Sn: 123, + Data: "test data", + Sources: []string{"ST1.contract1"}, + Destinations: []string{"dest1"}, + }, + }, + setupMocks: func() { + mockTx := &transaction.ContractCallTransaction{} + mockClient.On("MakeContractCall", + mock.Anything, + "ST1", + "contract1", + "send-message", + mock.MatchedBy(func(args []clarity.ClarityValue) bool { + return len(args) == 3 + }), + "senderAddress", + []byte("senderKey"), + ).Return(mockTx, nil).Once() + + mockClient.On("BroadcastTransaction", + mock.Anything, + mockTx, + ).Return("", fmt.Errorf("broadcast failed")).Once() + }, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockClient.ExpectedCalls = nil + mockClient.Calls = nil + + tt.setupMocks() + + err := processor.handleCallMessageSentEvent(tt.event) + + if tt.expectError { + assert.Error(t, err, "Expected an error but got nil") + } else { + assert.NoError(t, err, "Expected no error but got: %v", err) + } + + mockClient.AssertExpectations(t) + }) + } +} + +func TestEventProcessor_handleCallMessageEvent(t *testing.T) { + ctx := context.Background() + log := zap.NewNop() + mockClient := new(mocks.MockClient) + store := NewMemoryEventStore() + + processor := NewEventProcessor(ctx, store, make(chan *Event, 10), 1, log, mockClient, "senderAddress", []byte("senderKey")) + + tests := []struct { + name string + event *Event + expectError bool + }{ + { + name: "successful call message", + event: &Event{ + ID: "event1", + Type: CallMessage, + Data: CallMessageData{ + From: "fromAddr", + To: "toAddr", + Sn: 123, + ReqID: 456, + Data: "test data", + }, + }, + expectError: false, + }, + { + name: "invalid data type", + event: &Event{ + ID: "event2", + Type: CallMessage, + Data: "invalid data type", + }, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := processor.handleCallMessageEvent(tt.event) + + if tt.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestEventProcessor_handleResponseMessageEvent(t *testing.T) { + ctx := context.Background() + log := zap.NewNop() + mockClient := new(mocks.MockClient) + store := NewMemoryEventStore() + + processor := NewEventProcessor(ctx, store, make(chan *Event, 10), 1, log, mockClient, "senderAddress", []byte("senderKey")) + + tests := []struct { + name string + event *Event + expectError bool + }{ + { + name: "successful response message", + event: &Event{ + ID: "event1", + Type: ResponseMessage, + Data: ResponseMessageData{ + Sn: 123, + Code: 0, + Msg: "success", + }, + }, + expectError: false, + }, + { + name: "invalid data type", + event: &Event{ + ID: "event2", + Type: ResponseMessage, + Data: "invalid data type", + }, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := processor.handleResponseMessageEvent(tt.event) + + if tt.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestEventProcessor_handleRollbackMessageEvent(t *testing.T) { + ctx := context.Background() + log := zap.NewNop() + mockClient := new(mocks.MockClient) + store := NewMemoryEventStore() + + processor := NewEventProcessor(ctx, store, make(chan *Event, 10), 1, log, mockClient, "senderAddress", []byte("senderKey")) + + tests := []struct { + name string + event *Event + expectError bool + }{ + { + name: "successful rollback message", + event: &Event{ + ID: "event1", + Type: RollbackMessage, + Data: RollbackMessageData{ + Sn: 123, + }, + }, + expectError: false, + }, + { + name: "invalid data type", + event: &Event{ + ID: "event2", + Type: RollbackMessage, + Data: "invalid data type", + }, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := processor.handleRollbackMessageEvent(tt.event) + + if tt.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestEventProcessor_callSendMessageFunction(t *testing.T) { + ctx := context.Background() + log := zap.NewNop() + mockClient := new(mocks.MockClient) + store := NewMemoryEventStore() + + processor := NewEventProcessor(ctx, store, make(chan *Event, 10), 1, log, mockClient, "senderAddress", []byte("senderKey")) + + tests := []struct { + name string + sourceContract string + to string + sn uint64 + msg string + setupMocks func() + expectError bool + }{ + { + name: "successful contract call", + sourceContract: "ST1.contract1", + to: "toAddr", + sn: 123, + msg: "test data", + setupMocks: func() { + mockTx := &transaction.ContractCallTransaction{} + mockClient.On("MakeContractCall", + mock.Anything, + "ST1", + "contract1", + "send-message", + mock.MatchedBy(func(args []clarity.ClarityValue) bool { + return len(args) == 3 + }), + "senderAddress", + []byte("senderKey"), + ).Return(mockTx, nil).Once() + + mockClient.On("BroadcastTransaction", + mock.Anything, + mockTx, + ).Return("tx-id", nil).Once() + }, + expectError: false, + }, + { + name: "invalid contract format", + sourceContract: "invalid-format", + to: "toAddr", + sn: 123, + msg: "test data", + setupMocks: func() {}, + expectError: true, + }, + { + name: "contract call fails", + sourceContract: "ST1.contract1", + to: "toAddr", + sn: 123, + msg: "test data", + setupMocks: func() { + mockTx := &transaction.ContractCallTransaction{} + mockClient.On("MakeContractCall", + mock.Anything, + "ST1", + "contract1", + "send-message", + mock.MatchedBy(func(args []clarity.ClarityValue) bool { + return len(args) == 3 + }), + "senderAddress", + []byte("senderKey"), + ).Return(mockTx, fmt.Errorf("contract call failed")).Once() + }, + expectError: true, + }, + { + name: "broadcast fails", + sourceContract: "ST1.contract1", + to: "toAddr", + sn: 123, + msg: "test data", + setupMocks: func() { + mockTx := &transaction.ContractCallTransaction{} + mockClient.On("MakeContractCall", + mock.Anything, + "ST1", + "contract1", + "send-message", + mock.MatchedBy(func(args []clarity.ClarityValue) bool { + return len(args) == 3 + }), + "senderAddress", + []byte("senderKey"), + ).Return(mockTx, nil).Once() + + mockClient.On("BroadcastTransaction", + mock.Anything, + mockTx, + ).Return("", fmt.Errorf("broadcast failed")).Once() + }, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockClient.ExpectedCalls = nil + mockClient.Calls = nil + + tt.setupMocks() + + err := processor.callSendMessageFunction(tt.sourceContract, tt.to, tt.sn, tt.msg) + + if tt.expectError { + assert.Error(t, err, "Expected an error but got nil") + if err == nil { + t.Logf("Expected error for test case: %s", tt.name) + } + } else { + assert.NoError(t, err, "Expected no error but got: %v", err) + } + + mockClient.AssertExpectations(t) + }) + } +} diff --git a/relayer/chains/stacks/events/listener.go b/relayer/chains/stacks/events/listener.go index ff6e9166..ddf0f45a 100644 --- a/relayer/chains/stacks/events/listener.go +++ b/relayer/chains/stacks/events/listener.go @@ -104,7 +104,7 @@ func (l *EventListener) connect() error { l.conn = conn l.log.Info("WebSocket connection established") - for _, eventType := range []string{EmitMessage, CallMessage, RollbackMessage} { + for _, eventType := range []string{CallMessageSent, CallMessage, ResponseMessage, RollbackMessage} { if err := l.subscribe(eventType); err != nil { l.conn.Close() return fmt.Errorf("failed to subscribe to %s: %w", eventType, err) @@ -224,24 +224,31 @@ func (l *EventListener) parseEvent(message []byte) (*Event, error) { var eventData interface{} switch printValue.Event { - case EmitMessage: - var data EmitMessageData + case CallMessageSent: + var data CallMessageSentData if err := json.Unmarshal(printValue.Data, &data); err != nil { - return nil, fmt.Errorf("failed to unmarshal emit message data: %w", err) + return nil, fmt.Errorf("failed to unmarshal CallMessageSent data: %w", err) } eventData = data case CallMessage: var data CallMessageData if err := json.Unmarshal(printValue.Data, &data); err != nil { - return nil, fmt.Errorf("failed to unmarshal call message data: %w", err) + return nil, fmt.Errorf("failed to unmarshal CallMessage data: %w", err) + } + eventData = data + + case ResponseMessage: + var data ResponseMessageData + if err := json.Unmarshal(printValue.Data, &data); err != nil { + return nil, fmt.Errorf("failed to unmarshal ResponseMessage data: %w", err) } eventData = data case RollbackMessage: var data RollbackMessageData if err := json.Unmarshal(printValue.Data, &data); err != nil { - return nil, fmt.Errorf("failed to unmarshal rollback message data: %w", err) + return nil, fmt.Errorf("failed to unmarshal RollbackMessage data: %w", err) } eventData = data diff --git a/relayer/chains/stacks/events/listener_test.go b/relayer/chains/stacks/events/listener_test.go new file mode 100644 index 00000000..bfc7dc87 --- /dev/null +++ b/relayer/chains/stacks/events/listener_test.go @@ -0,0 +1,136 @@ +package events + +import ( + "encoding/json" + "testing" + + "go.uber.org/zap" +) + +func TestEventListener_parseEvent(t *testing.T) { + log := zap.NewNop() + listener := &EventListener{ + log: log, + } + + messageStruct := WSMessage{ + JSONRPC: "2.0", + Method: "event", + Params: json.RawMessage(`{ + "event_type": "smart_contract_log", + "contract_event": { + "contract_id": "ST1234.contract", + "topic": "print", + "value": { + "event": "CallMessageSent", + "data": { + "from": "fromAddress", + "to": "toAddress", + "sn": 123, + "data": "message data", + "sources": ["source1"], + "destinations": ["dest1"] + } + } + }, + "tx_id": "0xabc", + "block_height": 100 + }`), + } + + messageBytes, err := json.Marshal(messageStruct) + if err != nil { + t.Fatalf("Failed to marshal test message: %v", err) + } + + event, err := listener.parseEvent(messageBytes) + if err != nil { + t.Fatalf("parseEvent returned error: %v", err) + } + if event == nil { + t.Fatal("parseEvent returned nil event") + } + + if event.Type != CallMessageSent { + t.Errorf("Expected event type %s, got %s", CallMessageSent, event.Type) + } + + data, ok := event.Data.(CallMessageSentData) + if !ok { + t.Errorf("Event data type is not CallMessageSentData") + } else { + if data.From != "fromAddress" { + t.Errorf("Expected data.From to be 'fromAddress', got '%s'", data.From) + } + if data.To != "toAddress" { + t.Errorf("Expected data.To to be 'toAddress', got '%s'", data.To) + } + if data.Sn != 123 { + t.Errorf("Expected data.Sn to be 123, got %d", data.Sn) + } + if data.Data != "message data" { + t.Errorf("Expected data.Data to be 'message data', got '%s'", data.Data) + } + if len(data.Sources) != 1 || data.Sources[0] != "source1" { + t.Errorf("Expected data.Sources to be ['source1'], got %v", data.Sources) + } + if len(data.Destinations) != 1 || data.Destinations[0] != "dest1" { + t.Errorf("Expected data.Destinations to be ['dest1'], got %v", data.Destinations) + } + } +} + +func TestEventListener_parseEvent_InvalidMethod(t *testing.T) { + log := zap.NewNop() + listener := &EventListener{ + log: log, + } + + messageStruct := WSMessage{ + JSONRPC: "2.0", + Method: "non_event", + Params: json.RawMessage(`{}`), + } + + messageBytes, err := json.Marshal(messageStruct) + if err != nil { + t.Fatalf("Failed to marshal test message: %v", err) + } + + event, err := listener.parseEvent(messageBytes) + if err != nil { + t.Errorf("parseEvent returned error: %v", err) + } + if event != nil { + t.Errorf("Expected nil event for non 'event' method") + } +} + +func TestEventListener_parseEvent_InvalidEventType(t *testing.T) { + log := zap.NewNop() + listener := &EventListener{ + log: log, + } + + messageStruct := WSMessage{ + JSONRPC: "2.0", + Method: "event", + Params: json.RawMessage(`{ + "event_type": "other_event", + "contract_event": {} + }`), + } + + messageBytes, err := json.Marshal(messageStruct) + if err != nil { + t.Fatalf("Failed to marshal test message: %v", err) + } + + event, err := listener.parseEvent(messageBytes) + if err != nil { + t.Errorf("parseEvent returned error: %v", err) + } + if event != nil { + t.Errorf("Expected nil event for invalid event_type") + } +} diff --git a/relayer/chains/stacks/events/processor.go b/relayer/chains/stacks/events/processor.go index a4b81964..fdc99e87 100644 --- a/relayer/chains/stacks/events/processor.go +++ b/relayer/chains/stacks/events/processor.go @@ -3,30 +3,37 @@ package events import ( "context" + "github.com/icon-project/centralized-relay/relayer/chains/stacks/interfaces" "go.uber.org/zap" ) type EventProcessor struct { - handlers []EventHandler - store EventStore - processChan chan *Event - maxWorkers int - workerTokens chan struct{} - log *zap.Logger - ctx context.Context - cancel context.CancelFunc + handlers []EventHandler + store EventStore + processChan chan *Event + maxWorkers int + workerTokens chan struct{} + log *zap.Logger + ctx context.Context + cancel context.CancelFunc + client interfaces.IClient + senderAddress string + senderKey []byte } -func NewEventProcessor(ctx context.Context, store EventStore, processChan chan *Event, maxWorkers int, log *zap.Logger) *EventProcessor { +func NewEventProcessor(ctx context.Context, store EventStore, processChan chan *Event, maxWorkers int, log *zap.Logger, client interfaces.IClient, senderAddress string, senderKey []byte) *EventProcessor { ctx, cancel := context.WithCancel(ctx) return &EventProcessor{ - store: store, - processChan: processChan, - maxWorkers: maxWorkers, - workerTokens: make(chan struct{}, maxWorkers), - log: log, - ctx: ctx, - cancel: cancel, + store: store, + processChan: processChan, + maxWorkers: maxWorkers, + workerTokens: make(chan struct{}, maxWorkers), + log: log, + client: client, + senderAddress: senderAddress, + senderKey: senderKey, + ctx: ctx, + cancel: cancel, } } @@ -70,6 +77,26 @@ func (p *EventProcessor) processEvent(event *Event) { } } + var err error + switch event.Type { + case CallMessageSent: + err = p.handleCallMessageSentEvent(event) + case CallMessage: + err = p.handleCallMessageEvent(event) + case ResponseMessage: + err = p.handleResponseMessageEvent(event) + case RollbackMessage: + err = p.handleRollbackMessageEvent(event) + default: + p.log.Warn("No handler for event type", zap.String("type", event.Type)) + return + } + + if err != nil { + p.log.Error("Handler failed", zap.Error(err), zap.String("eventType", event.Type)) + return + } + if err := p.store.MarkProcessed(event.ID); err != nil { p.log.Error("Failed to mark event as processed", zap.Error(err)) } diff --git a/relayer/chains/stacks/events/processor_test.go b/relayer/chains/stacks/events/processor_test.go new file mode 100644 index 00000000..73d4b598 --- /dev/null +++ b/relayer/chains/stacks/events/processor_test.go @@ -0,0 +1,271 @@ +package events + +import ( + "context" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "go.uber.org/zap" + + "github.com/icon-project/centralized-relay/relayer/chains/stacks/mocks" + "github.com/icon-project/stacks-go-sdk/pkg/clarity" + "github.com/icon-project/stacks-go-sdk/pkg/transaction" +) + +func TestEventProcessor_processEvent(t *testing.T) { + ctx := context.Background() + store := NewMemoryEventStore() + processChan := make(chan *Event, 10) + log := zap.NewNop() + mockClient := new(mocks.MockClient) + + processor := NewEventProcessor(ctx, store, processChan, 1, log, mockClient, "senderAddress", []byte("senderKey")) + + tests := []struct { + name string + event *Event + setupMocks func() + expectError bool + }{ + { + name: "CallMessageSent event", + event: &Event{ + ID: "event1", + Type: CallMessageSent, + Data: CallMessageSentData{ + From: "fromAddress", + To: "toAddress", + Sn: 123, + Data: "test data", + Sources: []string{"ST1.contract1"}, + Destinations: []string{"dest1"}, + }, + BlockHeight: 1, + Timestamp: time.Now(), + }, + setupMocks: func() { + mockTx := &transaction.ContractCallTransaction{} + + mockClient.On("MakeContractCall", + mock.Anything, + "ST1", + "contract1", + "send-message", + mock.MatchedBy(func(args []clarity.ClarityValue) bool { + if len(args) != 3 { + return false + } + _, isString := args[0].(*clarity.StringASCII) + _, isUint := args[1].(*clarity.UInt) + _, isBuffer := args[2].(*clarity.Buffer) + return isString && isUint && isBuffer + }), + "senderAddress", + []byte("senderKey"), + ).Return(mockTx, nil) + + mockClient.On("BroadcastTransaction", + mock.Anything, + mockTx, + ).Return("tx-id", nil) + }, + expectError: false, + }, + { + name: "CallMessage event", + event: &Event{ + ID: "event2", + Type: CallMessage, + Data: CallMessageData{ + From: "fromAddress", + To: "toAddress", + Sn: 123, + ReqID: 456, + Data: "test data", + }, + BlockHeight: 2, + Timestamp: time.Now(), + }, + setupMocks: func() {}, + expectError: false, + }, + { + name: "ResponseMessage event", + event: &Event{ + ID: "event3", + Type: ResponseMessage, + Data: ResponseMessageData{ + Sn: 123, + Code: 0, + Msg: "success", + }, + BlockHeight: 3, + Timestamp: time.Now(), + }, + setupMocks: func() {}, + expectError: false, + }, + { + name: "RollbackMessage event", + event: &Event{ + ID: "event4", + Type: RollbackMessage, + Data: RollbackMessageData{ + Sn: 123, + }, + BlockHeight: 4, + Timestamp: time.Now(), + }, + setupMocks: func() {}, + expectError: false, + }, + { + name: "Invalid event type", + event: &Event{ + ID: "event5", + Type: "InvalidType", + Data: nil, + BlockHeight: 5, + Timestamp: time.Now(), + }, + setupMocks: func() {}, + expectError: true, + }, + { + name: "Invalid data type for CallMessageSent", + event: &Event{ + ID: "event6", + Type: CallMessageSent, + Data: "invalid data type", + BlockHeight: 6, + Timestamp: time.Now(), + }, + setupMocks: func() {}, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.setupMocks() + + processor.processEvent(tt.event) + + events, err := store.GetEvents(tt.event.BlockHeight) + assert.NoError(t, err) + found := false + for _, e := range events { + if e.ID == tt.event.ID { + found = true + break + } + } + assert.True(t, found, "Event should be found in store") + + if !tt.expectError { + store.mu.RLock() + processed := store.processedEvents[tt.event.ID] + store.mu.RUnlock() + assert.True(t, processed, "Event should be marked as processed") + } + + mockClient.AssertExpectations(t) + }) + } +} + +func TestEventProcessor_Start_Stop(t *testing.T) { + ctx := context.Background() + store := NewMemoryEventStore() + processChan := make(chan *Event, 10) + log := zap.NewNop() + mockClient := new(mocks.MockClient) + + processor := NewEventProcessor(ctx, store, processChan, 2, log, mockClient, "senderAddress", []byte("senderKey")) + + processor.Start() + + event := &Event{ + ID: "test-event", + Type: CallMessage, + Data: CallMessageData{ + From: "fromAddress", + To: "toAddress", + Sn: 123, + ReqID: 456, + Data: "test data", + }, + BlockHeight: 1, + Timestamp: time.Now(), + } + + processChan <- event + + time.Sleep(100 * time.Millisecond) + + processor.Stop() + + store.mu.RLock() + processed := store.processedEvents["test-event"] + store.mu.RUnlock() + assert.True(t, processed) +} + +func TestEventProcessor_AddHandler(t *testing.T) { + ctx := context.Background() + store := NewMemoryEventStore() + processChan := make(chan *Event, 10) + log := zap.NewNop() + mockClient := new(mocks.MockClient) + + processor := NewEventProcessor(ctx, store, processChan, 1, log, mockClient, "senderAddress", []byte("senderKey")) + + handledEvents := make([]*Event, 0) + var mu sync.Mutex + + handler := func(event *Event) error { + mu.Lock() + handledEvents = append(handledEvents, event) + mu.Unlock() + return nil + } + + processor.AddHandler(handler) + + event := &Event{ + ID: "test-event", + Type: CallMessage, + Data: CallMessageData{ + From: "fromAddress", + To: "toAddress", + Sn: 123, + ReqID: 456, + Data: "test data", + }, + BlockHeight: 1, + Timestamp: time.Now(), + } + + processor.processEvent(event) + + time.Sleep(50 * time.Millisecond) + + mu.Lock() + assert.Equal(t, 1, len(handledEvents), "Handler should have been called exactly once") + if len(handledEvents) > 0 { + assert.Equal(t, event, handledEvents[0], "Handler should have received the correct event") + } + mu.Unlock() + + events, err := store.GetEvents(event.BlockHeight) + assert.NoError(t, err) + assert.Equal(t, 1, len(events), "Event should be saved in store") + + store.mu.RLock() + processed := store.processedEvents[event.ID] + store.mu.RUnlock() + assert.True(t, processed, "Event should be marked as processed") +} diff --git a/relayer/chains/stacks/events/store_test.go b/relayer/chains/stacks/events/store_test.go new file mode 100644 index 00000000..363ff456 --- /dev/null +++ b/relayer/chains/stacks/events/store_test.go @@ -0,0 +1,116 @@ +package events + +import ( + "testing" + "time" +) + +func TestMemoryEventStore_SaveEvent(t *testing.T) { + store := NewMemoryEventStore() + event := &Event{ + ID: "event1", + Type: "TestEvent", + Data: "test data", + BlockHeight: 1, + Timestamp: time.Now(), + } + + err := store.SaveEvent(event) + if err != nil { + t.Errorf("SaveEvent returned error: %v", err) + } + + store.mu.RLock() + defer store.mu.RUnlock() + savedEvent, exists := store.events["event1"] + if !exists { + t.Errorf("Event not saved") + } + if savedEvent != event { + t.Errorf("Saved event does not match the original") + } +} + +func TestMemoryEventStore_GetEvents(t *testing.T) { + store := NewMemoryEventStore() + event1 := &Event{ + ID: "event1", + Type: "TestEvent", + Data: "data1", + BlockHeight: 1, + Timestamp: time.Now(), + } + event2 := &Event{ + ID: "event2", + Type: "TestEvent", + Data: "data2", + BlockHeight: 2, + Timestamp: time.Now(), + } + + store.SaveEvent(event1) + store.SaveEvent(event2) + + events, err := store.GetEvents(1) + if err != nil { + t.Errorf("GetEvents returned error: %v", err) + } + if len(events) != 2 { + t.Errorf("Expected 2 events, got %d", len(events)) + } + + events, err = store.GetEvents(2) + if err != nil { + t.Errorf("GetEvents returned error: %v", err) + } + if len(events) != 1 { + t.Errorf("Expected 1 event, got %d", len(events)) + } +} + +func TestMemoryEventStore_MarkProcessed(t *testing.T) { + store := NewMemoryEventStore() + event := &Event{ + ID: "event1", + Type: "TestEvent", + Data: "test data", + BlockHeight: 5, + Timestamp: time.Now(), + } + + store.SaveEvent(event) + err := store.MarkProcessed("event1") + if err != nil { + t.Errorf("MarkProcessed returned error: %v", err) + } + + store.mu.RLock() + defer store.mu.RUnlock() + if !store.processedEvents["event1"] { + t.Errorf("Event not marked as processed") + } + if store.lastProcessedHeight != 5 { + t.Errorf("Incorrect last processed height, expected 5, got %d", store.lastProcessedHeight) + } +} + +func TestMemoryEventStore_GetLastProcessedHeight(t *testing.T) { + store := NewMemoryEventStore() + + height, err := store.GetLastProcessedHeight() + if err != nil { + t.Errorf("GetLastProcessedHeight returned error: %v", err) + } + if height != 0 { + t.Errorf("Expected height 0, got %d", height) + } + + store.lastProcessedHeight = 10 + height, err = store.GetLastProcessedHeight() + if err != nil { + t.Errorf("GetLastProcessedHeight returned error: %v", err) + } + if height != 10 { + t.Errorf("Expected height 10, got %d", height) + } +} diff --git a/relayer/chains/stacks/events/system.go b/relayer/chains/stacks/events/system.go index bd6fb069..c3268dea 100644 --- a/relayer/chains/stacks/events/system.go +++ b/relayer/chains/stacks/events/system.go @@ -3,6 +3,7 @@ package events import ( "context" + "github.com/icon-project/centralized-relay/relayer/chains/stacks/interfaces" "go.uber.org/zap" ) @@ -15,12 +16,12 @@ type EventSystem struct { cancel context.CancelFunc } -func NewEventSystem(ctx context.Context, wsURL string, log *zap.Logger) *EventSystem { +func NewEventSystem(ctx context.Context, wsURL string, log *zap.Logger, client interfaces.IClient, senderAddress string, senderKey []byte) *EventSystem { ctx, cancel := context.WithCancel(ctx) store := NewMemoryEventStore() listener := NewEventListener(ctx, wsURL, 1000, log) - processor := NewEventProcessor(ctx, store, listener.processChan, 5, log) + processor := NewEventProcessor(ctx, store, listener.processChan, 5, log, client, senderAddress, senderKey) return &EventSystem{ listener: listener, diff --git a/relayer/chains/stacks/events/types.go b/relayer/chains/stacks/events/types.go index 84fe235c..f109733a 100644 --- a/relayer/chains/stacks/events/types.go +++ b/relayer/chains/stacks/events/types.go @@ -55,26 +55,38 @@ type WSResponse struct { } `json:"error,omitempty"` } -type EmitMessageData struct { - TargetNetwork string `json:"targetNetwork"` - Sn string `json:"sn"` - Msg string `json:"msg"` +type CallMessageSentData struct { + From string `json:"from"` + To string `json:"to"` + Sn uint64 `json:"sn"` + Data string `json:"data"` + Sources []string `json:"sources"` + Destinations []string `json:"destinations"` } type CallMessageData struct { - ReqID string `json:"req_id"` - Sn string `json:"sn"` + From string `json:"from"` + To string `json:"to"` + Sn uint64 `json:"sn"` + ReqID uint64 `json:"req-id"` Data string `json:"data"` } +type ResponseMessageData struct { + Sn uint64 `json:"sn"` + Code uint64 `json:"code"` + Msg string `json:"msg"` +} + type RollbackMessageData struct { - Sn string `json:"sn"` + Sn uint64 `json:"sn"` } const ( - EmitMessage = "message_event" - CallMessage = "call_message_event" - RollbackMessage = "rollback_message_event" + CallMessageSent = "CallMessageSent" + CallMessage = "CallMessage" + ResponseMessage = "ResponseMessage" + RollbackMessage = "RollbackMessage" ) type EventHandler func(event *Event) error diff --git a/relayer/chains/stacks/interfaces/client.go b/relayer/chains/stacks/interfaces/client.go index 2d341168..94a4717f 100644 --- a/relayer/chains/stacks/interfaces/client.go +++ b/relayer/chains/stacks/interfaces/client.go @@ -6,6 +6,7 @@ import ( "github.com/icon-project/stacks-go-sdk/pkg/clarity" blockchainApiClient "github.com/icon-project/stacks-go-sdk/pkg/stacks_blockchain_api_client" + "github.com/icon-project/stacks-go-sdk/pkg/transaction" "go.uber.org/zap" ) @@ -25,6 +26,8 @@ type IClient interface { ExecuteRollback(ctx context.Context, contractAddress string, args []clarity.ClarityValue, senderAddress string, senderKey []byte) (string, error) GetLatestBlock(ctx context.Context) (*blockchainApiClient.GetBlocks200ResponseResultsInner, error) CallReadOnlyFunction(ctx context.Context, contractAddress string, contractName string, functionName string, functionArgs []string) (*string, error) + BroadcastTransaction(ctx context.Context, tx transaction.StacksTransaction) (string, error) + MakeContractCall(context.Context, string, string, string, []clarity.ClarityValue, string, []byte) (*transaction.ContractCallTransaction, error) GetWebSocketURL() string Log() *zap.Logger } diff --git a/relayer/chains/stacks/listener.go b/relayer/chains/stacks/listener.go index b857e013..e1f00e60 100644 --- a/relayer/chains/stacks/listener.go +++ b/relayer/chains/stacks/listener.go @@ -15,7 +15,7 @@ func (p *Provider) Listener(ctx context.Context, lastProcessedTx providerTypes.L wsURL := p.client.GetWebSocketURL() p.log.Debug("Using WebSocket URL", zap.String("url", wsURL)) - eventSystem := events.NewEventSystem(ctx, wsURL, p.log) + eventSystem := events.NewEventSystem(ctx, wsURL, p.log, p.client, p.cfg.GetWallet(), p.privateKey) eventSystem.OnEvent(func(event *events.Event) error { msg, err := p.getRelayMessageFromEvent(event.Type, event.Data) diff --git a/relayer/chains/stacks/mocks/client_mock.go b/relayer/chains/stacks/mocks/client_mock.go index b0ea95c9..42897804 100644 --- a/relayer/chains/stacks/mocks/client_mock.go +++ b/relayer/chains/stacks/mocks/client_mock.go @@ -6,6 +6,7 @@ import ( "github.com/icon-project/stacks-go-sdk/pkg/clarity" blockchainApiClient "github.com/icon-project/stacks-go-sdk/pkg/stacks_blockchain_api_client" + "github.com/icon-project/stacks-go-sdk/pkg/transaction" "github.com/stretchr/testify/mock" "go.uber.org/zap" ) @@ -89,6 +90,24 @@ func (m *MockClient) ExecuteRollback(ctx context.Context, contractAddress string return mockArgs.String(0), mockArgs.Error(1) } +func (m *MockClient) MakeContractCall( + ctx context.Context, + contractAddress string, + contractName string, + functionName string, + args []clarity.ClarityValue, + senderAddress string, + senderKey []byte, +) (*transaction.ContractCallTransaction, error) { + mockArgs := m.Called(ctx, contractAddress, contractName, functionName, args, senderAddress, senderKey) + return mockArgs.Get(0).(*transaction.ContractCallTransaction), mockArgs.Error(1) +} + +func (m *MockClient) BroadcastTransaction(ctx context.Context, tx transaction.StacksTransaction) (string, error) { + mockArgs := m.Called(ctx, tx) + return mockArgs.String(0), mockArgs.Error(1) +} + func (m *MockClient) GetWebSocketURL() string { mockArgs := m.Called() return mockArgs.String(0) diff --git a/relayer/chains/stacks/provider_test.go b/relayer/chains/stacks/provider_test.go index 574826b7..ffafd13d 100644 --- a/relayer/chains/stacks/provider_test.go +++ b/relayer/chains/stacks/provider_test.go @@ -2,18 +2,15 @@ package stacks import ( "context" - "fmt" "math/big" "os" "path/filepath" "testing" - "time" "github.com/icon-project/centralized-relay/relayer/chains/stacks/mocks" "github.com/icon-project/centralized-relay/relayer/events" "github.com/icon-project/centralized-relay/relayer/provider" providerTypes "github.com/icon-project/centralized-relay/relayer/types" - "github.com/icon-project/stacks-go-sdk/pkg/clarity" blockchainApiClient "github.com/icon-project/stacks-go-sdk/pkg/stacks_blockchain_api_client" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -145,132 +142,6 @@ func TestProvider_ClaimFee(t *testing.T) { mockClient.AssertExpectations(t) } -func TestProvider_SetAdmin(t *testing.T) { - provider, mockClient := setupTestProvider(t) - - newAdmin := "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM" - expectedTxID := "0x123456789" - - var hash160 [20]byte - copy(hash160[:], []byte("ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH")) - currentImpl, err := clarity.NewContractPrincipal(0, hash160, "xcall-impl") - assert.NoError(t, err) - - mockClient.On("GetCurrentImplementation", mock.Anything, provider.cfg.Contracts[providerTypes.XcallContract]). - Return(currentImpl, nil).Once() - - mockClient.On("SetAdmin", - mock.Anything, - provider.cfg.Contracts[providerTypes.XcallContract], - newAdmin, - currentImpl, - provider.cfg.Address, - provider.privateKey, - ).Return(expectedTxID, nil).Once() - - successStatus := "success" - mockResponse := &blockchainApiClient.GetTransactionById200Response{ - GetTransactionList200ResponseResultsInner: &blockchainApiClient.GetTransactionList200ResponseResultsInner{ - ContractCallTransaction: &blockchainApiClient.ContractCallTransaction{ - TxId: expectedTxID, - BlockHeight: 1234, - TxStatus: blockchainApiClient.TokenTransferTransactionTxStatus{ - String: &successStatus, - }, - Canonical: true, - }, - }, - } - mockClient.On("GetTransactionById", mock.Anything, expectedTxID). - Return(mockResponse, nil).Once() - - err = provider.SetAdmin(context.Background(), newAdmin) - assert.NoError(t, err, "SetAdmin should execute without error") - - mockClient.AssertExpectations(t) -} - -func TestProvider_MessageReceived(t *testing.T) { - provider, mockClient := setupTestProvider(t) - - tests := []struct { - name string - key *providerTypes.MessageKey - mockSetup func() - expected bool - expectErr bool - }{ - { - name: "EmitMessage Success", - key: &providerTypes.MessageKey{ - EventType: events.EmitMessage, - Src: "icon", - Sn: big.NewInt(12345), - }, - mockSetup: func() { - mockClient.On("GetReceipt", - mock.Anything, - provider.cfg.Contracts[providerTypes.ConnectionContract], - "icon", - big.NewInt(12345), - ).Return(true, nil).Once() - }, - expected: true, - expectErr: false, - }, - { - name: "CallMessage Returns False", - key: &providerTypes.MessageKey{ - EventType: events.CallMessage, - Src: "icon", - Sn: big.NewInt(12345), - }, - mockSetup: func() {}, - expected: false, - expectErr: false, - }, - { - name: "RollbackMessage Returns False", - key: &providerTypes.MessageKey{ - EventType: events.RollbackMessage, - Src: "icon", - Sn: big.NewInt(12345), - }, - mockSetup: func() {}, - expected: false, - expectErr: false, - }, - { - name: "Unknown Event Type", - key: &providerTypes.MessageKey{ - EventType: "unknown", - Src: "icon", - Sn: big.NewInt(12345), - }, - mockSetup: func() {}, - expected: true, - expectErr: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.mockSetup() - - received, err := provider.MessageReceived(context.Background(), tt.key) - - if tt.expectErr { - assert.Error(t, err) - } else { - assert.NoError(t, err) - assert.Equal(t, tt.expected, received) - } - }) - } - - mockClient.AssertExpectations(t) -} - func TestProvider_RestoreKeystore(t *testing.T) { provider, _ := setupTestProvider(t) mockKMS := new(mocks.MockKMS) @@ -487,70 +358,6 @@ func TestProviderConfig_GetWallet(t *testing.T) { assert.Equal(t, cfg.Address, address) } -func TestProvider_QueryTransactionReceipt(t *testing.T) { - provider, mockClient := setupTestProvider(t) - - txID := "0x123456789" - - t.Run("Mempool Transaction", func(t *testing.T) { - pendingStatus := "pending" - response := &blockchainApiClient.GetTransactionById200Response{ - GetMempoolTransactionList200ResponseResultsInner: &blockchainApiClient.GetMempoolTransactionList200ResponseResultsInner{ - ContractCallMempoolTransaction1: &blockchainApiClient.ContractCallMempoolTransaction1{ - TxId: txID, - TxStatus: blockchainApiClient.TokenTransferMempoolTransaction1TxStatus{ - String: &pendingStatus, - }, - }, - }, - } - - mockClient.On("GetTransactionById", mock.Anything, txID).Return(response, nil).Once() - - receipt, err := provider.QueryTransactionReceipt(context.Background(), txID) - assert.NoError(t, err) - assert.NotNil(t, receipt) - assert.Equal(t, txID, receipt.TxHash) - assert.Equal(t, uint64(0), receipt.Height) - }) - - t.Run("Confirmed Transaction", func(t *testing.T) { - successStatus := "success" - response := &blockchainApiClient.GetTransactionById200Response{ - GetTransactionList200ResponseResultsInner: &blockchainApiClient.GetTransactionList200ResponseResultsInner{ - ContractCallTransaction: &blockchainApiClient.ContractCallTransaction{ - TxId: txID, - BlockHeight: 1234, - TxStatus: blockchainApiClient.TokenTransferTransactionTxStatus{ - String: &successStatus, - }, - Canonical: true, - }, - }, - } - - mockClient.On("GetTransactionById", mock.Anything, txID).Return(response, nil).Once() - - receipt, err := provider.QueryTransactionReceipt(context.Background(), txID) - assert.NoError(t, err) - assert.NotNil(t, receipt) - assert.Equal(t, txID, receipt.TxHash) - assert.Equal(t, uint64(1234), receipt.Height) - assert.True(t, receipt.Status) - }) - - t.Run("Error Case", func(t *testing.T) { - mockClient.On("GetTransactionById", mock.Anything, txID). - Return((*blockchainApiClient.GetTransactionById200Response)(nil), fmt.Errorf("transaction not found")).Once() - - receipt, err := provider.QueryTransactionReceipt(context.Background(), txID) - assert.Error(t, err) - assert.Nil(t, receipt) - }) - - mockClient.AssertExpectations(t) -} - func TestProvider_ShouldReceiveMessage(t *testing.T) { provider, _ := setupTestProvider(t) @@ -579,72 +386,6 @@ func TestProvider_ShouldSendMessage(t *testing.T) { assert.True(t, should) } -func TestProvider_WaitForTransactionConfirmation(t *testing.T) { - provider, mockClient := setupTestProvider(t) - - txID := "0x123456789" - - t.Run("Successful Confirmation", func(t *testing.T) { - successStatus := "success" - response := &blockchainApiClient.GetTransactionById200Response{ - GetTransactionList200ResponseResultsInner: &blockchainApiClient.GetTransactionList200ResponseResultsInner{ - ContractCallTransaction: &blockchainApiClient.ContractCallTransaction{ - TxId: txID, - BlockHeight: 1234, - TxStatus: blockchainApiClient.TokenTransferTransactionTxStatus{ - String: &successStatus, - }, - Canonical: true, - }, - }, - } - - mockClient.On("GetTransactionById", mock.Anything, txID).Return(response, nil) - - receipt, err := provider.waitForTransactionConfirmation(context.Background(), txID, MAX_WAIT_TIME) - assert.NoError(t, err) - assert.NotNil(t, receipt) - assert.Equal(t, txID, receipt.TxHash) - assert.True(t, receipt.Status) - assert.Equal(t, uint64(1234), receipt.Height) - }) - - t.Run("Context Cancellation", func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - cancel() - - _, err := provider.waitForTransactionConfirmation(ctx, txID, MAX_WAIT_TIME) - assert.Error(t, err) - assert.Equal(t, context.Canceled, err) - }) - - t.Run("Timeout", func(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) - defer cancel() - - pendingStatus := "pending" - pendingResponse := &blockchainApiClient.GetTransactionById200Response{ - GetMempoolTransactionList200ResponseResultsInner: &blockchainApiClient.GetMempoolTransactionList200ResponseResultsInner{ - ContractCallMempoolTransaction1: &blockchainApiClient.ContractCallMempoolTransaction1{ - TxId: txID, - TxStatus: blockchainApiClient.TokenTransferMempoolTransaction1TxStatus{ - String: &pendingStatus, - }, - }, - }, - } - - mockClient.On("GetTransactionById", mock.Anything, txID).Return(pendingResponse, nil) - - timeoutDuration := 100 * time.Millisecond - _, err := provider.waitForTransactionConfirmation(ctx, txID, timeoutDuration) - assert.Error(t, err) - assert.Contains(t, err.Error(), "transaction confirmation timed out") - }) - - mockClient.AssertExpectations(t) -} - func TestProvider_ImportKeystore(t *testing.T) { provider, _ := setupTestProvider(t) mockKMS := new(mocks.MockKMS) diff --git a/relayer/chains/stacks/query.go b/relayer/chains/stacks/query.go index 8771ba43..7a83139d 100644 --- a/relayer/chains/stacks/query.go +++ b/relayer/chains/stacks/query.go @@ -21,10 +21,12 @@ func (p *Provider) ShouldSendMessage(ctx context.Context, message *providerTypes func (p *Provider) MessageReceived(ctx context.Context, key *providerTypes.MessageKey) (bool, error) { switch key.EventType { - case events.EmitMessage: + case events.CallMessageSent: return p.client.GetReceipt(ctx, p.cfg.Contracts[providerTypes.ConnectionContract], key.Src, key.Sn) case events.CallMessage: return false, nil + case events.ResponseMessage: + return false, nil case events.RollbackMessage: return false, nil default: @@ -186,7 +188,7 @@ func (p *Provider) GenerateMessages(ctx context.Context, fromHeight uint64, toHe errorChan := make(chan error, 1) wsURL := p.client.GetWebSocketURL() - eventSystem := events.NewEventSystem(ctx, wsURL, p.log) + eventSystem := events.NewEventSystem(ctx, wsURL, p.log, p.client, p.cfg.GetWallet(), p.privateKey) eventSystem.OnEvent(func(event *events.Event) error { if event.BlockHeight < fromHeight || event.BlockHeight > toHeight { diff --git a/relayer/chains/stacks/stacks_test.go b/relayer/chains/stacks/stacks_test.go deleted file mode 100644 index 7fc377dd..00000000 --- a/relayer/chains/stacks/stacks_test.go +++ /dev/null @@ -1,79 +0,0 @@ -package stacks_test - -import ( - "context" - "math/big" - "testing" - "time" - - "github.com/icon-project/centralized-relay/relayer/chains/stacks" - "github.com/icon-project/centralized-relay/relayer/events" - "github.com/icon-project/centralized-relay/relayer/provider" - providerTypes "github.com/icon-project/centralized-relay/relayer/types" - "github.com/stretchr/testify/assert" - "go.uber.org/zap" -) - -func setupTestStacksProvider(t *testing.T) *stacks.Provider { - logger, _ := zap.NewDevelopment() - cfg := &stacks.Config{ - CommonConfig: provider.CommonConfig{ - RPCUrl: "https://stacks-node-api.testnet.stacks.co", - Contracts: providerTypes.ContractConfigMap{ - "XcallContract": "ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH.xcall-proxy", - "ConnectionContract": "ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH.centralized-connection", - }, - NID: "stacks_testnet", - }, - } - - p, err := cfg.NewProvider(context.Background(), logger, "/tmp/relayer", false, "stacks_testnet") - assert.NoError(t, err) - assert.NotNil(t, p) - - return p.(*stacks.Provider) -} - -func TestGenerateMessages(t *testing.T) { - p := setupTestStacksProvider(t) - - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) - defer cancel() - - fromHeight := uint64(12345) - toHeight := uint64(12345) - - messages, err := p.GenerateMessages(ctx, fromHeight, toHeight) - assert.NoError(t, err) - assert.NotEmpty(t, messages) - - for _, msg := range messages { - t.Logf("Generated message: %+v", msg) - assert.GreaterOrEqual(t, msg.MessageHeight, fromHeight) - assert.LessOrEqual(t, msg.MessageHeight, toHeight) - } -} - -func TestRoute(t *testing.T) { - p := setupTestStacksProvider(t) - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) - defer cancel() - - message := &providerTypes.Message{ - Dst: "stacks_testnet", - Src: "icon_testnet", - Sn: big.NewInt(12345), - EventType: events.EmitMessage, - Data: []byte("Hello, Stacks!"), - } - - callback := func(key *providerTypes.MessageKey, response *providerTypes.TxResponse, err error) { - assert.NoError(t, err) - assert.NotNil(t, response) - assert.Equal(t, providerTypes.Success, response.Code) - } - - err := p.Route(ctx, message, callback) - assert.NoError(t, err) -} diff --git a/test/chains/stacks/remotenet.go b/test/chains/stacks/remotenet.go index b8e7ec00..b5f8a2ef 100644 --- a/test/chains/stacks/remotenet.go +++ b/test/chains/stacks/remotenet.go @@ -9,7 +9,6 @@ import ( "time" stacksClient "github.com/icon-project/centralized-relay/relayer/chains/stacks" - "github.com/icon-project/centralized-relay/relayer/chains/stacks/events" "github.com/icon-project/centralized-relay/relayer/kms" "github.com/icon-project/centralized-relay/test/chains" "github.com/icon-project/centralized-relay/test/interchaintest/relayer/centralized" @@ -17,6 +16,7 @@ import ( "github.com/icon-project/stacks-go-sdk/pkg/clarity" "github.com/icon-project/stacks-go-sdk/pkg/crypto" "github.com/icon-project/stacks-go-sdk/pkg/stacks" + blockchainApiClient "github.com/icon-project/stacks-go-sdk/pkg/stacks_blockchain_api_client" "github.com/icon-project/stacks-go-sdk/pkg/transaction" "go.uber.org/zap" "gopkg.in/yaml.v3" @@ -142,8 +142,8 @@ func (s *StacksLocalnet) SetupXCall(ctx context.Context) error { {"centralized-connection", "connection", true, nil}, - {"xcall-impl-v3", "xcall-impl", true, func(proxyAddr string) error { - implAddr := senderAddress + ".xcall-impl-v3" + {"xcall-impl-v5", "xcall-impl", true, func(proxyAddr string) error { + implAddr := senderAddress + ".xcall-impl-v5" implPrincipal, err := clarity.StringToPrincipal(implAddr) if err != nil { return fmt.Errorf("failed to convert implementation address to principal: %w", err) @@ -216,8 +216,8 @@ func (s *StacksLocalnet) SetupXCall(ctx context.Context) error { } connectionContractName := "centralized-connection" - implContractName := "xcall-impl-v3" - proxyContractName := "xcall-impl-v3" + implContractName := "xcall-impl-v5" + proxyContractName := "xcall-proxy" s.IBCAddresses["xcall-proxy"] = senderAddress + "." + proxyContractName s.IBCAddresses["xcall-impl"] = senderAddress + "." + implContractName @@ -288,7 +288,7 @@ func (s *StacksLocalnet) SetupXCall(ctx context.Context) error { } s.IBCAddresses["xcall-proxy"] = deployedContracts["xcall-proxy"] - s.IBCAddresses["xcall-impl"] = deployedContracts["xcall-impl-v3"] + s.IBCAddresses["xcall-impl"] = deployedContracts["xcall-impl-v5"] s.IBCAddresses["connection"] = deployedContracts["centralized-connection"] return nil @@ -308,7 +308,7 @@ func (s *StacksLocalnet) setDefaultConnection(ctx context.Context, privateKey [] return fmt.Errorf("failed to create connection address argument: %w", err) } - implAddr := senderAddress + "." + "xcall-impl-v3" + implAddr := senderAddress + "." + "xcall-impl-v5" implPrincipal, err := clarity.StringToPrincipal(implAddr) if err != nil { return fmt.Errorf("failed to convert implementation address to principal: %w", err) @@ -369,7 +369,7 @@ func (s *StacksLocalnet) initializeXCallImpl(ctx context.Context, privateKey []b txCall, err := transaction.MakeContractCall( senderAddress, - "xcall-impl-v3", + "xcall-impl-v5", "init", args, *s.network, @@ -505,7 +505,7 @@ func (s *StacksLocalnet) setAdminXCallImpl(ctx context.Context, privateKey []byt txCall, err := transaction.MakeContractCall( senderAddress, - "xcall-impl-v3", + "xcall-impl-v5", "set-admin", args, *s.network, @@ -1186,194 +1186,218 @@ func (s *StacksLocalnet) extractSnFromTransaction(ctx context.Context, txID stri return "", fmt.Errorf("serial number 'sn' not found in transaction events") } -func (s *StacksLocalnet) FindCallMessage(ctx context.Context, startHeight uint64, from, to, sn string) (string, string, error) { - ctx, cancel := context.WithTimeout(ctx, 2*time.Minute) - defer cancel() - - resultChan := make(chan struct { - txID string - data string - }, 1) +func (s *StacksLocalnet) FindEvent(ctx context.Context, startHeight uint64, contract, signature string, index []string) (*blockchainApiClient.SmartContractLogTransactionEvent, error) { + for { + select { + case <-ctx.Done(): + return nil, fmt.Errorf("context cancelled while finding event %s", signature) + default: + events, err := s.client.GetContractEvents(ctx, contract, 50, 0) + if err != nil { + return nil, fmt.Errorf("failed to get contract events: %w", err) + } - wsURL := s.client.GetWebSocketURL() - eventSystem := events.NewEventSystem(ctx, wsURL, s.log) + for _, event := range events.Results { + if event.SmartContractLogTransactionEvent != nil && + event.SmartContractLogTransactionEvent.ContractLog.Topic == signature { + return event.SmartContractLogTransactionEvent, nil + } + } - eventSystem.OnEvent(func(event *events.Event) error { - if event.Type != stacksClient.CallMessage { - return nil + time.Sleep(BLOCK_TIME) } + } +} - if data, ok := event.Data.(events.CallMessageData); ok { - if data.Sn == sn { - select { - case resultChan <- struct { - txID string - data string - }{ - txID: data.ReqID, - data: data.Data, - }: - case <-ctx.Done(): - } +func (s *StacksLocalnet) FindCallMessage(ctx context.Context, startHeight uint64, from, to, sn string) (string, string, error) { + for { + select { + case <-ctx.Done(): + return "", "", fmt.Errorf("context cancelled while finding call message with sn %s", sn) + default: + events, err := s.client.GetContractEvents(ctx, s.IBCAddresses["xcall-proxy"], 50, 0) + if err != nil { + return "", "", fmt.Errorf("failed to get contract events: %w", err) } - } - return nil - }) - if err := eventSystem.Start(); err != nil { - return "", "", fmt.Errorf("failed to start event system: %w", err) - } - defer eventSystem.Stop() + for _, event := range events.Results { + if event.SmartContractLogTransactionEvent != nil { + log := event.SmartContractLogTransactionEvent.ContractLog + if log.Topic == "print" && strings.Contains(log.Value.Repr, "CallMessage") { + eventSn := extractSnFromEvent(log.Value.Repr) + if eventSn == sn { + reqId, data := extractCallMessageData(log.Value.Repr) + if reqId != "" && data != "" { + return reqId, data, nil + } + } + } + } + } - select { - case result := <-resultChan: - return result.txID, result.data, nil - case <-ctx.Done(): - if ctx.Err() == context.DeadlineExceeded { - return "", "", fmt.Errorf("find call message timed out") + time.Sleep(BLOCK_TIME) } - return "", "", ctx.Err() } } func (s *StacksLocalnet) FindCallResponse(ctx context.Context, startHeight uint64, sn string) (string, error) { - ctx, cancel := context.WithTimeout(ctx, 2*time.Minute) - defer cancel() - - resultChan := make(chan string, 1) - - wsURL := s.client.GetWebSocketURL() - eventSystem := events.NewEventSystem(ctx, wsURL, s.log) - - eventSystem.OnEvent(func(event *events.Event) error { - if event.Type != stacksClient.CallMessage { - return nil - } + for { + select { + case <-ctx.Done(): + return "", fmt.Errorf("context cancelled while finding call response with sn %s", sn) + default: + events, err := s.client.GetContractEvents(ctx, s.IBCAddresses["xcall-proxy"], 50, 0) + if err != nil { + return "", fmt.Errorf("failed to get contract events: %w", err) + } - if data, ok := event.Data.(events.CallMessageData); ok { - if data.Sn == sn { - select { - case resultChan <- data.ReqID: - case <-ctx.Done(): + for _, event := range events.Results { + if event.SmartContractLogTransactionEvent != nil { + log := event.SmartContractLogTransactionEvent.ContractLog + if log.Topic == "print" && strings.Contains(log.Value.Repr, "CallResponse") { + eventSn := extractSnFromEvent(log.Value.Repr) + if eventSn == sn { + return event.SmartContractLogTransactionEvent.TxId, nil + } + } } } - } - return nil - }) - if err := eventSystem.Start(); err != nil { - return "", fmt.Errorf("failed to start event system: %w", err) - } - defer eventSystem.Stop() - - select { - case txID := <-resultChan: - return txID, nil - case <-ctx.Done(): - if ctx.Err() == context.DeadlineExceeded { - return "", fmt.Errorf("find call response timed out") + time.Sleep(BLOCK_TIME) } - return "", ctx.Err() } } func (s *StacksLocalnet) FindRollbackExecutedMessage(ctx context.Context, startHeight uint64, sn string) (string, error) { - ctx, cancel := context.WithTimeout(ctx, 2*time.Minute) - defer cancel() - - resultChan := make(chan string, 1) - - wsURL := s.client.GetWebSocketURL() - eventSystem := events.NewEventSystem(ctx, wsURL, s.log) - - eventSystem.OnEvent(func(event *events.Event) error { - if event.Type != stacksClient.RollbackMessage { - return nil - } + for { + select { + case <-ctx.Done(): + return "", fmt.Errorf("context cancelled while finding rollback message with sn %s", sn) + default: + events, err := s.client.GetContractEvents(ctx, s.IBCAddresses["xcall-proxy"], 50, 0) + if err != nil { + return "", fmt.Errorf("failed to get contract events: %w", err) + } - if data, ok := event.Data.(events.RollbackMessageData); ok { - if data.Sn == sn { - select { - case resultChan <- data.Sn: - case <-ctx.Done(): + for _, event := range events.Results { + if event.SmartContractLogTransactionEvent != nil { + log := event.SmartContractLogTransactionEvent.ContractLog + if log.Topic == "print" && strings.Contains(log.Value.Repr, "RollbackExecuted") { + eventSn := extractSnFromEvent(log.Value.Repr) + if eventSn == sn { + return sn, nil + } + } } } - } - return nil - }) - if err := eventSystem.Start(); err != nil { - return "", fmt.Errorf("failed to start event system: %w", err) - } - defer eventSystem.Stop() - - select { - case txID := <-resultChan: - return txID, nil - case <-ctx.Done(): - if ctx.Err() == context.DeadlineExceeded { - return "", fmt.Errorf("find rollback message timed out") + time.Sleep(BLOCK_TIME) } - return "", ctx.Err() } } func (s *StacksLocalnet) FindTargetXCallMessage(ctx context.Context, target chains.Chain, height uint64, to string) (*chains.XCallResponse, error) { - ctx, cancel := context.WithTimeout(ctx, 2*time.Minute) - defer cancel() - - resultChan := make(chan *chains.XCallResponse, 1) - - wsURL := s.client.GetWebSocketURL() - eventSystem := events.NewEventSystem(ctx, wsURL, s.log) - - eventSystem.OnEvent(func(event *events.Event) error { - var response *chains.XCallResponse + for { + select { + case <-ctx.Done(): + return nil, fmt.Errorf("context cancelled while finding target xcall message") + default: + events, err := s.client.GetContractEvents(ctx, s.IBCAddresses["xcall-proxy"], 50, 0) + if err != nil { + return nil, fmt.Errorf("failed to get contract events: %w", err) + } - switch event.Type { - case stacksClient.EmitMessage: - if data, ok := event.Data.(events.EmitMessageData); ok { - if data.TargetNetwork == to { - response = &chains.XCallResponse{ - SerialNo: data.Sn, - Data: data.Msg, + for _, event := range events.Results { + if event.SmartContractLogTransactionEvent != nil { + log := event.SmartContractLogTransactionEvent.ContractLog + if log.Topic == "print" { + if strings.Contains(log.Value.Repr, "EmitMessage") { + sn, msg, targetNetwork := extractEmitMessageData(log.Value.Repr) + if targetNetwork == to { + return &chains.XCallResponse{ + SerialNo: sn, + Data: msg, + }, nil + } + } else if strings.Contains(log.Value.Repr, "CallMessage") { + sn, reqId, data := extractFullCallMessageData(log.Value.Repr) + return &chains.XCallResponse{ + SerialNo: sn, + RequestID: reqId, + Data: data, + }, nil + } } } } - case stacksClient.CallMessage: - if data, ok := event.Data.(events.CallMessageData); ok { - response = &chains.XCallResponse{ - SerialNo: data.Sn, - RequestID: data.ReqID, - Data: data.Data, - } - } + time.Sleep(BLOCK_TIME) } + } +} - if response != nil { - select { - case resultChan <- response: - case <-ctx.Done(): - } +func extractSnFromEvent(repr string) string { + startIdx := strings.Index(repr, "(sn u") + if startIdx != -1 { + startIdx += 5 // Move past "(sn u" + endIdx := strings.Index(repr[startIdx:], ")") + if endIdx != -1 { + return repr[startIdx : startIdx+endIdx] } - return nil - }) + } + return "" +} - if err := eventSystem.Start(); err != nil { - return nil, fmt.Errorf("failed to start event system: %w", err) +func extractCallMessageData(repr string) (reqId, data string) { + reqIdStart := strings.Index(repr, "reqId u") + if reqIdStart != -1 { + reqIdStart += 7 + reqIdEnd := strings.Index(repr[reqIdStart:], " ") + if reqIdEnd != -1 { + reqId = repr[reqIdStart : reqIdStart+reqIdEnd] + } } - defer eventSystem.Stop() - select { - case response := <-resultChan: - return response, nil - case <-ctx.Done(): - if ctx.Err() == context.DeadlineExceeded { - return nil, fmt.Errorf("find target message timed out") + dataStart := strings.Index(repr, "data 0x") + if dataStart != -1 { + dataStart += 7 + dataEnd := strings.Index(repr[dataStart:], ")") + if dataEnd != -1 { + data = repr[dataStart : dataStart+dataEnd] } - return nil, ctx.Err() } + + return reqId, data +} + +func extractEmitMessageData(repr string) (sn, msg, targetNetwork string) { + sn = extractSnFromEvent(repr) + + msgStart := strings.Index(repr, "msg 0x") + if msgStart != -1 { + msgStart += 6 + msgEnd := strings.Index(repr[msgStart:], " ") + if msgEnd != -1 { + msg = repr[msgStart : msgStart+msgEnd] + } + } + + networkStart := strings.Index(repr, "network \"") + if networkStart != -1 { + networkStart += 9 + networkEnd := strings.Index(repr[networkStart:], "\"") + if networkEnd != -1 { + targetNetwork = repr[networkStart : networkStart+networkEnd] + } + } + + return sn, msg, targetNetwork +} + +func extractFullCallMessageData(repr string) (sn, reqId, data string) { + sn = extractSnFromEvent(repr) + reqId, data = extractCallMessageData(repr) + return sn, reqId, data } func (s *StacksLocalnet) loadPrivateKey(keystoreFile, password string) ([]byte, string, error) { diff --git a/test/sample-config.yaml b/test/sample-config.yaml index 863d42ab..6db43f9d 100644 --- a/test/sample-config.yaml +++ b/test/sample-config.yaml @@ -72,7 +72,7 @@ chains: - name: icon version: "3" environment: remote - rpc_uri: https://lisbon.net.solidwallet.io/api/v3 + rpc_uri: https://lisbon.net.solidwallet.io/api/v3/ keystore_file: godwallet.json keystore_password: gochain relay_wallet : hxb6b5791be0b5ef67063b3c10b840fb81514db2fd From af91fb31db59e7a933e6697ffb6949dec9064504 Mon Sep 17 00:00:00 2001 From: CyrusVorwald <90732384+CyrusVorwald@users.noreply.github.com> Date: Wed, 13 Nov 2024 22:42:49 -0500 Subject: [PATCH 9/9] fix: add contract address to subscription params --- go.work.sum | 18 + relayer/chains/stacks/client.go | 32 +- relayer/chains/stacks/client_test.go | 62 + relayer/chains/stacks/events/listener.go | 68 +- relayer/chains/stacks/events/processor.go | 16 +- relayer/chains/stacks/events/system.go | 4 +- relayer/chains/stacks/interfaces/client.go | 1 + relayer/chains/stacks/listener.go | 2 +- relayer/chains/stacks/listener_test.go | 336 ------ relayer/chains/stacks/mocks/client_mock.go | 5 + relayer/chains/stacks/query.go | 2 +- test/chains/stacks/events.go | 225 ++++ test/chains/stacks/initialization.go | 959 +++++++++++++++ test/chains/stacks/remotenet.go | 1272 -------------------- test/chains/stacks/utils.go | 123 ++ 15 files changed, 1489 insertions(+), 1636 deletions(-) delete mode 100644 relayer/chains/stacks/listener_test.go create mode 100644 test/chains/stacks/events.go create mode 100644 test/chains/stacks/initialization.go create mode 100644 test/chains/stacks/utils.go diff --git a/go.work.sum b/go.work.sum index 9ae36b41..49733bdc 100644 --- a/go.work.sum +++ b/go.work.sum @@ -172,6 +172,11 @@ cosmossdk.io/x/upgrade v0.1.0/go.mod h1:/6jjNGbiPCNtmA1N+rBtP601sr0g4ZXuj3yC6ClP dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= firebase.google.com/go v3.12.0+incompatible/go.mod h1:xlah6XbEyW6tbfSklcfe5FHJIwjt8toICdV5Wh9ptHs= gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= +gioui.org v0.2.0/go.mod h1:1H72sKEk/fNFV+l0JNeM2Dt3co3Y4uaQcD+I+/GQ0e4= +gioui.org/cpu v0.0.0-20220412190645-f1e9e8c3b1f7/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ= +gioui.org/shader v1.0.6/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM= +gioui.org/x v0.2.0/go.mod h1:rCGN2nZ8ZHqrtseJoQxCMZpt2xrZUrdZ2WuMRLBJmYs= +git.sr.ht/~sbinet/cmpimg v0.1.0/go.mod h1:FU12psLbF4TfNXkKH2ZZQ29crIqoiqTZmeQ7dkp/pxE= git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= git.sr.ht/~sbinet/gg v0.5.0/go.mod h1:G2C0eRESqlKhS7ErsNey6HHrqU1PwsnCQlekFi9Q2Oo= github.com/2opremio/pretty v0.2.2-0.20230601220618-e1d5758b2a95/go.mod h1:Gv4NIpY67KDahg+DtIG5/2Ok4l8vzYEekiirSCH+IGA= @@ -191,6 +196,7 @@ github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDm github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= github.com/ChainSafe/go-schnorrkel v1.0.0 h1:3aDA67lAykLaG1y3AOjs88dMxC88PgUuHRrLeDnvGIM= github.com/ChainSafe/go-schnorrkel v1.0.0/go.mod h1:dpzHYVxLZcp8pjlV+O+UR8K0Hp/z7vcchBSbMBEhCw4= github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= @@ -250,6 +256,7 @@ github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HR github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/stroke v0.0.0-20221221101821-bd29b49d73f0/go.mod h1:ccdDYaY5+gO+cbnQdFxEXqfy0RkoV25H3jLXUDNM3wg= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/apache/arrow/go/v15 v15.0.2/go.mod h1:DGXsR3ajT524njufqf95822i+KTh+yea1jass9YXgjA= github.com/araddon/gou v0.0.0-20190110011759-c797efecbb61/go.mod h1:ikc1XA58M+Rx7SEbf0bLJCfBkwayZ8T5jBo5FXK8Uz8= @@ -489,17 +496,21 @@ github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgoo github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= +github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-critic/go-critic v0.6.5/go.mod h1:ezfP/Lh7MA6dBNn4c6ab5ALv3sKnZVLx37tr00uuaOY= github.com/go-critic/go-critic v0.7.0/go.mod h1:moYzd7GdVXE2C2hYTwd7h0CPcqlUeclsyBRwMa38v64= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= +github.com/go-fonts/dejavu v0.3.2/go.mod h1:m+TzKY7ZEl09/a17t1593E4VYW8L1VaBXHzFZOIjGEY= github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= +github.com/go-fonts/latin-modern v0.3.2/go.mod h1:9odJt4NbRrbdj4UAMuLVd4zEukf6aAEKnDaQga0whqQ= github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= github.com/go-fonts/liberation v0.3.2/go.mod h1:N0QsDLVUQPy3UYg9XAc3Uh3UDMp2Z7M1o4+X98dXkmI= github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= +github.com/go-fonts/stix v0.2.2/go.mod h1:SUxggC9dxd/Q+rb5PkJuvfvTbOPtNc2Qaua00fIp9iU= github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= @@ -527,6 +538,7 @@ github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-text/typesetting v0.0.0-20230803102845-24e03d8b5372/go.mod h1:evDBbvNR/KaVFZ2ZlDSOWWXIUKq0wCOEtzLxRM8SG3k= github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU= github.com/go-toolsmith/astcopy v1.0.2/go.mod h1:4TcEdbElGc9twQEYpVo/aieIXfHhiuLh4aLAck6dO7Y= github.com/go-toolsmith/astcopy v1.1.0/go.mod h1:hXM6gan18VA1T/daUEHCFcYiW8Ai1tIwIzHY6srfEAw= @@ -619,6 +631,8 @@ github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Rep github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= +github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= +github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= github.com/guptarohit/asciigraph v0.5.5/go.mod h1:dYl5wwK4gNsnFf9Zp+l06rFiDZ5YtXM6x7SRWZ3KGag= github.com/guregu/null v4.0.0+incompatible/go.mod h1:ePGpQaN9cw0tj45IR5E5ehMvsFlLlQZAkkOXZurJ3NM= github.com/hashicorp/consul/api v1.14.0/go.mod h1:bcaw5CSZ7NE9qfOfKCI1xb7ZKjzu/MyvQkCLTfqLqxQ= @@ -778,6 +792,7 @@ github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= +github.com/lyft/protoc-gen-star/v2 v2.0.4-0.20230330145011-496ad1ac90a4/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18= @@ -804,6 +819,7 @@ github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGw github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= @@ -845,6 +861,7 @@ github.com/moricho/tparallel v0.3.0/go.mod h1:leENX2cUv7Sv2qDgdi0D0fCftN8fRC67Bc github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/mozilla/tls-observatory v0.0.0-20210609171429-7bc42856d2e5/go.mod h1:FUqVoUPHSEdDR0MnFM3Dh8AU0pZHLXUD127SAJGER/s= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/mrunalp/fileutils v0.5.1/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= @@ -1210,6 +1227,7 @@ golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQz golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= +golang.org/x/exp/shiny v0.0.0-20230801115018-d63ba01acd4b/go.mod h1:UH99kUObWAZkDnWqppdQe5ZhPYESUw8I0zVV1uWBR+0= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= diff --git a/relayer/chains/stacks/client.go b/relayer/chains/stacks/client.go index 33f3e3b8..505528b0 100644 --- a/relayer/chains/stacks/client.go +++ b/relayer/chains/stacks/client.go @@ -150,10 +150,40 @@ func (c *Client) GetBlockByHeightOrHash(ctx context.Context, height uint64) (*bl } func (c *Client) GetLatestBlock(ctx context.Context) (*blockchainApiClient.GetBlocks200ResponseResultsInner, error) { - resp, _, err := c.apiClient.BlocksAPI.GetBlocks(ctx).Limit(1).Execute() + req := c.apiClient.BlocksAPI.GetBlocks(ctx).Limit(1) + resp, httpResp, err := req.Execute() if err != nil { + if httpResp != nil && httpResp.StatusCode == 200 { + var rawMap map[string]interface{} + if err := json.NewDecoder(httpResp.Body).Decode(&rawMap); err != nil { + return nil, fmt.Errorf("failed to decode response: %w", err) + } + + results, ok := rawMap["results"].([]interface{}) + if !ok || len(results) == 0 { + return nil, fmt.Errorf("no blocks found") + } + + firstBlock, ok := results[0].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("invalid block format") + } + + height, ok := firstBlock["height"].(float64) + if !ok { + return nil, fmt.Errorf("invalid height format") + } + + return &blockchainApiClient.GetBlocks200ResponseResultsInner{ + Height: int32(height), + }, nil + } return nil, err } + + if len(resp.Results) == 0 { + return nil, fmt.Errorf("no blocks found") + } return &resp.Results[0], nil } diff --git a/relayer/chains/stacks/client_test.go b/relayer/chains/stacks/client_test.go index c675b207..443fcd3c 100644 --- a/relayer/chains/stacks/client_test.go +++ b/relayer/chains/stacks/client_test.go @@ -13,6 +13,24 @@ import ( "go.uber.org/zap" ) +func TestClient_GetAccountBalance(t *testing.T) { + ctx := context.Background() + logger, _ := zap.NewDevelopment() + network := stacksSdk.NewStacksTestnet() + client, err := stacks.NewClient(logger, network) + if err != nil { + t.Fatalf("Failed to create client: %v", err) + } + + address := "ST15C893XJFJ6FSKM020P9JQDB5T7X6MQTXMBPAVH" + balance, err := client.GetAccountBalance(ctx, address) + if err != nil { + t.Fatalf("Failed to get account balance: %v", err) + } + + t.Logf("Balance for address %s: %s", address, balance.String()) +} + func TestClient_GetAccountNonce(t *testing.T) { ctx := context.Background() logger, _ := zap.NewDevelopment() @@ -31,6 +49,50 @@ func TestClient_GetAccountNonce(t *testing.T) { t.Logf("Nonce for address %s: %d", address, nonce) } +func TestClient_GetBlockByHeightOrHash(t *testing.T) { + ctx := context.Background() + logger, _ := zap.NewDevelopment() + network := stacksSdk.NewStacksTestnet() + client, err := stacks.NewClient(logger, network) + if err != nil { + t.Fatalf("Failed to create client: %v", err) + } + + block, err := client.GetLatestBlock(ctx) + if err != nil { + t.Fatalf("Failed to get latest blocks: %v", err) + } + if block == nil { + t.Fatalf("No blocks found") + } + + blockHeight := block.Height + + block, err = client.GetBlockByHeightOrHash(ctx, uint64(blockHeight)) + if err != nil { + t.Fatalf("Failed to get block by height: %v", err) + } + + t.Logf("Block at height %d: %+v", blockHeight, block) +} + +func TestClient_GetLatestBlock(t *testing.T) { + ctx := context.Background() + logger, _ := zap.NewDevelopment() + network := stacksSdk.NewStacksTestnet() + client, err := stacks.NewClient(logger, network) + if err != nil { + t.Fatalf("Failed to create client: %v", err) + } + + block, err := client.GetLatestBlock(ctx) + if err != nil { + t.Fatalf("Failed to get latest blocks: %v", err) + } + + t.Logf("Latest block: %+v", block) +} + func TestClient_CallReadOnlyFunction(t *testing.T) { ctx := context.Background() logger, _ := zap.NewDevelopment() diff --git a/relayer/chains/stacks/events/listener.go b/relayer/chains/stacks/events/listener.go index ddf0f45a..bf91e315 100644 --- a/relayer/chains/stacks/events/listener.go +++ b/relayer/chains/stacks/events/listener.go @@ -15,29 +15,31 @@ import ( ) type EventListener struct { - wsURL string - conn *websocket.Conn - eventChan chan *Event - processChan chan *Event - backlog *ring.Ring - maxBufferSize int - mu sync.RWMutex - log *zap.Logger - ctx context.Context - cancel context.CancelFunc + wsURL string + conn *websocket.Conn + eventChan chan *Event + processChan chan *Event + backlog *ring.Ring + maxBufferSize int + mu sync.RWMutex + log *zap.Logger + ctx context.Context + cancel context.CancelFunc + contractAddress string } -func NewEventListener(ctx context.Context, wsURL string, bufferSize int, log *zap.Logger) *EventListener { +func NewEventListener(ctx context.Context, wsURL string, bufferSize int, log *zap.Logger, contractAddress string) *EventListener { ctx, cancel := context.WithCancel(ctx) return &EventListener{ - wsURL: wsURL, - eventChan: make(chan *Event, bufferSize), - processChan: make(chan *Event, bufferSize), - backlog: ring.New(bufferSize), - maxBufferSize: bufferSize, - log: log, - ctx: ctx, - cancel: cancel, + wsURL: wsURL, + eventChan: make(chan *Event, bufferSize), + processChan: make(chan *Event, bufferSize), + backlog: ring.New(bufferSize), + maxBufferSize: bufferSize, + log: log, + ctx: ctx, + cancel: cancel, + contractAddress: contractAddress, } } @@ -126,6 +128,8 @@ func (l *EventListener) readMessages() { return } + l.log.Debug("Received WebSocket message", zap.String("message", string(message))) + event, err := l.parseEvent(message) if err != nil { l.log.Error("Failed to parse event", zap.Error(err)) @@ -136,6 +140,11 @@ func (l *EventListener) readMessages() { continue } + l.log.Info("Parsed event", + zap.String("id", event.ID), + zap.String("type", event.Type), + zap.Any("data", event.Data)) + l.eventChan <- event } } @@ -160,10 +169,15 @@ func (l *EventListener) subscribe(eventType string) error { ID: time.Now().UnixNano(), Method: "subscribe", Params: map[string]interface{}{ - "event": eventType, + "event": eventType, + "address": l.contractAddress, }, } + l.log.Debug("Subscribing to event", + zap.String("type", eventType), + zap.Any("request", request)) + data, err := json.Marshal(request) if err != nil { return fmt.Errorf("failed to marshal subscription request: %w", err) @@ -183,14 +197,22 @@ func (l *EventListener) subscribe(eventType string) error { var response WSResponse if err := json.Unmarshal(message, &response); err != nil { + l.log.Error("Failed to unmarshal subscription response", + zap.Error(err), + zap.String("response", string(message))) return fmt.Errorf("failed to unmarshal subscription response: %w", err) } if response.Error != nil { + l.log.Error("Subscription failed", + zap.String("type", eventType), + zap.String("error", response.Error.Message)) return fmt.Errorf("subscription failed: %s", response.Error.Message) } - l.log.Info("Successfully subscribed to event", zap.String("type", eventType)) + l.log.Info("Successfully subscribed to event", + zap.String("type", eventType), + zap.String("response", string(message))) return nil } @@ -200,6 +222,10 @@ func (l *EventListener) parseEvent(message []byte) (*Event, error) { return nil, fmt.Errorf("failed to unmarshal WebSocket message: %w", err) } + l.log.Debug("Parsed WebSocket message", + zap.String("method", wsMsg.Method), + zap.String("params", string(wsMsg.Params))) + if wsMsg.Method != "event" { return nil, nil } diff --git a/relayer/chains/stacks/events/processor.go b/relayer/chains/stacks/events/processor.go index fdc99e87..cd8544d2 100644 --- a/relayer/chains/stacks/events/processor.go +++ b/relayer/chains/stacks/events/processor.go @@ -65,6 +65,10 @@ func (p *EventProcessor) worker() { } func (p *EventProcessor) processEvent(event *Event) { + p.log.Debug("Processing event", + zap.String("type", event.Type), + zap.Any("data", event.Data)) + if err := p.store.SaveEvent(event); err != nil { p.log.Error("Failed to save event", zap.Error(err)) return @@ -72,7 +76,9 @@ func (p *EventProcessor) processEvent(event *Event) { for _, handler := range p.handlers { if err := handler(event); err != nil { - p.log.Error("Handler failed", zap.Error(err)) + p.log.Error("Handler failed", + zap.Error(err), + zap.String("type", event.Type)) continue } } @@ -80,12 +86,16 @@ func (p *EventProcessor) processEvent(event *Event) { var err error switch event.Type { case CallMessageSent: + p.log.Debug("Processing CallMessageSent event") err = p.handleCallMessageSentEvent(event) case CallMessage: + p.log.Debug("Processing CallMessage event") err = p.handleCallMessageEvent(event) case ResponseMessage: + p.log.Debug("Processing ResponseMessage event") err = p.handleResponseMessageEvent(event) case RollbackMessage: + p.log.Debug("Processing RollbackMessage event") err = p.handleRollbackMessageEvent(event) default: p.log.Warn("No handler for event type", zap.String("type", event.Type)) @@ -93,7 +103,9 @@ func (p *EventProcessor) processEvent(event *Event) { } if err != nil { - p.log.Error("Handler failed", zap.Error(err), zap.String("eventType", event.Type)) + p.log.Error("Handler failed", + zap.Error(err), + zap.String("eventType", event.Type)) return } diff --git a/relayer/chains/stacks/events/system.go b/relayer/chains/stacks/events/system.go index c3268dea..0aab44e6 100644 --- a/relayer/chains/stacks/events/system.go +++ b/relayer/chains/stacks/events/system.go @@ -16,11 +16,11 @@ type EventSystem struct { cancel context.CancelFunc } -func NewEventSystem(ctx context.Context, wsURL string, log *zap.Logger, client interfaces.IClient, senderAddress string, senderKey []byte) *EventSystem { +func NewEventSystem(ctx context.Context, wsURL string, log *zap.Logger, client interfaces.IClient, senderAddress string, senderKey []byte, contractAddress string) *EventSystem { ctx, cancel := context.WithCancel(ctx) store := NewMemoryEventStore() - listener := NewEventListener(ctx, wsURL, 1000, log) + listener := NewEventListener(ctx, wsURL, 1000, log, contractAddress) processor := NewEventProcessor(ctx, store, listener.processChan, 5, log, client, senderAddress, senderKey) return &EventSystem{ diff --git a/relayer/chains/stacks/interfaces/client.go b/relayer/chains/stacks/interfaces/client.go index 94a4717f..93fccfef 100644 --- a/relayer/chains/stacks/interfaces/client.go +++ b/relayer/chains/stacks/interfaces/client.go @@ -28,6 +28,7 @@ type IClient interface { CallReadOnlyFunction(ctx context.Context, contractAddress string, contractName string, functionName string, functionArgs []string) (*string, error) BroadcastTransaction(ctx context.Context, tx transaction.StacksTransaction) (string, error) MakeContractCall(context.Context, string, string, string, []clarity.ClarityValue, string, []byte) (*transaction.ContractCallTransaction, error) + GetContractEvents(ctx context.Context, contractId string, limit, offset int32) (*blockchainApiClient.GetContractEventsById200Response, error) GetWebSocketURL() string Log() *zap.Logger } diff --git a/relayer/chains/stacks/listener.go b/relayer/chains/stacks/listener.go index e1f00e60..869ef202 100644 --- a/relayer/chains/stacks/listener.go +++ b/relayer/chains/stacks/listener.go @@ -15,7 +15,7 @@ func (p *Provider) Listener(ctx context.Context, lastProcessedTx providerTypes.L wsURL := p.client.GetWebSocketURL() p.log.Debug("Using WebSocket URL", zap.String("url", wsURL)) - eventSystem := events.NewEventSystem(ctx, wsURL, p.log, p.client, p.cfg.GetWallet(), p.privateKey) + eventSystem := events.NewEventSystem(ctx, wsURL, p.log, p.client, p.cfg.GetWallet(), p.privateKey, p.cfg.Contracts[providerTypes.XcallContract]) eventSystem.OnEvent(func(event *events.Event) error { msg, err := p.getRelayMessageFromEvent(event.Type, event.Data) diff --git a/relayer/chains/stacks/listener_test.go b/relayer/chains/stacks/listener_test.go deleted file mode 100644 index c2812917..00000000 --- a/relayer/chains/stacks/listener_test.go +++ /dev/null @@ -1,336 +0,0 @@ -package stacks - -import ( - "context" - "math/big" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "go.uber.org/zap" - - "github.com/icon-project/centralized-relay/relayer/chains/stacks/interfaces" - "github.com/icon-project/centralized-relay/relayer/chains/stacks/mocks" - "github.com/icon-project/centralized-relay/relayer/events" - "github.com/icon-project/centralized-relay/relayer/provider" - providerTypes "github.com/icon-project/centralized-relay/relayer/types" -) - -func setupProvider(t *testing.T, mockClient *mocks.MockClient, cfg *Config) *Provider { - logger, err := zap.NewDevelopment() - assert.NoError(t, err) - p, err := cfg.NewProvider(context.Background(), logger, "/tmp/relayer", false, "stacks_testnet") - assert.NoError(t, err) - assert.NotNil(t, p) - - providerInstance := p.(*Provider) - providerInstance.client = mockClient - providerInstance.contracts = cfg.eventMap() - return providerInstance -} - -func TestListener_Success(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - mockClient := new(mocks.MockClient) - - emitMsgEvent := EmitMessageEvent{ - TargetNetwork: "stacks_testnet", - Sn: "12345", - Msg: "Hello, Stacks!", - } - - callMsgEvent := CallMessageEvent{ - ReqID: "67890", - Sn: "54321", - Data: "0xabcdef", - } - - mockClient.On("SubscribeToEvents", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { - callback := args.Get(2).(interfaces.EventCallback) - - go func() { - err := callback("message_event", emitMsgEvent) - assert.NoError(t, err, "Callback for EmitMessageEvent should not error") - - err = callback("call_message_event", callMsgEvent) - assert.NoError(t, err, "Callback for CallMessageEvent should not error") - }() - }).Return(nil) - - cfg := &Config{ - CommonConfig: provider.CommonConfig{ - ChainName: "stacks_testnet", - RPCUrl: "https://stacks-node-api.example.com", - Contracts: providerTypes.ContractConfigMap{ - "xcall": "ST000000000000000000002AMW42H", - "connection": "ST000000000000000000002AMW42H", - }, - NID: "stacks_testnet", - }, - } - - providerInstance := setupProvider(t, mockClient, cfg) - - blockInfoChan := make(chan *providerTypes.BlockInfo, 2) - - go func() { - err := providerInstance.Listener(ctx, providerTypes.LastProcessedTx{}, blockInfoChan) - if err != nil { - t.Logf("Listener exited with error: %v", err) - } - }() - - expectedMessages := map[string]*providerTypes.Message{ - events.EmitMessage: { - Dst: "stacks_testnet", - Src: "stacks_testnet", - Sn: big.NewInt(12345), - MessageHeight: 0, // todo: update - EventType: events.EmitMessage, - Data: []byte("Hello, Stacks!"), - }, - events.CallMessage: { - Dst: "stacks_testnet", - Src: "stacks_testnet", - Sn: big.NewInt(54321), - MessageHeight: 0, // todo: update - EventType: events.CallMessage, - Data: []byte("0xabcdef"), - ReqID: big.NewInt(67890), - }, - } - - receivedMessages := make(map[string]*providerTypes.Message) - - timeout := time.After(2 * time.Second) - for i := 0; i < 2; i++ { - select { - case blockInfo := <-blockInfoChan: - assert.NotNil(t, blockInfo, "Received BlockInfo should not be nil") - assert.Equal(t, uint64(0), blockInfo.Height, "Block height should be 0") - assert.Len(t, blockInfo.Messages, 1, "BlockInfo should contain one message") - - msg := blockInfo.Messages[0] - expectedMsg, exists := expectedMessages[msg.EventType] - assert.True(t, exists, "Unexpected event type received: %s", msg.EventType) - - assert.Equal(t, expectedMsg.Dst, msg.Dst, "Dst field mismatch") - assert.Equal(t, expectedMsg.Src, msg.Src, "Src field mismatch") - assert.True(t, msg.Sn.Cmp(expectedMsg.Sn) == 0, "Sn field mismatch") - assert.Equal(t, expectedMsg.EventType, msg.EventType, "EventType field mismatch") - assert.Equal(t, expectedMsg.Data, msg.Data, "Data field mismatch") - - if msg.EventType == events.CallMessage { - assert.True(t, msg.ReqID.Cmp(expectedMsg.ReqID) == 0, "ReqID field mismatch for CallMessageEvent") - } - - receivedMessages[msg.EventType] = msg - - case <-timeout: - t.Fatal("Timed out waiting for BlockInfo messages") - } - } - - for eventType, expectedMsg := range expectedMessages { - receivedMsg, exists := receivedMessages[eventType] - assert.True(t, exists, "Expected to receive event type: %s", eventType) - assert.Equal(t, expectedMsg.Dst, receivedMsg.Dst, "Dst field mismatch for event type: %s", eventType) - assert.Equal(t, expectedMsg.Src, receivedMsg.Src, "Src field mismatch for event type: %s", eventType) - assert.True(t, receivedMsg.Sn.Cmp(expectedMsg.Sn) == 0, "Sn field mismatch for event type: %s", eventType) - assert.Equal(t, expectedMsg.EventType, receivedMsg.EventType, "EventType field mismatch for event type: %s", eventType) - assert.Equal(t, expectedMsg.Data, receivedMsg.Data, "Data field mismatch for event type: %s", eventType) - - if eventType == events.CallMessage { - assert.True(t, receivedMsg.ReqID.Cmp(expectedMsg.ReqID) == 0, "ReqID field mismatch for CallMessageEvent") - } - } - - cancel() - - time.Sleep(100 * time.Millisecond) - - select { - case blockInfo := <-blockInfoChan: - t.Errorf("Received unexpected BlockInfo after cancellation: %+v", blockInfo) - default: - } - - mockClient.AssertNumberOfCalls(t, "SubscribeToEvents", 1) -} - -func TestListener_CallbackError(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - mockClient := new(mocks.MockClient) - - invalidEmitMsgEvent := EmitMessageEvent{ - TargetNetwork: "stacks_testnet", - Sn: "invalid_sn", - Msg: "Hello, Stacks!", - } - - mockClient.On("SubscribeToEvents", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { - callback := args.Get(2).(interfaces.EventCallback) - - go func() { - err := callback("message_event", invalidEmitMsgEvent) - assert.Error(t, err, "Callback should return an error due to invalid SN") - }() - }).Return(nil) - - cfg := &Config{ - CommonConfig: provider.CommonConfig{ - ChainName: "stacks_testnet", - RPCUrl: "https://stacks-node-api.example.com", - Contracts: providerTypes.ContractConfigMap{ - "xcall": "ST000000000000000000002AMW42H", - "connection": "ST000000000000000000002AMW42H", - }, - NID: "stacks_testnet", - }, - } - - providerInstance := setupProvider(t, mockClient, cfg) - - blockInfoChan := make(chan *providerTypes.BlockInfo, 1) - - go func() { - err := providerInstance.Listener(ctx, providerTypes.LastProcessedTx{}, blockInfoChan) - if err != nil { - t.Logf("Listener exited with error: %v", err) - } - }() - - time.Sleep(100 * time.Millisecond) - - select { - case blockInfo := <-blockInfoChan: - t.Errorf("Received unexpected BlockInfo due to callback error: %+v", blockInfo) - default: - } - - mockClient.AssertNumberOfCalls(t, "SubscribeToEvents", 1) -} - -func TestListener_InvalidEvent(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - mockClient := new(mocks.MockClient) - - unknownEventType := "unknown_event_type" - unknownEventData := map[string]interface{}{ - "some_field": "some_value", - } - - mockClient.On("SubscribeToEvents", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { - callback := args.Get(2).(interfaces.EventCallback) - - go func() { - err := callback(unknownEventType, unknownEventData) - assert.Error(t, err, "Callback should return an error for unknown event type") - }() - }).Return(nil) - - cfg := &Config{ - CommonConfig: provider.CommonConfig{ - ChainName: "stacks_testnet", - RPCUrl: "https://stacks-node-api.example.com", - Contracts: providerTypes.ContractConfigMap{ - "xcall": "ST000000000000000000002AMW42H", - "connection": "ST000000000000000000002AMW42H", - }, - NID: "stacks_testnet", - }, - } - - providerInstance := setupProvider(t, mockClient, cfg) - - blockInfoChan := make(chan *providerTypes.BlockInfo, 1) - - go func() { - err := providerInstance.Listener(ctx, providerTypes.LastProcessedTx{}, blockInfoChan) - if err != nil { - t.Logf("Listener exited with error: %v", err) - } - }() - - time.Sleep(100 * time.Millisecond) - - select { - case blockInfo := <-blockInfoChan: - t.Errorf("Received unexpected BlockInfo for unknown event type: %+v", blockInfo) - default: - } - - mockClient.AssertNumberOfCalls(t, "SubscribeToEvents", 1) -} - -func TestListener_ContextCancel(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - - mockClient := new(mocks.MockClient) - - emitMsgEvent := EmitMessageEvent{ - TargetNetwork: "stacks_testnet", - Sn: "12345", - Msg: "Hello, Stacks!", - } - - mockClient.On("SubscribeToEvents", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { - callback := args.Get(2).(interfaces.EventCallback) - - go func() { - for { - select { - case <-ctx.Done(): - return - default: - callback("message_event", emitMsgEvent) - time.Sleep(50 * time.Millisecond) - } - } - }() - }).Return(nil) - - cfg := &Config{ - CommonConfig: provider.CommonConfig{ - ChainName: "stacks_testnet", - RPCUrl: "https://stacks-node-api.example.com", - Contracts: providerTypes.ContractConfigMap{ - "xcall": "ST000000000000000000002AMW42H", - "connection": "ST000000000000000000002AMW42H", - }, - NID: "stacks_testnet", - }, - } - - providerInstance := setupProvider(t, mockClient, cfg) - - blockInfoChan := make(chan *providerTypes.BlockInfo, 10) - - go func() { - err := providerInstance.Listener(ctx, providerTypes.LastProcessedTx{}, blockInfoChan) - if err != nil { - t.Logf("Listener exited with error: %v", err) - } - }() - - time.Sleep(200 * time.Millisecond) - - cancel() - - time.Sleep(100 * time.Millisecond) - - select { - case blockInfo := <-blockInfoChan: - t.Logf("Received BlockInfo before cancellation: %+v", blockInfo) - default: - } - - mockClient.AssertNumberOfCalls(t, "SubscribeToEvents", 1) -} diff --git a/relayer/chains/stacks/mocks/client_mock.go b/relayer/chains/stacks/mocks/client_mock.go index 42897804..c3ea6ad0 100644 --- a/relayer/chains/stacks/mocks/client_mock.go +++ b/relayer/chains/stacks/mocks/client_mock.go @@ -108,6 +108,11 @@ func (m *MockClient) BroadcastTransaction(ctx context.Context, tx transaction.St return mockArgs.String(0), mockArgs.Error(1) } +func (m *MockClient) GetContractEvents(ctx context.Context, contractId string, limit, offset int32) (*blockchainApiClient.GetContractEventsById200Response, error) { + args := m.Called(ctx, contractId, limit, offset) + return args.Get(0).(*blockchainApiClient.GetContractEventsById200Response), args.Error(1) +} + func (m *MockClient) GetWebSocketURL() string { mockArgs := m.Called() return mockArgs.String(0) diff --git a/relayer/chains/stacks/query.go b/relayer/chains/stacks/query.go index 7a83139d..864efc02 100644 --- a/relayer/chains/stacks/query.go +++ b/relayer/chains/stacks/query.go @@ -188,7 +188,7 @@ func (p *Provider) GenerateMessages(ctx context.Context, fromHeight uint64, toHe errorChan := make(chan error, 1) wsURL := p.client.GetWebSocketURL() - eventSystem := events.NewEventSystem(ctx, wsURL, p.log, p.client, p.cfg.GetWallet(), p.privateKey) + eventSystem := events.NewEventSystem(ctx, wsURL, p.log, p.client, p.cfg.GetWallet(), p.privateKey, p.cfg.Contracts[providerTypes.XcallContract]) eventSystem.OnEvent(func(event *events.Event) error { if event.BlockHeight < fromHeight || event.BlockHeight > toHeight { diff --git a/test/chains/stacks/events.go b/test/chains/stacks/events.go new file mode 100644 index 00000000..d7ed3208 --- /dev/null +++ b/test/chains/stacks/events.go @@ -0,0 +1,225 @@ +package stacks + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/icon-project/centralized-relay/test/chains" + blockchainApiClient "github.com/icon-project/stacks-go-sdk/pkg/stacks_blockchain_api_client" +) + +func (s *StacksLocalnet) FindEvent(ctx context.Context, startHeight uint64, contract, signature string, index []string) (*blockchainApiClient.SmartContractLogTransactionEvent, error) { + for { + select { + case <-ctx.Done(): + return nil, fmt.Errorf("context cancelled while finding event %s", signature) + default: + events, err := s.client.GetContractEvents(ctx, contract, 50, 0) + if err != nil { + return nil, fmt.Errorf("failed to get contract events: %w", err) + } + + for _, event := range events.Results { + if event.SmartContractLogTransactionEvent != nil && + event.SmartContractLogTransactionEvent.ContractLog.Topic == signature { + return event.SmartContractLogTransactionEvent, nil + } + } + + time.Sleep(BLOCK_TIME) + } + } +} + +func (s *StacksLocalnet) FindCallMessage(ctx context.Context, startHeight uint64, from, to, sn string) (string, string, error) { + for { + select { + case <-ctx.Done(): + return "", "", fmt.Errorf("context cancelled while finding call message with sn %s", sn) + default: + events, err := s.client.GetContractEvents(ctx, s.IBCAddresses["xcall-proxy"], 50, 0) + if err != nil { + return "", "", fmt.Errorf("failed to get contract events: %w", err) + } + + for _, event := range events.Results { + if event.SmartContractLogTransactionEvent != nil { + log := event.SmartContractLogTransactionEvent.ContractLog + if log.Topic == "print" && strings.Contains(log.Value.Repr, "CallMessage") { + eventSn := extractSnFromEvent(log.Value.Repr) + if eventSn == sn { + reqId, data := extractCallMessageData(log.Value.Repr) + if reqId != "" && data != "" { + return reqId, data, nil + } + } + } + } + } + + time.Sleep(BLOCK_TIME) + } + } +} + +func (s *StacksLocalnet) FindCallResponse(ctx context.Context, startHeight uint64, sn string) (string, error) { + for { + select { + case <-ctx.Done(): + return "", fmt.Errorf("context cancelled while finding call response with sn %s", sn) + default: + events, err := s.client.GetContractEvents(ctx, s.IBCAddresses["xcall-proxy"], 50, 0) + if err != nil { + return "", fmt.Errorf("failed to get contract events: %w", err) + } + + for _, event := range events.Results { + if event.SmartContractLogTransactionEvent != nil { + log := event.SmartContractLogTransactionEvent.ContractLog + if log.Topic == "print" && strings.Contains(log.Value.Repr, "CallResponse") { + eventSn := extractSnFromEvent(log.Value.Repr) + if eventSn == sn { + return event.SmartContractLogTransactionEvent.TxId, nil + } + } + } + } + + time.Sleep(BLOCK_TIME) + } + } +} + +func (s *StacksLocalnet) FindRollbackExecutedMessage(ctx context.Context, startHeight uint64, sn string) (string, error) { + for { + select { + case <-ctx.Done(): + return "", fmt.Errorf("context cancelled while finding rollback message with sn %s", sn) + default: + events, err := s.client.GetContractEvents(ctx, s.IBCAddresses["xcall-proxy"], 50, 0) + if err != nil { + return "", fmt.Errorf("failed to get contract events: %w", err) + } + + for _, event := range events.Results { + if event.SmartContractLogTransactionEvent != nil { + log := event.SmartContractLogTransactionEvent.ContractLog + if log.Topic == "print" && strings.Contains(log.Value.Repr, "RollbackExecuted") { + eventSn := extractSnFromEvent(log.Value.Repr) + if eventSn == sn { + return sn, nil + } + } + } + } + + time.Sleep(BLOCK_TIME) + } + } +} + +func (s *StacksLocalnet) FindTargetXCallMessage(ctx context.Context, target chains.Chain, height uint64, to string) (*chains.XCallResponse, error) { + for { + select { + case <-ctx.Done(): + return nil, fmt.Errorf("context cancelled while finding target xcall message") + default: + events, err := s.client.GetContractEvents(ctx, s.IBCAddresses["xcall-proxy"], 50, 0) + if err != nil { + return nil, fmt.Errorf("failed to get contract events: %w", err) + } + + for _, event := range events.Results { + if event.SmartContractLogTransactionEvent != nil { + log := event.SmartContractLogTransactionEvent.ContractLog + if log.Topic == "print" { + if strings.Contains(log.Value.Repr, "EmitMessage") { + sn, msg, targetNetwork := extractEmitMessageData(log.Value.Repr) + if targetNetwork == to { + return &chains.XCallResponse{ + SerialNo: sn, + Data: msg, + }, nil + } + } else if strings.Contains(log.Value.Repr, "CallMessage") { + sn, reqId, data := extractFullCallMessageData(log.Value.Repr) + return &chains.XCallResponse{ + SerialNo: sn, + RequestID: reqId, + Data: data, + }, nil + } + } + } + } + + time.Sleep(BLOCK_TIME) + } + } +} + +func extractSnFromEvent(repr string) string { + startIdx := strings.Index(repr, "(sn u") + if startIdx != -1 { + startIdx += 5 // Move past "(sn u" + endIdx := strings.Index(repr[startIdx:], ")") + if endIdx != -1 { + return repr[startIdx : startIdx+endIdx] + } + } + return "" +} + +func extractCallMessageData(repr string) (reqId, data string) { + reqIdStart := strings.Index(repr, "reqId u") + if reqIdStart != -1 { + reqIdStart += 7 + reqIdEnd := strings.Index(repr[reqIdStart:], " ") + if reqIdEnd != -1 { + reqId = repr[reqIdStart : reqIdStart+reqIdEnd] + } + } + + dataStart := strings.Index(repr, "data 0x") + if dataStart != -1 { + dataStart += 7 + dataEnd := strings.Index(repr[dataStart:], ")") + if dataEnd != -1 { + data = repr[dataStart : dataStart+dataEnd] + } + } + + return reqId, data +} + +func extractEmitMessageData(repr string) (sn, msg, targetNetwork string) { + sn = extractSnFromEvent(repr) + + msgStart := strings.Index(repr, "msg 0x") + if msgStart != -1 { + msgStart += 6 + msgEnd := strings.Index(repr[msgStart:], " ") + if msgEnd != -1 { + msg = repr[msgStart : msgStart+msgEnd] + } + } + + networkStart := strings.Index(repr, "network \"") + if networkStart != -1 { + networkStart += 9 + networkEnd := strings.Index(repr[networkStart:], "\"") + if networkEnd != -1 { + targetNetwork = repr[networkStart : networkStart+networkEnd] + } + } + + return sn, msg, targetNetwork +} + +func extractFullCallMessageData(repr string) (sn, reqId, data string) { + sn = extractSnFromEvent(repr) + reqId, data = extractCallMessageData(repr) + return sn, reqId, data +} diff --git a/test/chains/stacks/initialization.go b/test/chains/stacks/initialization.go new file mode 100644 index 00000000..7be947d8 --- /dev/null +++ b/test/chains/stacks/initialization.go @@ -0,0 +1,959 @@ +package stacks + +import ( + "context" + "encoding/hex" + "fmt" + "os" + "strings" + + stacksClient "github.com/icon-project/centralized-relay/relayer/chains/stacks" + "github.com/icon-project/centralized-relay/test/chains" + "github.com/icon-project/stacks-go-sdk/pkg/clarity" + "github.com/icon-project/stacks-go-sdk/pkg/transaction" + "go.uber.org/zap" +) + +func (s *StacksLocalnet) SetupXCall(ctx context.Context) error { + if s.testconfig.Environment == "preconfigured" { + testcase := ctx.Value("testcase").(string) + s.IBCAddresses["xcall-proxy"] = "STXCALLPROXYADDRESS" + s.IBCAddresses["connection"] = "STXCONNECTIONADDRESS" + s.IBCAddresses[fmt.Sprintf("dapp-%s", testcase)] = "STXDAPPADDRESS" + return nil + } + + privateKey, senderAddress, err := s.loadPrivateKey(s.testconfig.KeystoreFile, s.testconfig.KeystorePassword) + if err != nil { + return fmt.Errorf("failed to load deployer's private key: %w", err) + } + + deployments := []struct { + name string // Contract name for deployment + contract string // Key in testconfig.Contracts + wait bool // Whether to wait for confirmation + postDeploy func(contractAddress string) error // Optional post-deployment initialization + }{ + {"xcall-common-trait", "common-trait", true, nil}, + {"xcall-receiver-trait", "receiver-trait", true, nil}, + {"xcall-impl-trait", "impl-trait", true, nil}, + {"xcall-proxy-trait", "proxy-trait", true, nil}, + + {"util", "util", true, nil}, + {"rlp-encode", "rlp-encode", true, nil}, + {"rlp-decode", "rlp-decode", true, nil}, + + {"xcall-proxy", "xcall-proxy", true, nil}, + + {"centralized-connection", "connection", true, nil}, + + {"xcall-impl-v5", "xcall-impl", true, func(proxyAddr string) error { + implAddr := senderAddress + ".xcall-impl-v5" + implPrincipal, err := clarity.StringToPrincipal(implAddr) + if err != nil { + return fmt.Errorf("failed to convert implementation address to principal: %w", err) + } + + upgradeTx, err := transaction.MakeContractCall( + senderAddress, + "xcall-proxy", + "upgrade", + []clarity.ClarityValue{ + implPrincipal, + clarity.NewOptionNone(), + }, + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create upgrade transaction: %w", err) + } + + txID, err := transaction.BroadcastTransaction(upgradeTx, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast upgrade transaction: %w", err) + } + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return fmt.Errorf("failed to confirm upgrade transaction: %w", err) + } + + err = s.initializeXCallImpl(ctx, privateKey, senderAddress) + if err != nil { + return fmt.Errorf("failed to initialize xcall-impl: %w", err) + } + + err = s.setAdminXCallImpl(ctx, privateKey, senderAddress) + if err != nil { + return fmt.Errorf("failed to set admin for xcall-impl: %w", err) + } + + err = s.setDefaultConnection(ctx, privateKey, senderAddress) + if err != nil { + return fmt.Errorf("failed to set default connection: %w", err) + } + + err = s.setProtocolFeeHandler(ctx, privateKey, senderAddress) + if err != nil { + return fmt.Errorf("failed to set protocol fee handler: %w", err) + } + + err = s.setConnectionFees(ctx, privateKey, senderAddress) + if err != nil { + return fmt.Errorf("failed to set connection fees: %w", err) + } + + err = s.setProtocolFee(ctx, privateKey, senderAddress) + if err != nil { + return fmt.Errorf("failed to set protocol fee: %w", err) + } + + s.log.Info("Initialized proxy with implementation", + zap.String("proxy", proxyAddr), + zap.String("implementation", implAddr)) + + return nil + }}, + } + + connectionContractName := "centralized-connection" + implContractName := "xcall-impl-v5" + proxyContractName := "xcall-proxy" + + s.IBCAddresses["xcall-proxy"] = senderAddress + "." + proxyContractName + s.IBCAddresses["xcall-impl"] = senderAddress + "." + implContractName + s.IBCAddresses["connection"] = senderAddress + "." + connectionContractName + + deployedContracts := make(map[string]string) + + for _, deployment := range deployments { + contractAddress := senderAddress + "." + deployment.name + deployedContracts[deployment.name] = contractAddress + + contract, err := s.client.GetContractById(ctx, contractAddress) + if err != nil { + return fmt.Errorf("failed to check contract existence for %s: %w", deployment.name, err) + } + if contract != nil { + txResp, err := s.client.GetTransactionById(ctx, contract.TxId) + if err == nil { + receipt, err := stacksClient.GetReceipt(txResp) + if err == nil && receipt.Status { + s.log.Info("Contract already successfully deployed, skipping", + zap.String("contract", deployment.name), + zap.String("address", contractAddress)) + continue + } + } + } + + codeBody, err := os.ReadFile(s.testconfig.Contracts[deployment.contract]) + if err != nil { + return fmt.Errorf("failed to read contract code for %s: %w", deployment.name, err) + } + + tx, err := transaction.MakeContractDeploy( + deployment.name, + string(codeBody), + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create contract deploy transaction for %s: %w", deployment.name, err) + } + + txID, err := transaction.BroadcastTransaction(tx, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast transaction for %s: %w", deployment.name, err) + } + + s.log.Info("Deployed contract", + zap.String("contract", deployment.name), + zap.String("txID", txID)) + + if deployment.wait { + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return fmt.Errorf("failed to confirm transaction for %s: %w", deployment.name, err) + } + } + + if deployment.postDeploy != nil { + if err := deployment.postDeploy(contractAddress); err != nil { + return fmt.Errorf("post-deployment initialization failed for %s: %w", deployment.name, err) + } + } + } + + s.IBCAddresses["xcall-proxy"] = deployedContracts["xcall-proxy"] + s.IBCAddresses["xcall-impl"] = deployedContracts["xcall-impl-v5"] + s.IBCAddresses["connection"] = deployedContracts["centralized-connection"] + + return nil +} + +func (s *StacksLocalnet) setDefaultConnection(ctx context.Context, privateKey []byte, senderAddress string) error { + nid := "test" + connectionAddress := senderAddress + "." + "centralized-connection" + + nidArg, err := clarity.NewStringASCII(nid) + if err != nil { + return fmt.Errorf("failed to create nid argument: %w", err) + } + + connArg, err := clarity.NewStringASCII(connectionAddress) + if err != nil { + return fmt.Errorf("failed to create connection address argument: %w", err) + } + + implAddr := senderAddress + "." + "xcall-impl-v5" + implPrincipal, err := clarity.StringToPrincipal(implAddr) + if err != nil { + return fmt.Errorf("failed to convert implementation address to principal: %w", err) + } + + args := []clarity.ClarityValue{ + nidArg, + connArg, + implPrincipal, + } + + txCall, err := transaction.MakeContractCall( + senderAddress, + "xcall-proxy", + "set-default-connection", + args, + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + + if err != nil { + return fmt.Errorf("failed to create set-default-connection transaction: %w", err) + } + + txID, err := transaction.BroadcastTransaction(txCall, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast set-default-connection transaction: %w", err) + } + + s.log.Info("Set default connection in xcall-impl", zap.String("txID", txID)) + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return err + } + + return nil +} + +func (s *StacksLocalnet) initializeXCallImpl(ctx context.Context, privateKey []byte, senderAddress string) error { + nid := s.cfg.ChainID + addr := senderAddress + + nidArg, err := clarity.NewStringASCII(nid) + if err != nil { + return fmt.Errorf("failed to create nid argument: %w", err) + } + + addrArg, err := clarity.NewStringASCII(addr) + if err != nil { + return fmt.Errorf("failed to create addr argument: %w", err) + } + + args := []clarity.ClarityValue{nidArg, addrArg} + + txCall, err := transaction.MakeContractCall( + senderAddress, + "xcall-impl-v5", + "init", + args, + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create init transaction: %w", err) + } + + txID, err := transaction.BroadcastTransaction(txCall, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast init transaction: %w", err) + } + + s.log.Info("Initialized xcall-impl contract", zap.String("txID", txID)) + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return err + } + + return nil +} + +func (s *StacksLocalnet) setConnectionFees(ctx context.Context, privateKey []byte, senderAddress string) error { + networks := []string{"stacks_testnet", "test"} + messageFees := map[string]uint64{"stacks_testnet": 500000, "test": 1000000} + responseFees := map[string]uint64{"stacks_testnet": 250000, "test": 500000} + + for _, nid := range networks { + nidArg, err := clarity.NewStringASCII(nid) + if err != nil { + return fmt.Errorf("failed to create nid argument: %w", err) + } + + messageFeeArg, _ := clarity.NewUInt(messageFees[nid]) + responseFeeArg, _ := clarity.NewUInt(responseFees[nid]) + + args := []clarity.ClarityValue{ + nidArg, + messageFeeArg, + responseFeeArg, + } + + txCall, err := transaction.MakeContractCall( + senderAddress, + "centralized-connection", + "set-fee", + args, + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create set-fee transaction: %w", err) + } + + txID, err := transaction.BroadcastTransaction(txCall, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast set-fee transaction: %w", err) + } + + s.log.Info("Set fee in centralized-connection", zap.String("txID", txID), zap.String("nid", nid)) + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return err + } + } + + return nil +} + +func (s *StacksLocalnet) setProtocolFee(ctx context.Context, privateKey []byte, senderAddress string) error { + protocolFee := uint64(100000) + protocolFeeClarity, _ := clarity.NewUInt(protocolFee) + + implAddr := s.IBCAddresses["xcall-impl"] + implPrincipal, err := clarity.StringToPrincipal(implAddr) + if err != nil { + return fmt.Errorf("failed to convert implPrincipal to principal: %w", err) + } + + args := []clarity.ClarityValue{ + protocolFeeClarity, + implPrincipal, + } + + txCall, err := transaction.MakeContractCall( + senderAddress, + "xcall-proxy", + "set-protocol-fee", + args, + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create set-protocol-fee transaction: %w", err) + } + + txID, err := transaction.BroadcastTransaction(txCall, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast set-protocol-fee transaction: %w", err) + } + + s.log.Info("Set protocol fee in xcall-proxy", zap.String("txID", txID)) + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return err + } + + return nil +} + +func (s *StacksLocalnet) setAdminXCallImpl(ctx context.Context, privateKey []byte, senderAddress string) error { + senderPrincipal, err := clarity.StringToPrincipal(senderAddress) + if err != nil { + return fmt.Errorf("failed to convert senderAddress to principal: %w", err) + } + + args := []clarity.ClarityValue{ + senderPrincipal, + } + + txCall, err := transaction.MakeContractCall( + senderAddress, + "xcall-impl-v5", + "set-admin", + args, + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create set-admin transaction: %w", err) + } + + txID, err := transaction.BroadcastTransaction(txCall, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast set-admin transaction: %w", err) + } + + s.log.Info("Set admin for xcall-impl", zap.String("txID", txID)) + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return err + } + + return nil +} + +func (s *StacksLocalnet) setProtocolFeeHandler(ctx context.Context, privateKey []byte, senderAddress string) error { + connAddr := s.IBCAddresses["connection"] + connPrincipal, err := clarity.StringToPrincipal(connAddr) + if err != nil { + return fmt.Errorf("failed to create connection principal: %w", err) + } + + implAddr := s.IBCAddresses["xcall-impl"] + + implPrincipal, err := clarity.StringToPrincipal(implAddr) + if err != nil { + return fmt.Errorf("failed to convert implPrincipal to principal: %w", err) + } + + args := []clarity.ClarityValue{ + connPrincipal, + implPrincipal, + } + + txCall, err := transaction.MakeContractCall( + senderAddress, + "xcall-proxy", + "set-protocol-fee-handler", + args, + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create set-protocol-fee-handler transaction: %w", err) + } + + txID, err := transaction.BroadcastTransaction(txCall, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast set-protocol-fee-handler transaction: %w", err) + } + + s.log.Info("Set protocol fee handler in xcall-proxy", zap.String("txID", txID)) + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return err + } + + return nil +} + +func (s *StacksLocalnet) SetupConnection(ctx context.Context, target chains.Chain) error { + if s.testconfig.Environment == "preconfigured" { + return nil + } + + privateKey, senderAddress, err := s.loadPrivateKey(s.testconfig.KeystoreFile, s.testconfig.KeystorePassword) + if err != nil { + return fmt.Errorf("failed to load deployer's private key: %w", err) + } + + connectionContractName := "centralized-connection" + contractAddress := senderAddress + "." + connectionContractName + + contract, err := s.client.GetContractById(ctx, contractAddress) + if err == nil && contract != nil { + txResp, err := s.client.GetTransactionById(ctx, contract.TxId) + if err == nil { + receipt, err := stacksClient.GetReceipt(txResp) + if err == nil && receipt.Status { + s.log.Info("Connection contract already successfully deployed, skipping deployment", + zap.String("address", contractAddress)) + + s.IBCAddresses["connection"] = contractAddress + return s.initializeConnection(ctx, privateKey, senderAddress) + } + } + } + + codeBody, err := os.ReadFile(s.testconfig.Contracts["connection"]) + if err != nil { + return fmt.Errorf("failed to read connection contract code: %w", err) + } + + tx, err := transaction.MakeContractDeploy( + connectionContractName, + string(codeBody), + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create contract deploy transaction: %w", err) + } + + txID, err := transaction.BroadcastTransaction(tx, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast transaction: %w", err) + } + + s.log.Info("Deployed centralized-connection contract", zap.String("txID", txID)) + s.IBCAddresses["connection"] = contractAddress + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return err + } + + return s.initializeConnection(ctx, privateKey, senderAddress) +} + +func (s *StacksLocalnet) isConnectionInitialized(ctx context.Context, contractAddress string) (bool, error) { + parts := strings.Split(contractAddress, ".") + if len(parts) != 2 { + return false, fmt.Errorf("invalid contract ID format: %s", contractAddress) + } + contractAddress = parts[0] + contractName := parts[1] + + result, err := s.client.CallReadOnlyFunction( + ctx, + contractAddress, + contractName, + "get-xcall", + []string{}, + ) + if err != nil { + return false, fmt.Errorf("failed to check connection initialization: %w", err) + } + + byteResult, err := hex.DecodeString(strings.TrimPrefix(*result, "0x")) + if err != nil { + return false, fmt.Errorf("failed to hex decode get-xcall response: %w", err) + } + + clarityValue, err := clarity.DeserializeClarityValue(byteResult) + if err != nil { + return false, fmt.Errorf("failed to deserialize get-xcall response: %w", err) + } + + responseValue, ok := clarityValue.(*clarity.ResponseOk) + if !ok { + return false, fmt.Errorf("unexpected response type: %T", clarityValue) + } + + _, ok = responseValue.Value.(*clarity.OptionNone) + if ok { + return false, nil + } + + return true, nil +} + +func (s *StacksLocalnet) initializeConnection(ctx context.Context, privateKey []byte, senderAddress string) error { + contractAddress := s.IBCAddresses["connection"] + initialized, err := s.isConnectionInitialized(ctx, contractAddress) + if err != nil { + return fmt.Errorf("failed to check connection initialization status: %w", err) + } + + if initialized { + s.log.Info("Connection contract already initialized, skipping initialization") + return nil + } + + xcallAddress := s.IBCAddresses["xcall-proxy"] + relayerAddress := s.testconfig.RelayWalletAddress + + xcallPrincipal, err := clarity.StringToPrincipal(xcallAddress) + if err != nil { + return fmt.Errorf("invalid xcall address: %w", err) + } + relayerPrincipal, err := clarity.StringToPrincipal(relayerAddress) + if err != nil { + return fmt.Errorf("invalid relayer address: %w", err) + } + + args := []clarity.ClarityValue{xcallPrincipal, relayerPrincipal} + + txCall, err := transaction.MakeContractCall( + senderAddress, + "centralized-connection", + "initialize", + args, + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create contract call transaction: %w", err) + } + + txID, err := transaction.BroadcastTransaction(txCall, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast transaction: %w", err) + } + + s.log.Info("Initialized centralized-connection contract", zap.String("txID", txID)) + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return err + } + + return nil +} + +func shortenContractName(testcase string) string { + // Stacks has a contract name limit defined in SIP-003 + maxLength := 30 + prefix := "x-dapp-" + + cleaned := strings.Map(func(r rune) rune { + if r >= 'a' && r <= 'z' || r >= '0' && r <= '9' || r == '-' { + return r + } + return '-' + }, strings.ToLower(testcase)) + + totalLen := len(prefix) + len(cleaned) + if totalLen > maxLength { + remaining := maxLength - len(prefix) + if remaining > 0 { + cleaned = cleaned[:remaining] + } else { + cleaned = "" + } + } + return prefix + cleaned +} + +func (s *StacksLocalnet) DeployXCallMockApp(ctx context.Context, keyName string, connections []chains.XCallConnection) error { + if s.testconfig.Environment == "preconfigured" { + return nil + } + + testcase := ctx.Value("testcase").(string) + appContractName := shortenContractName(testcase) + + privateKey, senderAddress, err := s.loadPrivateKey(s.testconfig.KeystoreFile, s.testconfig.KeystorePassword) + if err != nil { + return fmt.Errorf("failed to load deployer's private key: %w", err) + } + + contractAddress := senderAddress + "." + appContractName + + contract, err := s.client.GetContractById(ctx, contractAddress) + if err == nil && contract != nil { + txResp, err := s.client.GetTransactionById(ctx, contract.TxId) + if err == nil { + receipt, err := stacksClient.GetReceipt(txResp) + if err == nil && receipt.Status { + s.log.Info("XCall mock app contract already successfully deployed, skipping deployment", + zap.String("address", contractAddress)) + + s.IBCAddresses[fmt.Sprintf("dapp-%s", testcase)] = contractAddress + return nil + } + } + } + + codeBody, err := os.ReadFile(s.testconfig.Contracts["dapp"]) + if err != nil { + return fmt.Errorf("failed to read dapp contract code: %w", err) + } + + tx, err := transaction.MakeContractDeploy( + appContractName, + string(codeBody), + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create contract deploy transaction: %w", err) + } + + txID, err := transaction.BroadcastTransaction(tx, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast transaction: %w", err) + } + + s.log.Info("Deployed xcall mock app contract", + zap.String("txID", txID), + zap.String("contractName", appContractName)) + + s.IBCAddresses[fmt.Sprintf("dapp-%s", testcase)] = contractAddress + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return err + } + + xcallAddress := s.IBCAddresses["xcall-proxy"] + xcallPrincipal, err := clarity.StringToPrincipal(xcallAddress) + if err != nil { + return fmt.Errorf("invalid xcall address: %w", err) + } + + args := []clarity.ClarityValue{xcallPrincipal} + + txCall, err := transaction.MakeContractCall( + senderAddress, + appContractName, + "initialize", + args, + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create contract call transaction: %w", err) + } + + txID, err = transaction.BroadcastTransaction(txCall, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast transaction: %w", err) + } + + s.log.Info("Initialized xcall mock app contract", zap.String("txID", txID)) + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return err + } + + for _, connection := range connections { + s.log.Debug("Setting up connection", + zap.String("nid", connection.Nid), + zap.String("destination", connection.Destination)) + err := s.addConnection(ctx, senderAddress, appContractName, privateKey, connection) + if err != nil { + s.log.Error("Failed to add connection", + zap.Error(err), + zap.String("nid", connection.Nid)) + continue + } + } + + return nil +} + +func (s *StacksLocalnet) isConnectionExists(ctx context.Context, contractAddress, contractName, nid, source, destination string) (bool, error) { + sourcesResult, err := s.client.CallReadOnlyFunction( + ctx, + contractAddress, + contractName, + "get-sources", + []string{ + fmt.Sprintf("0x%s", hex.EncodeToString([]byte(nid))), + }, + ) + if err != nil { + return false, fmt.Errorf("failed to check sources: %w", err) + } + + destsResult, err := s.client.CallReadOnlyFunction( + ctx, + contractAddress, + contractName, + "get-destinations", + []string{ + fmt.Sprintf("0x%s", hex.EncodeToString([]byte(nid))), + }, + ) + if err != nil { + return false, fmt.Errorf("failed to check destinations: %w", err) + } + + sourceBytes, err := hex.DecodeString(strings.TrimPrefix(*sourcesResult, "0x")) + if err != nil { + return false, fmt.Errorf("failed to decode sources response: %w", err) + } + + sourcesValue, err := clarity.DeserializeClarityValue(sourceBytes) + if err != nil { + return false, fmt.Errorf("failed to deserialize sources: %w", err) + } + + destBytes, err := hex.DecodeString(strings.TrimPrefix(*destsResult, "0x")) + if err != nil { + return false, fmt.Errorf("failed to decode destinations response: %w", err) + } + + destsValue, err := clarity.DeserializeClarityValue(destBytes) + if err != nil { + return false, fmt.Errorf("failed to deserialize destinations: %w", err) + } + + sourcesList, ok := sourcesValue.(*clarity.List) + if !ok { + return false, fmt.Errorf("unexpected sources type: %T", sourcesValue) + } + + destsList, ok := destsValue.(*clarity.List) + if !ok { + return false, fmt.Errorf("unexpected destinations type: %T", destsValue) + } + + sourceExists := false + for _, item := range sourcesList.Values { + if stringVal, ok := item.(*clarity.StringASCII); ok { + if stringVal.Data == source { + sourceExists = true + break + } + } + } + + destExists := false + for _, item := range destsList.Values { + if stringVal, ok := item.(*clarity.StringASCII); ok { + if stringVal.Data == destination { + destExists = true + break + } + } + } + + s.log.Debug("Connection check result", + zap.String("nid", nid), + zap.String("source", source), + zap.String("destination", destination), + zap.Bool("sourceExists", sourceExists), + zap.Bool("destExists", destExists)) + + return sourceExists && destExists, nil +} + +func (s *StacksLocalnet) addConnection(ctx context.Context, senderAddress, appContractName string, privateKey []byte, connection chains.XCallConnection) error { + connAddress := s.IBCAddresses[connection.Connection] + + connArg, err := clarity.NewStringASCII(connAddress) + if err != nil { + return fmt.Errorf("failed to create connection argument: %w", err) + } + + destArg, err := clarity.NewStringASCII(connection.Destination) + if err != nil { + return fmt.Errorf("failed to create destination argument: %w", err) + } + + nidArg, err := clarity.NewStringASCII(connection.Nid) + if err != nil { + return fmt.Errorf("failed to create nid argument: %w", err) + } + + args := []clarity.ClarityValue{ + nidArg, + connArg, + destArg, + } + + parts := strings.Split(connAddress, ".") + if len(parts) != 2 { + return fmt.Errorf("invalid connection address format: %s", connAddress) + } + contractName := parts[1] + + exists, err := s.isConnectionExists(ctx, senderAddress, appContractName, + connection.Nid, contractName, connection.Destination) + if err != nil { + s.log.Warn("Failed to check existing connection", + zap.Error(err), + zap.String("nid", connection.Nid)) + } + + if exists { + s.log.Info("Connection already exists, skipping", + zap.String("nid", connection.Nid), + zap.String("source", contractName), + zap.String("destination", connection.Destination)) + return nil + } + + txCall, err := transaction.MakeContractCall( + senderAddress, + appContractName, + "add-connection", + args, + *s.network, + senderAddress, + privateKey, + nil, + nil, + ) + if err != nil { + return fmt.Errorf("failed to create contract call transaction: %w", err) + } + + txID, err := transaction.BroadcastTransaction(txCall, s.network) + if err != nil { + return fmt.Errorf("failed to broadcast transaction: %w", err) + } + + s.log.Info("Adding new connection to xcall mock app", + zap.String("txID", txID), + zap.String("nid", connection.Nid), + zap.String("source", contractName), + zap.String("destination", connection.Destination)) + + err = s.waitForTransactionConfirmation(ctx, txID) + if err != nil { + return fmt.Errorf("failed to confirm transaction: %w", err) + } + + s.log.Info("Successfully added new connection", + zap.String("nid", connection.Nid), + zap.String("source", contractName), + zap.String("destination", connection.Destination)) + + return nil +} diff --git a/test/chains/stacks/remotenet.go b/test/chains/stacks/remotenet.go index b5f8a2ef..96d187db 100644 --- a/test/chains/stacks/remotenet.go +++ b/test/chains/stacks/remotenet.go @@ -2,9 +2,7 @@ package stacks import ( "context" - "encoding/hex" "fmt" - "os" "strings" "time" @@ -14,9 +12,7 @@ import ( "github.com/icon-project/centralized-relay/test/interchaintest/relayer/centralized" "github.com/icon-project/centralized-relay/test/testsuite/testconfig" "github.com/icon-project/stacks-go-sdk/pkg/clarity" - "github.com/icon-project/stacks-go-sdk/pkg/crypto" "github.com/icon-project/stacks-go-sdk/pkg/stacks" - blockchainApiClient "github.com/icon-project/stacks-go-sdk/pkg/stacks_blockchain_api_client" "github.com/icon-project/stacks-go-sdk/pkg/transaction" "go.uber.org/zap" "gopkg.in/yaml.v3" @@ -109,950 +105,6 @@ func (s *StacksLocalnet) GetContractAddress(key string) string { return value } -func (s *StacksLocalnet) SetupXCall(ctx context.Context) error { - if s.testconfig.Environment == "preconfigured" { - testcase := ctx.Value("testcase").(string) - s.IBCAddresses["xcall-proxy"] = "STXCALLPROXYADDRESS" - s.IBCAddresses["connection"] = "STXCONNECTIONADDRESS" - s.IBCAddresses[fmt.Sprintf("dapp-%s", testcase)] = "STXDAPPADDRESS" - return nil - } - - privateKey, senderAddress, err := s.loadPrivateKey(s.testconfig.KeystoreFile, s.testconfig.KeystorePassword) - if err != nil { - return fmt.Errorf("failed to load deployer's private key: %w", err) - } - - deployments := []struct { - name string // Contract name for deployment - contract string // Key in testconfig.Contracts - wait bool // Whether to wait for confirmation - postDeploy func(contractAddress string) error // Optional post-deployment initialization - }{ - {"xcall-common-trait", "common-trait", true, nil}, - {"xcall-receiver-trait", "receiver-trait", true, nil}, - {"xcall-impl-trait", "impl-trait", true, nil}, - {"xcall-proxy-trait", "proxy-trait", true, nil}, - - {"util", "util", true, nil}, - {"rlp-encode", "rlp-encode", true, nil}, - {"rlp-decode", "rlp-decode", true, nil}, - - {"xcall-proxy", "xcall-proxy", true, nil}, - - {"centralized-connection", "connection", true, nil}, - - {"xcall-impl-v5", "xcall-impl", true, func(proxyAddr string) error { - implAddr := senderAddress + ".xcall-impl-v5" - implPrincipal, err := clarity.StringToPrincipal(implAddr) - if err != nil { - return fmt.Errorf("failed to convert implementation address to principal: %w", err) - } - - upgradeTx, err := transaction.MakeContractCall( - senderAddress, - "xcall-proxy", - "upgrade", - []clarity.ClarityValue{ - implPrincipal, - clarity.NewOptionNone(), - }, - *s.network, - senderAddress, - privateKey, - nil, - nil, - ) - if err != nil { - return fmt.Errorf("failed to create upgrade transaction: %w", err) - } - - txID, err := transaction.BroadcastTransaction(upgradeTx, s.network) - if err != nil { - return fmt.Errorf("failed to broadcast upgrade transaction: %w", err) - } - - err = s.waitForTransactionConfirmation(ctx, txID) - if err != nil { - return fmt.Errorf("failed to confirm upgrade transaction: %w", err) - } - - err = s.initializeXCallImpl(ctx, privateKey, senderAddress) - if err != nil { - return fmt.Errorf("failed to initialize xcall-impl: %w", err) - } - - err = s.setAdminXCallImpl(ctx, privateKey, senderAddress) - if err != nil { - return fmt.Errorf("failed to set admin for xcall-impl: %w", err) - } - - err = s.setDefaultConnection(ctx, privateKey, senderAddress) - if err != nil { - return fmt.Errorf("failed to set default connection: %w", err) - } - - err = s.setProtocolFeeHandler(ctx, privateKey, senderAddress) - if err != nil { - return fmt.Errorf("failed to set protocol fee handler: %w", err) - } - - err = s.setConnectionFees(ctx, privateKey, senderAddress) - if err != nil { - return fmt.Errorf("failed to set connection fees: %w", err) - } - - err = s.setProtocolFee(ctx, privateKey, senderAddress) - if err != nil { - return fmt.Errorf("failed to set protocol fee: %w", err) - } - - s.log.Info("Initialized proxy with implementation", - zap.String("proxy", proxyAddr), - zap.String("implementation", implAddr)) - - return nil - }}, - } - - connectionContractName := "centralized-connection" - implContractName := "xcall-impl-v5" - proxyContractName := "xcall-proxy" - - s.IBCAddresses["xcall-proxy"] = senderAddress + "." + proxyContractName - s.IBCAddresses["xcall-impl"] = senderAddress + "." + implContractName - s.IBCAddresses["connection"] = senderAddress + "." + connectionContractName - - deployedContracts := make(map[string]string) - - for _, deployment := range deployments { - contractAddress := senderAddress + "." + deployment.name - deployedContracts[deployment.name] = contractAddress - - contract, err := s.client.GetContractById(ctx, contractAddress) - if err != nil { - return fmt.Errorf("failed to check contract existence for %s: %w", deployment.name, err) - } - if contract != nil { - txResp, err := s.client.GetTransactionById(ctx, contract.TxId) - if err == nil { - receipt, err := stacksClient.GetReceipt(txResp) - if err == nil && receipt.Status { - s.log.Info("Contract already successfully deployed, skipping", - zap.String("contract", deployment.name), - zap.String("address", contractAddress)) - continue - } - } - } - - codeBody, err := os.ReadFile(s.testconfig.Contracts[deployment.contract]) - if err != nil { - return fmt.Errorf("failed to read contract code for %s: %w", deployment.name, err) - } - - tx, err := transaction.MakeContractDeploy( - deployment.name, - string(codeBody), - *s.network, - senderAddress, - privateKey, - nil, - nil, - ) - if err != nil { - return fmt.Errorf("failed to create contract deploy transaction for %s: %w", deployment.name, err) - } - - txID, err := transaction.BroadcastTransaction(tx, s.network) - if err != nil { - return fmt.Errorf("failed to broadcast transaction for %s: %w", deployment.name, err) - } - - s.log.Info("Deployed contract", - zap.String("contract", deployment.name), - zap.String("txID", txID)) - - if deployment.wait { - err = s.waitForTransactionConfirmation(ctx, txID) - if err != nil { - return fmt.Errorf("failed to confirm transaction for %s: %w", deployment.name, err) - } - } - - if deployment.postDeploy != nil { - if err := deployment.postDeploy(contractAddress); err != nil { - return fmt.Errorf("post-deployment initialization failed for %s: %w", deployment.name, err) - } - } - } - - s.IBCAddresses["xcall-proxy"] = deployedContracts["xcall-proxy"] - s.IBCAddresses["xcall-impl"] = deployedContracts["xcall-impl-v5"] - s.IBCAddresses["connection"] = deployedContracts["centralized-connection"] - - return nil -} - -func (s *StacksLocalnet) setDefaultConnection(ctx context.Context, privateKey []byte, senderAddress string) error { - nid := "test" - connectionAddress := senderAddress + "." + "centralized-connection" - - nidArg, err := clarity.NewStringASCII(nid) - if err != nil { - return fmt.Errorf("failed to create nid argument: %w", err) - } - - connArg, err := clarity.NewStringASCII(connectionAddress) - if err != nil { - return fmt.Errorf("failed to create connection address argument: %w", err) - } - - implAddr := senderAddress + "." + "xcall-impl-v5" - implPrincipal, err := clarity.StringToPrincipal(implAddr) - if err != nil { - return fmt.Errorf("failed to convert implementation address to principal: %w", err) - } - - args := []clarity.ClarityValue{ - nidArg, - connArg, - implPrincipal, - } - - txCall, err := transaction.MakeContractCall( - senderAddress, - "xcall-proxy", - "set-default-connection", - args, - *s.network, - senderAddress, - privateKey, - nil, - nil, - ) - - if err != nil { - return fmt.Errorf("failed to create set-default-connection transaction: %w", err) - } - - txID, err := transaction.BroadcastTransaction(txCall, s.network) - if err != nil { - return fmt.Errorf("failed to broadcast set-default-connection transaction: %w", err) - } - - s.log.Info("Set default connection in xcall-impl", zap.String("txID", txID)) - - err = s.waitForTransactionConfirmation(ctx, txID) - if err != nil { - return err - } - - return nil -} - -func (s *StacksLocalnet) initializeXCallImpl(ctx context.Context, privateKey []byte, senderAddress string) error { - nid := s.cfg.ChainID - addr := senderAddress - - nidArg, err := clarity.NewStringASCII(nid) - if err != nil { - return fmt.Errorf("failed to create nid argument: %w", err) - } - - addrArg, err := clarity.NewStringASCII(addr) - if err != nil { - return fmt.Errorf("failed to create addr argument: %w", err) - } - - args := []clarity.ClarityValue{nidArg, addrArg} - - txCall, err := transaction.MakeContractCall( - senderAddress, - "xcall-impl-v5", - "init", - args, - *s.network, - senderAddress, - privateKey, - nil, - nil, - ) - if err != nil { - return fmt.Errorf("failed to create init transaction: %w", err) - } - - txID, err := transaction.BroadcastTransaction(txCall, s.network) - if err != nil { - return fmt.Errorf("failed to broadcast init transaction: %w", err) - } - - s.log.Info("Initialized xcall-impl contract", zap.String("txID", txID)) - - err = s.waitForTransactionConfirmation(ctx, txID) - if err != nil { - return err - } - - return nil -} - -func (s *StacksLocalnet) setConnectionFees(ctx context.Context, privateKey []byte, senderAddress string) error { - networks := []string{"stacks_testnet", "test"} - messageFees := map[string]uint64{"stacks_testnet": 500000, "test": 1000000} - responseFees := map[string]uint64{"stacks_testnet": 250000, "test": 500000} - - for _, nid := range networks { - nidArg, err := clarity.NewStringASCII(nid) - if err != nil { - return fmt.Errorf("failed to create nid argument: %w", err) - } - - messageFeeArg, _ := clarity.NewUInt(messageFees[nid]) - responseFeeArg, _ := clarity.NewUInt(responseFees[nid]) - - args := []clarity.ClarityValue{ - nidArg, - messageFeeArg, - responseFeeArg, - } - - txCall, err := transaction.MakeContractCall( - senderAddress, - "centralized-connection", - "set-fee", - args, - *s.network, - senderAddress, - privateKey, - nil, - nil, - ) - if err != nil { - return fmt.Errorf("failed to create set-fee transaction: %w", err) - } - - txID, err := transaction.BroadcastTransaction(txCall, s.network) - if err != nil { - return fmt.Errorf("failed to broadcast set-fee transaction: %w", err) - } - - s.log.Info("Set fee in centralized-connection", zap.String("txID", txID), zap.String("nid", nid)) - - err = s.waitForTransactionConfirmation(ctx, txID) - if err != nil { - return err - } - } - - return nil -} - -func (s *StacksLocalnet) setProtocolFee(ctx context.Context, privateKey []byte, senderAddress string) error { - protocolFee := uint64(100000) - protocolFeeClarity, _ := clarity.NewUInt(protocolFee) - - implAddr := s.IBCAddresses["xcall-impl"] - implPrincipal, err := clarity.StringToPrincipal(implAddr) - if err != nil { - return fmt.Errorf("failed to convert implPrincipal to principal: %w", err) - } - - args := []clarity.ClarityValue{ - protocolFeeClarity, - implPrincipal, - } - - txCall, err := transaction.MakeContractCall( - senderAddress, - "xcall-proxy", - "set-protocol-fee", - args, - *s.network, - senderAddress, - privateKey, - nil, - nil, - ) - if err != nil { - return fmt.Errorf("failed to create set-protocol-fee transaction: %w", err) - } - - txID, err := transaction.BroadcastTransaction(txCall, s.network) - if err != nil { - return fmt.Errorf("failed to broadcast set-protocol-fee transaction: %w", err) - } - - s.log.Info("Set protocol fee in xcall-proxy", zap.String("txID", txID)) - - err = s.waitForTransactionConfirmation(ctx, txID) - if err != nil { - return err - } - - return nil -} - -func (s *StacksLocalnet) setAdminXCallImpl(ctx context.Context, privateKey []byte, senderAddress string) error { - senderPrincipal, err := clarity.StringToPrincipal(senderAddress) - if err != nil { - return fmt.Errorf("failed to convert senderAddress to principal: %w", err) - } - - args := []clarity.ClarityValue{ - senderPrincipal, - } - - txCall, err := transaction.MakeContractCall( - senderAddress, - "xcall-impl-v5", - "set-admin", - args, - *s.network, - senderAddress, - privateKey, - nil, - nil, - ) - if err != nil { - return fmt.Errorf("failed to create set-admin transaction: %w", err) - } - - txID, err := transaction.BroadcastTransaction(txCall, s.network) - if err != nil { - return fmt.Errorf("failed to broadcast set-admin transaction: %w", err) - } - - s.log.Info("Set admin for xcall-impl", zap.String("txID", txID)) - - err = s.waitForTransactionConfirmation(ctx, txID) - if err != nil { - return err - } - - return nil -} - -func (s *StacksLocalnet) setProtocolFeeHandler(ctx context.Context, privateKey []byte, senderAddress string) error { - connAddr := s.IBCAddresses["connection"] - connPrincipal, err := clarity.StringToPrincipal(connAddr) - if err != nil { - return fmt.Errorf("failed to create connection principal: %w", err) - } - - implAddr := s.IBCAddresses["xcall-impl"] - - implPrincipal, err := clarity.StringToPrincipal(implAddr) - if err != nil { - return fmt.Errorf("failed to convert implPrincipal to principal: %w", err) - } - - args := []clarity.ClarityValue{ - connPrincipal, - implPrincipal, - } - - txCall, err := transaction.MakeContractCall( - senderAddress, - "xcall-proxy", - "set-protocol-fee-handler", - args, - *s.network, - senderAddress, - privateKey, - nil, - nil, - ) - if err != nil { - return fmt.Errorf("failed to create set-protocol-fee-handler transaction: %w", err) - } - - txID, err := transaction.BroadcastTransaction(txCall, s.network) - if err != nil { - return fmt.Errorf("failed to broadcast set-protocol-fee-handler transaction: %w", err) - } - - s.log.Info("Set protocol fee handler in xcall-proxy", zap.String("txID", txID)) - - err = s.waitForTransactionConfirmation(ctx, txID) - if err != nil { - return err - } - - return nil -} - -func (s *StacksLocalnet) SetupConnection(ctx context.Context, target chains.Chain) error { - if s.testconfig.Environment == "preconfigured" { - return nil - } - - privateKey, senderAddress, err := s.loadPrivateKey(s.testconfig.KeystoreFile, s.testconfig.KeystorePassword) - if err != nil { - return fmt.Errorf("failed to load deployer's private key: %w", err) - } - - connectionContractName := "centralized-connection" - contractAddress := senderAddress + "." + connectionContractName - - contract, err := s.client.GetContractById(ctx, contractAddress) - if err == nil && contract != nil { - txResp, err := s.client.GetTransactionById(ctx, contract.TxId) - if err == nil { - receipt, err := stacksClient.GetReceipt(txResp) - if err == nil && receipt.Status { - s.log.Info("Connection contract already successfully deployed, skipping deployment", - zap.String("address", contractAddress)) - - s.IBCAddresses["connection"] = contractAddress - return s.initializeConnection(ctx, privateKey, senderAddress) - } - } - } - - codeBody, err := os.ReadFile(s.testconfig.Contracts["connection"]) - if err != nil { - return fmt.Errorf("failed to read connection contract code: %w", err) - } - - tx, err := transaction.MakeContractDeploy( - connectionContractName, - string(codeBody), - *s.network, - senderAddress, - privateKey, - nil, - nil, - ) - if err != nil { - return fmt.Errorf("failed to create contract deploy transaction: %w", err) - } - - txID, err := transaction.BroadcastTransaction(tx, s.network) - if err != nil { - return fmt.Errorf("failed to broadcast transaction: %w", err) - } - - s.log.Info("Deployed centralized-connection contract", zap.String("txID", txID)) - s.IBCAddresses["connection"] = contractAddress - - err = s.waitForTransactionConfirmation(ctx, txID) - if err != nil { - return err - } - - return s.initializeConnection(ctx, privateKey, senderAddress) -} - -func (s *StacksLocalnet) isConnectionInitialized(ctx context.Context, contractAddress string) (bool, error) { - parts := strings.Split(contractAddress, ".") - if len(parts) != 2 { - return false, fmt.Errorf("invalid contract ID format: %s", contractAddress) - } - contractAddress = parts[0] - contractName := parts[1] - - result, err := s.client.CallReadOnlyFunction( - ctx, - contractAddress, - contractName, - "get-xcall", - []string{}, - ) - if err != nil { - return false, fmt.Errorf("failed to check connection initialization: %w", err) - } - - byteResult, err := hex.DecodeString(strings.TrimPrefix(*result, "0x")) - if err != nil { - return false, fmt.Errorf("failed to hex decode get-xcall response: %w", err) - } - - clarityValue, err := clarity.DeserializeClarityValue(byteResult) - if err != nil { - return false, fmt.Errorf("failed to deserialize get-xcall response: %w", err) - } - - responseValue, ok := clarityValue.(*clarity.ResponseOk) - if !ok { - return false, fmt.Errorf("unexpected response type: %T", clarityValue) - } - - _, ok = responseValue.Value.(*clarity.OptionNone) - if ok { - return false, nil - } - - return true, nil -} - -func (s *StacksLocalnet) initializeConnection(ctx context.Context, privateKey []byte, senderAddress string) error { - contractAddress := s.IBCAddresses["connection"] - initialized, err := s.isConnectionInitialized(ctx, contractAddress) - if err != nil { - return fmt.Errorf("failed to check connection initialization status: %w", err) - } - - if initialized { - s.log.Info("Connection contract already initialized, skipping initialization") - return nil - } - - xcallAddress := s.IBCAddresses["xcall-proxy"] - relayerAddress := s.testconfig.RelayWalletAddress - - xcallPrincipal, err := clarity.StringToPrincipal(xcallAddress) - if err != nil { - return fmt.Errorf("invalid xcall address: %w", err) - } - relayerPrincipal, err := clarity.StringToPrincipal(relayerAddress) - if err != nil { - return fmt.Errorf("invalid relayer address: %w", err) - } - - args := []clarity.ClarityValue{xcallPrincipal, relayerPrincipal} - - txCall, err := transaction.MakeContractCall( - senderAddress, - "centralized-connection", - "initialize", - args, - *s.network, - senderAddress, - privateKey, - nil, - nil, - ) - if err != nil { - return fmt.Errorf("failed to create contract call transaction: %w", err) - } - - txID, err := transaction.BroadcastTransaction(txCall, s.network) - if err != nil { - return fmt.Errorf("failed to broadcast transaction: %w", err) - } - - s.log.Info("Initialized centralized-connection contract", zap.String("txID", txID)) - - err = s.waitForTransactionConfirmation(ctx, txID) - if err != nil { - return err - } - - return nil -} - -func shortenContractName(testcase string) string { - // Stacks has a contract name limit defined in SIP-003 - maxLength := 30 - prefix := "x-dapp-" - - cleaned := strings.Map(func(r rune) rune { - if r >= 'a' && r <= 'z' || r >= '0' && r <= '9' || r == '-' { - return r - } - return '-' - }, strings.ToLower(testcase)) - - totalLen := len(prefix) + len(cleaned) - if totalLen > maxLength { - remaining := maxLength - len(prefix) - if remaining > 0 { - cleaned = cleaned[:remaining] - } else { - cleaned = "" - } - } - return prefix + cleaned -} - -func (s *StacksLocalnet) DeployXCallMockApp(ctx context.Context, keyName string, connections []chains.XCallConnection) error { - if s.testconfig.Environment == "preconfigured" { - return nil - } - - testcase := ctx.Value("testcase").(string) - appContractName := shortenContractName(testcase) - - privateKey, senderAddress, err := s.loadPrivateKey(s.testconfig.KeystoreFile, s.testconfig.KeystorePassword) - if err != nil { - return fmt.Errorf("failed to load deployer's private key: %w", err) - } - - contractAddress := senderAddress + "." + appContractName - - contract, err := s.client.GetContractById(ctx, contractAddress) - if err == nil && contract != nil { - txResp, err := s.client.GetTransactionById(ctx, contract.TxId) - if err == nil { - receipt, err := stacksClient.GetReceipt(txResp) - if err == nil && receipt.Status { - s.log.Info("XCall mock app contract already successfully deployed, skipping deployment", - zap.String("address", contractAddress)) - - s.IBCAddresses[fmt.Sprintf("dapp-%s", testcase)] = contractAddress - return nil - } - } - } - - codeBody, err := os.ReadFile(s.testconfig.Contracts["dapp"]) - if err != nil { - return fmt.Errorf("failed to read dapp contract code: %w", err) - } - - tx, err := transaction.MakeContractDeploy( - appContractName, - string(codeBody), - *s.network, - senderAddress, - privateKey, - nil, - nil, - ) - if err != nil { - return fmt.Errorf("failed to create contract deploy transaction: %w", err) - } - - txID, err := transaction.BroadcastTransaction(tx, s.network) - if err != nil { - return fmt.Errorf("failed to broadcast transaction: %w", err) - } - - s.log.Info("Deployed xcall mock app contract", - zap.String("txID", txID), - zap.String("contractName", appContractName)) - - s.IBCAddresses[fmt.Sprintf("dapp-%s", testcase)] = contractAddress - - err = s.waitForTransactionConfirmation(ctx, txID) - if err != nil { - return err - } - - xcallAddress := s.IBCAddresses["xcall-proxy"] - xcallPrincipal, err := clarity.StringToPrincipal(xcallAddress) - if err != nil { - return fmt.Errorf("invalid xcall address: %w", err) - } - - args := []clarity.ClarityValue{xcallPrincipal} - - txCall, err := transaction.MakeContractCall( - senderAddress, - appContractName, - "initialize", - args, - *s.network, - senderAddress, - privateKey, - nil, - nil, - ) - if err != nil { - return fmt.Errorf("failed to create contract call transaction: %w", err) - } - - txID, err = transaction.BroadcastTransaction(txCall, s.network) - if err != nil { - return fmt.Errorf("failed to broadcast transaction: %w", err) - } - - s.log.Info("Initialized xcall mock app contract", zap.String("txID", txID)) - - err = s.waitForTransactionConfirmation(ctx, txID) - if err != nil { - return err - } - - for _, connection := range connections { - s.log.Debug("Setting up connection", - zap.String("nid", connection.Nid), - zap.String("destination", connection.Destination)) - err := s.addConnection(ctx, senderAddress, appContractName, privateKey, connection) - if err != nil { - s.log.Error("Failed to add connection", - zap.Error(err), - zap.String("nid", connection.Nid)) - continue - } - } - - return nil -} - -func (s *StacksLocalnet) isConnectionExists(ctx context.Context, contractAddress, contractName, nid, source, destination string) (bool, error) { - sourcesResult, err := s.client.CallReadOnlyFunction( - ctx, - contractAddress, - contractName, - "get-sources", - []string{ - fmt.Sprintf("0x%s", hex.EncodeToString([]byte(nid))), - }, - ) - if err != nil { - return false, fmt.Errorf("failed to check sources: %w", err) - } - - destsResult, err := s.client.CallReadOnlyFunction( - ctx, - contractAddress, - contractName, - "get-destinations", - []string{ - fmt.Sprintf("0x%s", hex.EncodeToString([]byte(nid))), - }, - ) - if err != nil { - return false, fmt.Errorf("failed to check destinations: %w", err) - } - - sourceBytes, err := hex.DecodeString(strings.TrimPrefix(*sourcesResult, "0x")) - if err != nil { - return false, fmt.Errorf("failed to decode sources response: %w", err) - } - - sourcesValue, err := clarity.DeserializeClarityValue(sourceBytes) - if err != nil { - return false, fmt.Errorf("failed to deserialize sources: %w", err) - } - - destBytes, err := hex.DecodeString(strings.TrimPrefix(*destsResult, "0x")) - if err != nil { - return false, fmt.Errorf("failed to decode destinations response: %w", err) - } - - destsValue, err := clarity.DeserializeClarityValue(destBytes) - if err != nil { - return false, fmt.Errorf("failed to deserialize destinations: %w", err) - } - - sourcesList, ok := sourcesValue.(*clarity.List) - if !ok { - return false, fmt.Errorf("unexpected sources type: %T", sourcesValue) - } - - destsList, ok := destsValue.(*clarity.List) - if !ok { - return false, fmt.Errorf("unexpected destinations type: %T", destsValue) - } - - sourceExists := false - for _, item := range sourcesList.Values { - if stringVal, ok := item.(*clarity.StringASCII); ok { - if stringVal.Data == source { - sourceExists = true - break - } - } - } - - destExists := false - for _, item := range destsList.Values { - if stringVal, ok := item.(*clarity.StringASCII); ok { - if stringVal.Data == destination { - destExists = true - break - } - } - } - - s.log.Debug("Connection check result", - zap.String("nid", nid), - zap.String("source", source), - zap.String("destination", destination), - zap.Bool("sourceExists", sourceExists), - zap.Bool("destExists", destExists)) - - return sourceExists && destExists, nil -} - -func (s *StacksLocalnet) addConnection(ctx context.Context, senderAddress, appContractName string, privateKey []byte, connection chains.XCallConnection) error { - connAddress := s.IBCAddresses[connection.Connection] - - connArg, err := clarity.NewStringASCII(connAddress) - if err != nil { - return fmt.Errorf("failed to create connection argument: %w", err) - } - - destArg, err := clarity.NewStringASCII(connection.Destination) - if err != nil { - return fmt.Errorf("failed to create destination argument: %w", err) - } - - nidArg, err := clarity.NewStringASCII(connection.Nid) - if err != nil { - return fmt.Errorf("failed to create nid argument: %w", err) - } - - args := []clarity.ClarityValue{ - nidArg, - connArg, - destArg, - } - - parts := strings.Split(connAddress, ".") - if len(parts) != 2 { - return fmt.Errorf("invalid connection address format: %s", connAddress) - } - contractName := parts[1] - - exists, err := s.isConnectionExists(ctx, senderAddress, appContractName, - connection.Nid, contractName, connection.Destination) - if err != nil { - s.log.Warn("Failed to check existing connection", - zap.Error(err), - zap.String("nid", connection.Nid)) - } - - if exists { - s.log.Info("Connection already exists, skipping", - zap.String("nid", connection.Nid), - zap.String("source", contractName), - zap.String("destination", connection.Destination)) - return nil - } - - txCall, err := transaction.MakeContractCall( - senderAddress, - appContractName, - "add-connection", - args, - *s.network, - senderAddress, - privateKey, - nil, - nil, - ) - if err != nil { - return fmt.Errorf("failed to create contract call transaction: %w", err) - } - - txID, err := transaction.BroadcastTransaction(txCall, s.network) - if err != nil { - return fmt.Errorf("failed to broadcast transaction: %w", err) - } - - s.log.Info("Adding new connection to xcall mock app", - zap.String("txID", txID), - zap.String("nid", connection.Nid), - zap.String("source", contractName), - zap.String("destination", connection.Destination)) - - err = s.waitForTransactionConfirmation(ctx, txID) - if err != nil { - return fmt.Errorf("failed to confirm transaction: %w", err) - } - - s.log.Info("Successfully added new connection", - zap.String("nid", connection.Nid), - zap.String("source", contractName), - zap.String("destination", connection.Destination)) - - return nil -} - func (s *StacksLocalnet) SendPacketXCall(ctx context.Context, keyName, _to string, data, rollback []byte) (context.Context, error) { testcase := ctx.Value("testcase").(string) dappKey := fmt.Sprintf("dapp-%s", testcase) @@ -1146,294 +198,6 @@ func (s *StacksLocalnet) SendPacketXCall(ctx context.Context, keyName, _to strin return ctx, nil } -func (s *StacksLocalnet) extractSnFromTransaction(ctx context.Context, txID string) (string, error) { - tx, err := s.client.GetTransactionById(ctx, txID) - if err != nil { - return "", fmt.Errorf("failed to get transaction by ID: %w", err) - } - - if confirmed := tx.GetTransactionList200ResponseResultsInner; confirmed != nil { - if contractCall := confirmed.ContractCallTransaction; contractCall != nil { - for _, event := range contractCall.Events { - if event.SmartContractLogTransactionEvent != nil { - contractLog := event.SmartContractLogTransactionEvent.ContractLog - if contractLog.Topic == "print" { - repr := contractLog.Value.Repr - s.log.Debug("Found event log", - zap.String("repr", repr), - zap.String("topic", contractLog.Topic)) - if strings.Contains(repr, "CallMessageSent") { - s.log.Debug("Found CallMessageSent event", - zap.String("full_event", repr)) - startIdx := strings.Index(repr, "(sn u") - if startIdx != -1 { - startIdx += 5 // Move past "(sn u" - endIdx := strings.Index(repr[startIdx:], ")") - if endIdx != -1 { - sn := repr[startIdx : startIdx+endIdx] - s.log.Info("Successfully extracted sn", - zap.String("sn", sn)) - return sn, nil - } - } - } - } - } - } - } - } - - return "", fmt.Errorf("serial number 'sn' not found in transaction events") -} - -func (s *StacksLocalnet) FindEvent(ctx context.Context, startHeight uint64, contract, signature string, index []string) (*blockchainApiClient.SmartContractLogTransactionEvent, error) { - for { - select { - case <-ctx.Done(): - return nil, fmt.Errorf("context cancelled while finding event %s", signature) - default: - events, err := s.client.GetContractEvents(ctx, contract, 50, 0) - if err != nil { - return nil, fmt.Errorf("failed to get contract events: %w", err) - } - - for _, event := range events.Results { - if event.SmartContractLogTransactionEvent != nil && - event.SmartContractLogTransactionEvent.ContractLog.Topic == signature { - return event.SmartContractLogTransactionEvent, nil - } - } - - time.Sleep(BLOCK_TIME) - } - } -} - -func (s *StacksLocalnet) FindCallMessage(ctx context.Context, startHeight uint64, from, to, sn string) (string, string, error) { - for { - select { - case <-ctx.Done(): - return "", "", fmt.Errorf("context cancelled while finding call message with sn %s", sn) - default: - events, err := s.client.GetContractEvents(ctx, s.IBCAddresses["xcall-proxy"], 50, 0) - if err != nil { - return "", "", fmt.Errorf("failed to get contract events: %w", err) - } - - for _, event := range events.Results { - if event.SmartContractLogTransactionEvent != nil { - log := event.SmartContractLogTransactionEvent.ContractLog - if log.Topic == "print" && strings.Contains(log.Value.Repr, "CallMessage") { - eventSn := extractSnFromEvent(log.Value.Repr) - if eventSn == sn { - reqId, data := extractCallMessageData(log.Value.Repr) - if reqId != "" && data != "" { - return reqId, data, nil - } - } - } - } - } - - time.Sleep(BLOCK_TIME) - } - } -} - -func (s *StacksLocalnet) FindCallResponse(ctx context.Context, startHeight uint64, sn string) (string, error) { - for { - select { - case <-ctx.Done(): - return "", fmt.Errorf("context cancelled while finding call response with sn %s", sn) - default: - events, err := s.client.GetContractEvents(ctx, s.IBCAddresses["xcall-proxy"], 50, 0) - if err != nil { - return "", fmt.Errorf("failed to get contract events: %w", err) - } - - for _, event := range events.Results { - if event.SmartContractLogTransactionEvent != nil { - log := event.SmartContractLogTransactionEvent.ContractLog - if log.Topic == "print" && strings.Contains(log.Value.Repr, "CallResponse") { - eventSn := extractSnFromEvent(log.Value.Repr) - if eventSn == sn { - return event.SmartContractLogTransactionEvent.TxId, nil - } - } - } - } - - time.Sleep(BLOCK_TIME) - } - } -} - -func (s *StacksLocalnet) FindRollbackExecutedMessage(ctx context.Context, startHeight uint64, sn string) (string, error) { - for { - select { - case <-ctx.Done(): - return "", fmt.Errorf("context cancelled while finding rollback message with sn %s", sn) - default: - events, err := s.client.GetContractEvents(ctx, s.IBCAddresses["xcall-proxy"], 50, 0) - if err != nil { - return "", fmt.Errorf("failed to get contract events: %w", err) - } - - for _, event := range events.Results { - if event.SmartContractLogTransactionEvent != nil { - log := event.SmartContractLogTransactionEvent.ContractLog - if log.Topic == "print" && strings.Contains(log.Value.Repr, "RollbackExecuted") { - eventSn := extractSnFromEvent(log.Value.Repr) - if eventSn == sn { - return sn, nil - } - } - } - } - - time.Sleep(BLOCK_TIME) - } - } -} - -func (s *StacksLocalnet) FindTargetXCallMessage(ctx context.Context, target chains.Chain, height uint64, to string) (*chains.XCallResponse, error) { - for { - select { - case <-ctx.Done(): - return nil, fmt.Errorf("context cancelled while finding target xcall message") - default: - events, err := s.client.GetContractEvents(ctx, s.IBCAddresses["xcall-proxy"], 50, 0) - if err != nil { - return nil, fmt.Errorf("failed to get contract events: %w", err) - } - - for _, event := range events.Results { - if event.SmartContractLogTransactionEvent != nil { - log := event.SmartContractLogTransactionEvent.ContractLog - if log.Topic == "print" { - if strings.Contains(log.Value.Repr, "EmitMessage") { - sn, msg, targetNetwork := extractEmitMessageData(log.Value.Repr) - if targetNetwork == to { - return &chains.XCallResponse{ - SerialNo: sn, - Data: msg, - }, nil - } - } else if strings.Contains(log.Value.Repr, "CallMessage") { - sn, reqId, data := extractFullCallMessageData(log.Value.Repr) - return &chains.XCallResponse{ - SerialNo: sn, - RequestID: reqId, - Data: data, - }, nil - } - } - } - } - - time.Sleep(BLOCK_TIME) - } - } -} - -func extractSnFromEvent(repr string) string { - startIdx := strings.Index(repr, "(sn u") - if startIdx != -1 { - startIdx += 5 // Move past "(sn u" - endIdx := strings.Index(repr[startIdx:], ")") - if endIdx != -1 { - return repr[startIdx : startIdx+endIdx] - } - } - return "" -} - -func extractCallMessageData(repr string) (reqId, data string) { - reqIdStart := strings.Index(repr, "reqId u") - if reqIdStart != -1 { - reqIdStart += 7 - reqIdEnd := strings.Index(repr[reqIdStart:], " ") - if reqIdEnd != -1 { - reqId = repr[reqIdStart : reqIdStart+reqIdEnd] - } - } - - dataStart := strings.Index(repr, "data 0x") - if dataStart != -1 { - dataStart += 7 - dataEnd := strings.Index(repr[dataStart:], ")") - if dataEnd != -1 { - data = repr[dataStart : dataStart+dataEnd] - } - } - - return reqId, data -} - -func extractEmitMessageData(repr string) (sn, msg, targetNetwork string) { - sn = extractSnFromEvent(repr) - - msgStart := strings.Index(repr, "msg 0x") - if msgStart != -1 { - msgStart += 6 - msgEnd := strings.Index(repr[msgStart:], " ") - if msgEnd != -1 { - msg = repr[msgStart : msgStart+msgEnd] - } - } - - networkStart := strings.Index(repr, "network \"") - if networkStart != -1 { - networkStart += 9 - networkEnd := strings.Index(repr[networkStart:], "\"") - if networkEnd != -1 { - targetNetwork = repr[networkStart : networkStart+networkEnd] - } - } - - return sn, msg, targetNetwork -} - -func extractFullCallMessageData(repr string) (sn, reqId, data string) { - sn = extractSnFromEvent(repr) - reqId, data = extractCallMessageData(repr) - return sn, reqId, data -} - -func (s *StacksLocalnet) loadPrivateKey(keystoreFile, password string) ([]byte, string, error) { - if s.kms == nil { - return nil, "", fmt.Errorf("KMS not initialized") - } - - encryptedKey, err := os.ReadFile(keystoreFile) - if err != nil { - s.log.Error("Failed to read keystore file", - zap.String("path", keystoreFile), - zap.Error(err)) - return nil, "", fmt.Errorf("failed to read keystore file: %w", err) - } - - privateKey, err := s.kms.Decrypt(context.Background(), encryptedKey) - if err != nil { - s.log.Error("Failed to decrypt keystore", zap.Error(err)) - return nil, "", fmt.Errorf("failed to decrypt keystore: %w", err) - } - - network, err := stacksClient.MapNIDToChainID(s.cfg.ChainID) - if err != nil { - s.log.Error("Chain id not found. Check the NID config", zap.Error(err)) - return nil, "", fmt.Errorf("chain id not found: %w", err) - } - - address, err := crypto.GetAddressFromPrivateKey(privateKey, network) - if err != nil { - s.log.Error("Failed to derive address from private key", zap.Error(err)) - return nil, "", fmt.Errorf("failed to derive address: %w", err) - } - - return privateKey, address, nil -} - func (s *StacksLocalnet) XCall(ctx context.Context, targetChain chains.Chain, keyName, _to string, data, rollback []byte) (*chains.XCallResponse, error) { height, err := targetChain.Height(ctx) if err != nil { @@ -1462,39 +226,3 @@ func (s *StacksLocalnet) XCall(ctx context.Context, targetChain chains.Chain, ke Data: destData, }, nil } - -func (s *StacksLocalnet) waitForTransactionConfirmation(ctx context.Context, txID string) error { - timeout := time.After(MAX_WAIT_TIME) - ticker := time.NewTicker(BLOCK_TIME) - defer ticker.Stop() - - for { - select { - case <-ticker.C: - res, err := s.client.GetTransactionById(ctx, txID) - if err != nil { - s.log.Warn("Failed to query transaction receipt", zap.Error(err)) - continue - } - - receipt, err := stacksClient.GetReceipt(res) - if err != nil { - s.log.Warn("Failed to extract transaction receipt", zap.Error(err)) - continue - } - - if receipt.Status { - s.log.Info("Transaction confirmed", - zap.String("txID", txID), - zap.Uint64("height", receipt.Height)) - return nil - } - s.log.Debug("Transaction not yet confirmed", zap.String("txID", txID)) - - case <-timeout: - return fmt.Errorf("transaction confirmation timed out after %v seconds", MAX_WAIT_TIME) - case <-ctx.Done(): - return ctx.Err() - } - } -} diff --git a/test/chains/stacks/utils.go b/test/chains/stacks/utils.go new file mode 100644 index 00000000..7f293235 --- /dev/null +++ b/test/chains/stacks/utils.go @@ -0,0 +1,123 @@ +package stacks + +import ( + "context" + "fmt" + "os" + "strings" + "time" + + stacksClient "github.com/icon-project/centralized-relay/relayer/chains/stacks" + "github.com/icon-project/stacks-go-sdk/pkg/crypto" + "go.uber.org/zap" +) + +func (s *StacksLocalnet) extractSnFromTransaction(ctx context.Context, txID string) (string, error) { + tx, err := s.client.GetTransactionById(ctx, txID) + if err != nil { + return "", fmt.Errorf("failed to get transaction by ID: %w", err) + } + + if confirmed := tx.GetTransactionList200ResponseResultsInner; confirmed != nil { + if contractCall := confirmed.ContractCallTransaction; contractCall != nil { + for _, event := range contractCall.Events { + if event.SmartContractLogTransactionEvent != nil { + contractLog := event.SmartContractLogTransactionEvent.ContractLog + if contractLog.Topic == "print" { + repr := contractLog.Value.Repr + s.log.Debug("Found event log", + zap.String("repr", repr), + zap.String("topic", contractLog.Topic)) + if strings.Contains(repr, "CallMessageSent") { + s.log.Debug("Found CallMessageSent event", + zap.String("full_event", repr)) + startIdx := strings.Index(repr, "(sn u") + if startIdx != -1 { + startIdx += 5 // Move past "(sn u" + endIdx := strings.Index(repr[startIdx:], ")") + if endIdx != -1 { + sn := repr[startIdx : startIdx+endIdx] + s.log.Info("Successfully extracted sn", + zap.String("sn", sn)) + return sn, nil + } + } + } + } + } + } + } + } + + return "", fmt.Errorf("serial number 'sn' not found in transaction events") +} + +func (s *StacksLocalnet) loadPrivateKey(keystoreFile, password string) ([]byte, string, error) { + if s.kms == nil { + return nil, "", fmt.Errorf("KMS not initialized") + } + + encryptedKey, err := os.ReadFile(keystoreFile) + if err != nil { + s.log.Error("Failed to read keystore file", + zap.String("path", keystoreFile), + zap.Error(err)) + return nil, "", fmt.Errorf("failed to read keystore file: %w", err) + } + + privateKey, err := s.kms.Decrypt(context.Background(), encryptedKey) + if err != nil { + s.log.Error("Failed to decrypt keystore", zap.Error(err)) + return nil, "", fmt.Errorf("failed to decrypt keystore: %w", err) + } + + network, err := stacksClient.MapNIDToChainID(s.cfg.ChainID) + if err != nil { + s.log.Error("Chain id not found. Check the NID config", zap.Error(err)) + return nil, "", fmt.Errorf("chain id not found: %w", err) + } + + address, err := crypto.GetAddressFromPrivateKey(privateKey, network) + if err != nil { + s.log.Error("Failed to derive address from private key", zap.Error(err)) + return nil, "", fmt.Errorf("failed to derive address: %w", err) + } + + return privateKey, address, nil +} + +func (s *StacksLocalnet) waitForTransactionConfirmation(ctx context.Context, txID string) error { + timeout := time.After(MAX_WAIT_TIME) + ticker := time.NewTicker(BLOCK_TIME) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + res, err := s.client.GetTransactionById(ctx, txID) + if err != nil { + s.log.Warn("Failed to query transaction receipt", zap.Error(err)) + continue + } + + receipt, err := stacksClient.GetReceipt(res) + if err != nil { + s.log.Warn("Failed to extract transaction receipt", zap.Error(err)) + continue + } + + if receipt.Status { + s.log.Info("Transaction confirmed", + zap.String("txID", txID), + zap.Uint64("height", receipt.Height)) + return nil + } + s.log.Debug("Transaction not yet confirmed", zap.String("txID", txID)) + + case <-timeout: + return fmt.Errorf("transaction confirmation timed out after %v seconds", MAX_WAIT_TIME) + case <-ctx.Done(): + return ctx.Err() + } + } +}