diff --git a/.gitignore b/.gitignore index 967b8d36..5a12be78 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ artifacts vendor .DS_Store -.*env \ No newline at end of file +.*env +dist \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8eeb98fd..b5ac2559 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ All notable changes to this project will be documented in this file. +## [1.6.0] - 2024-08-12 + +### Added +- SUI chain implementation. +- Add `LastProcessedTxStore` to store the chain specific information about the last processed transaction. + +### Changed +- While switching in between multiple relayer wallet address, set admin before saving config. +- Add two new fields in the relayer's `Message` type: + - `DappModuleCapID` to track to which dapp module the message need to relayed. This is used for `ExecuteCall` and `ExecuteRollback` only. + - `TxInfo` to store the information of transaction in which the message is contained in the source chain. + This field is opaque to relayer's core and its type is known only in the chain's implementation. +- Changed the `Listener` method signature in the chain provider interface from `Listener(ctx context.Context, lastSavedHeight uint64, blockInfo chan *types.BlockInfo) error` to `Listener(ctx context.Context, lastProcessedTx types.LastProcessedTx, blockInfo chan *types.BlockInfo) error`. + + ## [1.5.1] - 2024-08-12 ### Changed diff --git a/Dockerfile b/Dockerfile index d1896cdb..0de33da1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -63,4 +63,4 @@ USER relayer WORKDIR /home/relayer -CMD ["/bin/centralized-relay"] +CMD ["/bin/centralized-relay"] \ No newline at end of file diff --git a/Makefile b/Makefile index 81992fb3..e5c90706 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,10 @@ install: go.sum e2e-test: - @go test -v ./test/e2e -testify.m TestE2E_all + @go test -v ./test/e2e -testify.m TestE2E_all -timeout 30m + +test-all: + @go test -v ./... test-all: @go test -v ./... diff --git a/cmd/config.go b/cmd/config.go index eb77d05d..749d3185 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -9,6 +9,7 @@ import ( jsoniter "github.com/json-iterator/go" + "github.com/icon-project/centralized-relay/relayer/chains/sui" "github.com/icon-project/centralized-relay/relayer/chains/wasm" "github.com/icon-project/centralized-relay/relayer" @@ -224,6 +225,7 @@ func (pcw *ProviderConfigWrapper) UnmarshalJSON(data []byte) error { "icon": reflect.TypeOf(icon.Config{}), "evm": reflect.TypeOf(evm.Config{}), "cosmos": reflect.TypeOf(wasm.Config{}), + "sui": reflect.TypeOf(sui.Config{}), } val, err := UnmarshalJSONProviderConfig(data, customTypes) if err != nil { @@ -255,6 +257,8 @@ func (iw *ProviderConfigYAMLWrapper) UnmarshalYAML(n *yaml.Node) error { iw.Value = new(evm.Config) case "cosmos": iw.Value = new(wasm.Config) + case "sui": + iw.Value = new(sui.Config) default: return fmt.Errorf("%s is an invalid chain type, check your config file", iw.Type) } @@ -268,6 +272,7 @@ func UnmarshalJSONProviderConfig(data []byte, customTypes map[string]reflect.Typ "icon": reflect.TypeOf(icon.Config{}), "evm": reflect.TypeOf(evm.Config{}), "cosmos": reflect.TypeOf(wasm.Config{}), + "sui": reflect.TypeOf(sui.Config{}), } if err := jsoniter.Unmarshal(data, &m); err != nil { return nil, err diff --git a/cmd/contracts.go b/cmd/contracts.go index 8861c6d4..d53db107 100644 --- a/cmd/contracts.go +++ b/cmd/contracts.go @@ -66,6 +66,8 @@ func (c *contractState) getFee() *cobra.Command { if err != nil { return err } + defer client.Close() + defer c.closeSocket() res, err := client.GetFee(c.chain, c.network, true) if err != nil { return err @@ -124,6 +126,7 @@ func (c *contractState) claimFee() *cobra.Command { return err } defer client.Close() + defer c.closeSocket() res, err := client.ClaimFee(c.chain) if err != nil { return err diff --git a/cmd/keystore.go b/cmd/keystore.go index 280717a2..4eebc391 100644 --- a/cmd/keystore.go +++ b/cmd/keystore.go @@ -183,11 +183,11 @@ func (k *keystoreState) use(a *appState) *cobra.Command { fmt.Fprintf(os.Stdout, "Wallet already configured: %s\n", k.address) return nil } - cf.SetWallet(k.address) - if err := a.config.Save(a.homePath); err != nil { + if err := chain.ChainProvider.SetAdmin(cmd.Context(), k.address); err != nil { return err } - if err := chain.ChainProvider.SetAdmin(cmd.Context(), k.address); err != nil { + cf.SetWallet(k.address) + if err := a.config.Save(a.configPath); err != nil { return err } fmt.Fprintf(os.Stdout, "Wallet configured: %s\n", k.address) diff --git a/example/configs/sui.json b/example/configs/sui.json new file mode 100644 index 00000000..da228845 --- /dev/null +++ b/example/configs/sui.json @@ -0,0 +1,35 @@ +{ + "type": "sui", + "value": { + "disabled": false, + "nid": "sui-test", + "rpc-url": "https://fullnode.testnet.sui.io:443", + "address": "0x07304a5d7d1a4763a1cea91f478d24e40aecf1fdbd2f14764d5ad745f4904f85", + "xcall-package-ids": [ + "0xd8acb58553eeefc32077075f4ee2a4dc7e9d65e0aa82639e12784043a0cffce1" + ], + "xcall-storage-id": "0x4655bb7859023e6a8804f31cb746999d9e0758da642aa8e7e18e11c31427c8cc", + "connection-id": "centralized-1", + "connection-cap-id": "0x0bd3506ebbb37bb531342469c4665c3594442b6b004a8bb0e9910e5b04cc57ae", + "dapp-package-id": "0x7d7ae28c5a82c0bdb17a106dbbb236e3ee94e4b12408f04a0a192b20273fb2fd", + "dapp-modules": [ + { + "name": "xcall_manager", + "cap-id": "0xa4ea25a8025e04543408e0ad054321ae98fda932bdf4ee846ba60f6548d64bcb", + "config-id": "0x85df6e0d192cb6f54e0fcdf681f34323a83ed4be871059c897a69eb2a466a34b" + }, + { + "name": "asset_manager", + "cap-id": "0xb31546a6f3a0fa3b265f0572113d6422e81ae7fa455a615d27d2cab8ef85ab93", + "config-id": "0xb5605a51dae249aecd7d70352cf36f589c11822568774c144909110ebd15ee02" + }, + { + "name": "balanced_dollar", + "cap-id": "0x630d4a826c090023600498c562a7dd611ef673268b7a4bd7de63c571684d97cf", + "config-id": "0x2427b3a3b95600749848e69f694ddffef5f96b2a0cc03e3d56d8a8b83ce94826" + } + ], + "gas-limit": 5000000, + "start-tx-digest": "" + } +} diff --git a/go.mod b/go.mod index 4248b0a1..9385c42b 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,11 @@ go 1.22 require ( github.com/CosmWasm/wasmd v0.52.0 github.com/cometbft/cometbft v0.38.10 + 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/fardream/go-bcs v0.4.0 github.com/gofrs/flock v0.8.1 github.com/gorilla/websocket v1.5.3 github.com/icon-project/goloop v1.3.11 @@ -45,8 +47,10 @@ require ( github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd // indirect github.com/btcsuite/btcd/btcutil v1.1.5 // 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 github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect + github.com/coming-chat/go-aptos v0.0.0-20221013022715-39f91035c785 // indirect 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 @@ -60,6 +64,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect 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/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 @@ -70,6 +75,7 @@ require ( github.com/labstack/gommon v0.4.1 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect @@ -82,6 +88,7 @@ require ( github.com/sagikazarmark/locafero v0.6.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/shamaton/msgpack/v2 v2.2.0 // indirect + github.com/shopspring/decimal v1.3.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/tinylib/msgp v1.1.9 // indirect @@ -116,7 +123,7 @@ require ( cosmossdk.io/collections v0.4.0 // indirect cosmossdk.io/core v0.11.0 // indirect cosmossdk.io/depinject v1.0.0-alpha.4 // indirect - cosmossdk.io/errors v1.0.1 // indirect + cosmossdk.io/errors v1.0.1 cosmossdk.io/log v1.3.1 // indirect cosmossdk.io/math v1.3.0 // indirect cosmossdk.io/store v1.1.0 // indirect diff --git a/go.sum b/go.sum index e946c286..2b814010 100644 --- a/go.sum +++ b/go.sum @@ -338,6 +338,8 @@ github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6 github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts= +github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= @@ -408,6 +410,10 @@ github.com/cometbft/cometbft v0.38.10 h1:2ePuglchT+j0Iao+cfmt/nw5U7K2lnGDzXSUPGV 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/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= +github.com/coming-chat/go-sui/v2 v2.0.1/go.mod h1:0/cgsi6HcHEfPFC05mY/ovzWuxxpmKxiY0NIEFgMP4g= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= @@ -524,6 +530,8 @@ github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 h1:KrE8I4reeV github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0/go.mod h1:D9AJLVXSyZQXJQVk8oh1EwjISE+sJTn2duYIZC0dy3w= 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= +github.com/fardream/go-bcs v0.4.0/go.mod h1:UsoxhIoe2GsVexX0s5NDLIChxeb/JUbjw7IWzzgF3Xk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= @@ -591,8 +599,8 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+ 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.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= -github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +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-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= @@ -944,6 +952,8 @@ github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eI github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -1132,6 +1142,8 @@ github.com/shamaton/msgpack/v2 v2.2.0 h1:IP1m01pHwCrMa6ZccP9B3bqxEMKMSmMVAVKk54g 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= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= +github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -1307,6 +1319,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= diff --git a/go.work.sum b/go.work.sum index 73d3c1cd..3215e8cc 100644 --- a/go.work.sum +++ b/go.work.sum @@ -13,6 +13,7 @@ cloud.google.com/go/analytics v0.23.2/go.mod h1:vtE3olAXZ6edJYk1UOndEs6EfaEc9T2B 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= cloud.google.com/go/apigeeregistry v0.8.5/go.mod h1:ZMg60hq2K35tlqZ1VVywb9yjFzk9AJ7zqxrysOxLi3o= +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.8.7/go.mod h1:L/xTq4NLP9mmxiGdcsVz7y1JLc9DI8pfaXRXbnjkR6w= cloud.google.com/go/artifactregistry v1.14.9/go.mod h1:n2OsUqbYoUI2KxpzQZumm6TtBgtRf++QulEohdnlsvI= @@ -44,6 +45,7 @@ cloud.google.com/go/dataform v0.9.4/go.mod h1:jjo4XY+56UrNE0wsEQsfAw4caUs4DLJVSy cloud.google.com/go/datafusion v1.7.7/go.mod h1:qGTtQcUs8l51lFA9ywuxmZJhS4ozxsBSus6ItqCUWMU= 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.8.7/go.mod h1:hvxGaSvINAVH5EJJsONIwT1y+B7OQogjHPjizOFoWOo= cloud.google.com/go/datastore v1.17.0/go.mod h1:RiRZU0G6VVlIVlv1HRo3vSAPFHULV0ddBNsXO+Sony4= @@ -60,10 +62,12 @@ cloud.google.com/go/eventarc v1.13.6/go.mod h1:QReOaYnDNdjwAQQWNC7nfr63WnaKFUw7M 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.16.2/go.mod h1:+gMvV5E3nMb9EPqX6XwRb646jTyVz8q4yk3DD6xxHpg= +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.8.7/go.mod h1:iUH1jgQpTyNFMK5LgXEq2o0beIJ2p7KKUUFerkf/eGc= 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.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 v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= cloud.google.com/go/iam v1.1.7/go.mod h1:J4PMPg8TtyurAUvSmPj8FF3EDgY1SPRZxcUGrn7WXGA= @@ -109,7 +113,10 @@ cloud.google.com/go/scheduler v1.10.8/go.mod h1:0YXHjROF1f5qTMvGTm4o7GH1PGAcmu/H cloud.google.com/go/secretmanager v1.13.0/go.mod h1:yWdfNmM2sLIiyv6RM6VqWKeBV7CdS0SO3ybxJJRhBEs= cloud.google.com/go/security v1.16.1/go.mod h1:UoF8QXvvJlV9ORs4YW/izW5GmDQtFUoq2P6TJgPlif8= cloud.google.com/go/securitycenter v1.30.0/go.mod h1:/tmosjS/dfTnzJxOzZhTXdX3MXWsCmPWfcYOgkJmaJk= +cloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk= cloud.google.com/go/servicedirectory v1.11.6/go.mod h1:peVGYNc1xArhcqSuhPP+NXp8kdl22XhB5E8IiNBNfZY= +cloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4= +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.23.1/go.mod h1:UNgzNxhNBuo/OxpF1rMhA/U2rdai7ILL6PBXFs70wq0= @@ -149,17 +156,33 @@ github.com/Abirdcfly/dupword v0.0.11/go.mod h1:wH8mVGuf3CP5fsBTkfWwwwKTjDnVVCxtU github.com/Antonboom/errname v0.1.9/go.mod h1:nLTcJzevREuAsgTbG85UsuiWpMpAqbKD1HNZ29OzE58= 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= github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.2.0/go.mod h1:c+Lifp3EDEamAkPVzMooRNOK6CZjNSdEnf1A7jsI9u4= 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/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= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= 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/wasmvm v1.4.0 h1:84I3MlvvzcOo2z+ed0ztPi7eeDNk6/sYuK76uyXP1nI= +github.com/CosmWasm/wasmvm v1.4.0/go.mod h1:vW/E3h8j9xBQs9bCoijDuawKo9kCtxOaS8N8J7KFtkc= +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/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.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= @@ -172,8 +195,11 @@ github.com/OpenPeeDeeP/depguard v1.1.1/go.mod h1:JtAMzWkmFEzDPyAd+W0NHl1lvpQKTvT github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/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/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/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.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= 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= @@ -184,10 +210,14 @@ github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cv 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/brotli v1.0.5/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/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/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-v2 v1.21.2/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM= github.com/aws/aws-sdk-go-v2/config v1.18.45/go.mod h1:ZwDUgFnQgsazQTnWfeLWk5GjeqTQTL8lMkoE1UXzxdE= github.com/aws/aws-sdk-go-v2/credentials v1.13.43/go.mod h1:zWJBz1Yf1ZtX5NGax9ZdNjhhI4rgjfgsyk6vTY1yfVg= @@ -195,6 +225,7 @@ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13/go.mod h1:f/Ib/qYjhV2/qds 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/endpoints/v2 v2.4.37/go.mod h1:Qe+2KtKml+FEsQF/DHmDV+xjtche/hwoF75EG4UlHW8= 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/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o= 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/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= @@ -203,8 +234,10 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.23.2/go.mod h1:Eows6e1uQEsc4ZaHANmsP github.com/aws/smithy-go v1.15.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= 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/bits-and-blooms/bitset v1.8.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/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= 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= @@ -218,6 +251,7 @@ github.com/bufbuild/connect-go v1.5.2/go.mod h1:GmMJYR6orFqD0Y6ZgX8pwQ8j9baizDrI github.com/bufbuild/protocompile v0.5.1/go.mod h1:G5iLmavmF4NsYtpZFvE3B/zFch2GIY8+wjsYLR/lc40= github.com/butuzov/ireturn v0.1.1/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ= github.com/chavacava/garif v0.0.0-20230227094218-b8c73b2037b8/go.mod h1:gakxgyXaaPkxvLw1XQxNGK4I37ys9iBRzNUx/B7pUCo= @@ -228,9 +262,11 @@ github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4M 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/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.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-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20240318125728-8a4994d93e50/go.mod h1:5e1+Vvlzido69INQaVO6d87Qn543Xr6nooe9Kz7oBFM= 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= @@ -246,7 +282,9 @@ github.com/cometbft/cometbft v0.38.2/go.mod h1:PIi48BpzwlHqtV3mzwPyQgOyOnU94BNBi 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-db v0.7.0/go.mod h1:yiKJIm2WKrt6x8Cyxtq9YTEcIMPcEe4XPxhgX59Fzf0= +github.com/coming-chat/lcs v0.0.0-20220829063658-0fa8432d2bdf/go.mod h1:CVVNl2j3TGYyUjuux+oYrRenPGvD+5UQbPGYp/zUews= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/stargz-snapshotter/estargz v0.12.1/go.mod h1:12VUuCq3qPq4y8yUW+l5w3+oXV3cx2Po3KSe/SmPGqw= 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= @@ -259,16 +297,26 @@ github.com/cosmos/iavl v1.0.0/go.mod h1:CmTGqMnRnucjxbjduneZXT+0vPgNElYvdefjX2q9 github.com/cosmos/iavl v1.1.1/go.mod h1:jLeUvm6bGT1YutCaL2fIar/8vGUE8cPZvh/gXEWDaDM= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 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/tomledit v0.0.24/go.mod h1:9qHbShRWQzSCcn617cMzg4eab1vbLCOjOshAWSzWr8U= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +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/daixiang0/gci v0.10.1/go.mod h1:xtHP9N7AHdNvtRNfcx9gwTDfw7FRJx4bZUsiEfiNNAI= github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= +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/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.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= 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/djherbis/atime v1.1.0/go.mod h1:28OF6Y8s3NQWwacXc5eZTsEsiMzp7LF8MbXE+XJPdBE= 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/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v23.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= @@ -280,6 +328,7 @@ github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3/go.mod h1:QMWlm50DNe14 github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= 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= @@ -309,11 +358,14 @@ github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbS github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= 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/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/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= 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.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-critic/go-critic v0.7.0/go.mod h1:moYzd7GdVXE2C2hYTwd7h0CPcqlUeclsyBRwMa38v64= github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= @@ -323,6 +375,7 @@ github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2H github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= 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.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= 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= @@ -331,7 +384,11 @@ github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= 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-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +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.1.0/go.mod h1:hXM6gan18VA1T/daUEHCFcYiW8Ai1tIwIzHY6srfEAw= @@ -339,15 +396,19 @@ github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/ 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.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.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= 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/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/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-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.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= 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= @@ -361,7 +422,10 @@ 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/flatbuffers v23.5.26+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= 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 v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= @@ -369,59 +433,82 @@ github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8I github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= 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.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go v0.0.0-20161107002406-da06d194a00e/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= 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-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/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= 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= github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A= 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/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/hashicorp/consul/api v1.28.2/go.mod h1:KyzqzgMEya+IZPcD65YFoOVAgPpbfERu4I/tzG6/ueE= +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-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= 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= github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +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/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= 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/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo= github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/hydrogen18/memlistener v1.0.0/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= 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/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.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 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= +github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= +github.com/iris-contrib/httpexpect/v2 v2.12.1/go.mod h1:7+RB6W5oNClX7PTwJgJnsQP3ZuUUYB3u61KCqeSgZ88= github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= +github.com/iris-contrib/jade v1.1.4/go.mod h1:EDqR+ur9piDl6DUgs6qRrlfzmlx/D5UybogqrXvJTBE= github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= 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/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/jgautheron/goconst v1.5.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= +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/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.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= 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= @@ -436,11 +523,14 @@ github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4 github.com/kataras/golog v0.1.8/go.mod h1:rGPAin4hYROfk1qT9wZP6VY2rsb4zzc37QpdPjdkqVw= github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= github.com/kataras/iris/v12 v12.2.0/go.mod h1:BLzBpEunc41GbE68OUaQlqX4jzi791mx5HU04uPb90Y= +github.com/kataras/jwt v0.1.8/go.mod h1:Q5j2IkcIHnfwy+oNY3TVWuEBJNw0ADgCcXK9CaZwV4o= github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= +github.com/kataras/neffos v0.0.21/go.mod h1:FeGka8lu8cjD2H+0OpBvW8c6xXawy3fj5VX6xcIJ1Fg= github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= github.com/kataras/pio v0.0.11/go.mod h1:38hH6SWH6m4DKSYmRhlrCJ5WItwWgCVrTNU62XZyUvI= github.com/kataras/sitemap v0.0.6/go.mod h1:dW4dOCNs896OR1HmG+dMLdT7JjDk7mYBzoIRwuj5jA4= github.com/kataras/tunnel v0.0.4/go.mod h1:9FkU4LaeifdMWqZu7o20ojmW4B7hdhv2CMLwfnHGpYw= +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.3/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw= @@ -458,6 +548,7 @@ github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgo 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= github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= @@ -468,11 +559,18 @@ github.com/kyoh86/exportloopref v0.1.11/go.mod h1:qkV4UF1zGl6EkF1ox8L5t9SwyeBAZ3 github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= github.com/ldez/gomoddirectives v0.2.3/go.mod h1:cpgBogWITnCfRq2qGoDkKMEVSaarhdBr6g8G04uz6d0= 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/leonklingele/grouper v1.1.1/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY= +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.8.6/go.mod h1:xZCIb5Muw+nhbDK4Y5UJuOrin5MceOuiXkVUR7vp4WY= github.com/linxGnu/grocksdb v1.8.12/go.mod h1:xZCIb5Muw+nhbDK4Y5UJuOrin5MceOuiXkVUR7vp4WY= +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/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= @@ -485,39 +583,73 @@ 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-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= +github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= 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= github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= 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.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= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/mimoo/StrobeGo v0.0.0-20220103164710-9a04d6ca976b h1:QrHweqAtyJ9EwCaGHBu1fghwxIPiopAHV06JlXrMHjk= +github.com/mimoo/StrobeGo v0.0.0-20220103164710-9a04d6ca976b/go.mod h1:xxLb2ip6sSUts3g1irPVHyk/DGslwQsNOo9I7smJfNU= github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= +github.com/misko9/go-substrate-rpc-client/v4 v4.0.0-20230913220906-b988ea7da0c2 h1:G/cVeTAbB9S/6FSWWqpFV0v49hiuHLbJPu9hTZ0UR2A= +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/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= +github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= +github.com/mmcloughlin/avo v0.5.0/go.mod h1:ChHFdoV7ql95Wi7vuq2YT1bwCJqiWdZrQ1im3VujLYM= github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= github.com/moricho/tparallel v0.3.0/go.mod h1:leENX2cUv7Sv2qDgdi0D0fCftN8fRC67Bcn8pqzeYNI= 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= +github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= +github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= +github.com/multiformats/go-multiaddr v0.11.0 h1:XqGyJ8ufbCE0HmTDwx2kPdsrQ36AGPZNZX6s6xfJH10= +github.com/multiformats/go-multiaddr v0.11.0/go.mod h1:gWUm0QLR4thQ6+ZF6SXUw8YjtwQSPapICM+NmCkxHSM= +github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= +github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= +github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= +github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= +github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= +github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= +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.3.0/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k= +github.com/nats-io/nats-server/v2 v2.5.0/go.mod h1:Kj86UtrXAL6LwYRA6H4RqzkHhK0Vcv2ZnKD5WbQ1t3g= github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= 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.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/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/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= 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 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= github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= @@ -529,19 +661,30 @@ github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZO 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.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-20230904192822-1876fd5063bc/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= 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= +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.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.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/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.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/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= @@ -557,12 +700,22 @@ github.com/prometheus/exporter-toolkit v0.10.0/go.mod h1:+sVFzuvV5JDyw+Ih6p3zFxZ 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/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.4.0/go.mod h1:Eu76Z/R8IXtViWUIHkE3p8gdH3/PKk1eh3YGfaEof10= +github.com/quasilyte/go-ruleguard/dsl v0.3.22/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= +github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50= github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= 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/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/remyoudompheng/go-dbus v0.0.0-20121104212943-b7232d34b1d5/go.mod h1:+u151txRmLpwxBmpYn9z3d1sdJdjRPQpsXuYeY9jNls= +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/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= @@ -571,12 +724,15 @@ github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= 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/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.3.0/go.mod h1:ggBxb3luypPEzqVtq33ee7YSN35V28XeGnid8dnni50= 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/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U= 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.23.0/go.mod h1:YPwr/Y1LATzHI93CqoPUN/2BzGQ/6N/cl/KwgR0B/aU= @@ -587,6 +743,7 @@ github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod github.com/securego/gosec/v2 v2.15.0/go.mod h1:VOjTrZOkUtSDt2QLSJmQBMWnvwiQPEjg0l+5juIqGk8= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= +github.com/shirou/gopsutil/v3 v3.23.2/go.mod h1:gv0aQw33GLo3pG8SiWKiQrbDzbRY1K80RyZJ7V4Th1M= 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= @@ -611,6 +768,9 @@ github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1Fof github.com/spf13/viper v1.18.1/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= 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/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/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= @@ -630,6 +790,8 @@ github.com/timakin/bodyclose v0.0.0-20221125081123-e39cf3fc478e/go.mod h1:27bSVN github.com/timonwong/loggercheck v0.9.4/go.mod h1:caz4zlPcgvpEkXgVnAJGowHAMW2NwHaNlpS8xDbVhTg= 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/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= @@ -638,7 +800,9 @@ github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKn github.com/uudashr/gocognit v1.0.6/go.mod h1:nAIUuVBnYU7pcninia3BHOvQkpQCeO76Uscky5BOwcY= github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= +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.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= @@ -646,9 +810,12 @@ github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q 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/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +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= github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= 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= @@ -657,7 +824,9 @@ github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FB 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.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= 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/etcd/api/v3 v3.5.12/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4= go.etcd.io/etcd/client/pkg/v3 v3.5.12/go.mod h1:seTzl2d9APP8R5Y2hFL3NVlD6qC/dOT+3kvrqPyTas4= @@ -675,6 +844,7 @@ go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDs 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= @@ -904,6 +1074,22 @@ gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/R gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= 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= +lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= +modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= +modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= +modernc.org/libc v1.29.0 h1:tTFRFq69YKCF2QyGNuRUQxKBm1uZZLubf6Cjh/pVHXs= +modernc.org/libc v1.29.0/go.mod h1:DaG/4Q3LRRdqpiLyP0C2m1B8ZMGkQ+cCgOIjEtQlYhQ= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= +modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sqlite v1.28.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0= +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-20221223090309-7455f1af531d/go.mod h1:IeHQjmn6TOD+e4Z3RFiZMMsLVL+A96Nvptar8Fj71is= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/relayer/chains/evm/listener.go b/relayer/chains/evm/listener.go index b8c8dacf..257d54e7 100644 --- a/relayer/chains/evm/listener.go +++ b/relayer/chains/evm/listener.go @@ -48,7 +48,9 @@ func (r *Provider) latestHeight(ctx context.Context) uint64 { return height } -func (p *Provider) Listener(ctx context.Context, lastSavedHeight uint64, blockInfoChan chan *relayertypes.BlockInfo) error { +func (p *Provider) Listener(ctx context.Context, lastProcessedTx relayertypes.LastProcessedTx, blockInfoChan chan *relayertypes.BlockInfo) error { + lastSavedHeight := lastProcessedTx.Height + startHeight, err := p.startFromHeight(ctx, lastSavedHeight) if err != nil { return err diff --git a/relayer/chains/icon/listener.go b/relayer/chains/icon/listener.go index d7880839..01bbf20c 100644 --- a/relayer/chains/icon/listener.go +++ b/relayer/chains/icon/listener.go @@ -29,7 +29,7 @@ type btpBlockRequest struct { response *btpBlockResponse } -func (p *Provider) Listener(ctx context.Context, lastSavedHeight uint64, incoming chan *providerTypes.BlockInfo) error { +func (p *Provider) Listener(ctx context.Context, lastProcessedTx providerTypes.LastProcessedTx, incoming chan *providerTypes.BlockInfo) error { reconnectCh := make(chan struct{}, 1) // reconnect channel reconnect := func() { @@ -39,6 +39,8 @@ func (p *Provider) Listener(ctx context.Context, lastSavedHeight uint64, incomin } } + lastSavedHeight := lastProcessedTx.Height + processedheight, err := p.StartFromHeight(ctx, lastSavedHeight) if err != nil { return errors.Wrapf(err, "failed to calculate start height") @@ -59,7 +61,6 @@ func (p *Provider) Listener(ctx context.Context, lastSavedHeight uint64, incomin select { case <-ctx.Done(): return ctx.Err() - case <-reconnectCh: ctxMonitorBlock, cancelMonitorBlock := context.WithCancel(ctx) go func(ctx context.Context, cancel context.CancelFunc) { diff --git a/relayer/chains/mockchain/provider.go b/relayer/chains/mockchain/provider.go index a6291000..49424bb2 100644 --- a/relayer/chains/mockchain/provider.go +++ b/relayer/chains/mockchain/provider.go @@ -8,6 +8,7 @@ import ( "github.com/icon-project/centralized-relay/relayer/kms" "github.com/icon-project/centralized-relay/relayer/provider" "github.com/icon-project/centralized-relay/relayer/types" + relayertypes "github.com/icon-project/centralized-relay/relayer/types" "go.uber.org/zap" ) @@ -84,12 +85,12 @@ func (p *MockProvider) QueryLatestHeight(ctx context.Context) (uint64, error) { return p.Height, nil } -func (p *MockProvider) Listener(ctx context.Context, lastSavedHeight uint64, blockInfo chan *types.BlockInfo) error { +func (p *MockProvider) Listener(ctx context.Context, lastProcessedTx relayertypes.LastProcessedTx, blockInfo chan *types.BlockInfo) error { ticker := time.NewTicker(1 * time.Second) if p.Height == 0 { - if lastSavedHeight != 0 { - p.Height = lastSavedHeight + if lastProcessedTx.Height != 0 { + p.Height = lastProcessedTx.Height } } p.log.Info("listening to mock provider from height", zap.Uint64("Height", p.Height)) diff --git a/relayer/chains/sui/client.go b/relayer/chains/sui/client.go new file mode 100644 index 00000000..bf0f51f1 --- /dev/null +++ b/relayer/chains/sui/client.go @@ -0,0 +1,285 @@ +package sui + +import ( + "context" + "fmt" + "slices" + "strconv" + + "github.com/coming-chat/go-sui/v2/account" + suisdkClient "github.com/coming-chat/go-sui/v2/client" + "github.com/coming-chat/go-sui/v2/lib" + "github.com/coming-chat/go-sui/v2/move_types" + "github.com/coming-chat/go-sui/v2/sui_types" + "github.com/coming-chat/go-sui/v2/types" + "github.com/fardream/go-bcs/bcs" + suitypes "github.com/icon-project/centralized-relay/relayer/chains/sui/types" + "go.uber.org/zap" +) + +const ( + suiCurrencyType = "0x2::sui::SUI" + suiStringType = "0x1::string::String" + suiU64 = "u64" + suiBool = "bool" + moveCall suisdkClient.UnsafeMethod = "moveCall" + + CallArgPure = "pure" + CallArgObject = "object" +) + +type IClient interface { + GetLatestCheckpointSeq(ctx context.Context) (uint64, error) + GetTotalBalance(ctx context.Context, addr string) (uint64, error) + SimulateTx(ctx context.Context, txBytes lib.Base64Data) (*types.DryRunTransactionBlockResponse, int64, error) + ExecuteTx(ctx context.Context, wallet *account.Account, txBytes lib.Base64Data, signatures []any) (*types.SuiTransactionBlockResponse, error) + GetTransaction(ctx context.Context, txDigest string) (*types.SuiTransactionBlockResponse, error) + QueryContract(ctx context.Context, senderAddr string, txBytes lib.Base64Data, resPtr interface{}) error + + GetCheckpoint(ctx context.Context, checkpoint uint64) (*suitypes.CheckpointResponse, error) + GetEventsFromTxBlocks(ctx context.Context, allowedEventTypes []string, digests []string) ([]suitypes.EventResponse, error) + + GetObject(ctx context.Context, objID sui_types.ObjectID, options *types.SuiObjectDataOptions) (*types.SuiObjectResponse, error) + + GetCoins(ctx context.Context, accountAddress string) (types.Coins, error) + + MoveCall( + ctx context.Context, + signer move_types.AccountAddress, + packageId move_types.AccountAddress, + module, function string, + typeArgs []string, + arguments []any, + gas *move_types.AccountAddress, + gasBudget types.SafeSuiBigInt[uint64], + ) (*types.TransactionBytes, error) + + QueryTxBlocks( + ctx context.Context, + query types.SuiTransactionBlockResponseQuery, + cursor *sui_types.TransactionDigest, + limit *uint, + descendingOrder bool, + ) (*types.TransactionBlocksPage, error) + + GetEvents( + ctx context.Context, + txDigest sui_types.TransactionDigest, + ) ([]types.SuiEvent, error) + + MultiGetTxBlocks( + ctx context.Context, + digests []string, + ) ([]*types.SuiTransactionBlockResponse, error) +} + +type Client struct { + rpc *suisdkClient.Client + log *zap.Logger +} + +func NewClient(rpcClient *suisdkClient.Client, l *zap.Logger) *Client { + return &Client{ + rpc: rpcClient, + log: l, + } +} + +func (c Client) MoveCall( + ctx context.Context, + signer move_types.AccountAddress, + packageId move_types.AccountAddress, + module, function string, + typeArgs []string, + arguments []any, + gas *move_types.AccountAddress, + gasBudget types.SafeSuiBigInt[uint64], +) (*types.TransactionBytes, error) { + return c.rpc.MoveCall(ctx, signer, packageId, module, function, typeArgs, arguments, gas, gasBudget) +} + +func (c Client) GetObject(ctx context.Context, objID sui_types.ObjectID, options *types.SuiObjectDataOptions) (*types.SuiObjectResponse, error) { + res, err := c.rpc.GetObject(ctx, objID, options) + if err != nil { + return nil, err + } + + if res.Error != nil { + if res.Error.Data.NotExists != nil { + return nil, fmt.Errorf("object: %s does not exist", res.Error.Data.NotExists.ObjectId) + } else if res.Error.Data.Deleted != nil { + return nil, fmt.Errorf("object: %s is deleted", res.Error.Data.Deleted.ObjectId) + } else if res.Error.Data.DisplayError != nil { + return nil, fmt.Errorf("%s", res.Error.Data.DisplayError.Error) + } else { + return nil, fmt.Errorf("unknown error occurred") + } + } + + return res, err +} + +func (c Client) GetCoins(ctx context.Context, addr string) (types.Coins, error) { + accountAddress, err := move_types.NewAccountAddressHex(addr) + if err != nil { + return nil, err + } + return c.rpc.GetSuiCoinsOwnedByAddress(ctx, *accountAddress) +} + +func (c Client) GetLatestCheckpointSeq(ctx context.Context) (uint64, error) { + checkPoint, err := c.rpc.GetLatestCheckpointSequenceNumber(ctx) + if err != nil { + return 0, err + } + return strconv.ParseUint(checkPoint, 10, 64) +} + +func (c *Client) GetTotalBalance(ctx context.Context, addr string) (uint64, error) { + accountAddress, err := move_types.NewAccountAddressHex(addr) + if err != nil { + return 0, fmt.Errorf("error getting balance: %w", err) + } + res, err := c.rpc.GetBalance(ctx, *accountAddress, suiCurrencyType) + if err != nil { + return 0, fmt.Errorf("error getting balance: %w", err) + } + return res.TotalBalance.BigInt().Uint64(), nil +} + +func (cl *Client) SimulateTx(ctx context.Context, txBytes lib.Base64Data) (*types.DryRunTransactionBlockResponse, int64, error) { + dryrunResult, err := cl.rpc.DryRunTransaction(ctx, txBytes) + return dryrunResult, dryrunResult.Effects.Data.GasFee(), err +} + +func (cl *Client) ExecuteTx(ctx context.Context, wallet *account.Account, txBytes lib.Base64Data, signatures []any) (*types.SuiTransactionBlockResponse, error) { + return cl.rpc.ExecuteTransactionBlock(ctx, txBytes, signatures, &types.SuiTransactionBlockResponseOptions{ + ShowEffects: true, + ShowEvents: true, + }, types.TxnRequestTypeWaitForLocalExecution) +} + +func (cl *Client) GetTransaction(ctx context.Context, txDigest string) (*types.SuiTransactionBlockResponse, error) { + b58Digest, err := lib.NewBase58(txDigest) + if err != nil { + return nil, err + } + txBlock, err := cl.rpc.GetTransactionBlock(ctx, *b58Digest, types.SuiTransactionBlockResponseOptions{ + ShowEffects: true, + }) + return txBlock, err +} + +func (cl *Client) QueryContract(ctx context.Context, senderAddr string, txBytes lib.Base64Data, resPtr interface{}) error { + senderAddress, err := move_types.NewAccountAddressHex(senderAddr) + if err != nil { + return err + } + + res, err := cl.rpc.DevInspectTransactionBlock(context.Background(), *senderAddress, txBytes, nil, nil) + if err != nil { + return err + } + + if res.Error != nil { + return fmt.Errorf("error occurred while calling sui contract: %s", *res.Error) + } + if len(res.Results) > 0 && len(res.Results[0].ReturnValues) > 0 { + returnValues := res.Results[0].ReturnValues[0] + returnResult := returnValues.([]interface{})[0] + + if _, ok := returnResult.([]byte); ok { + if _, err := bcs.Unmarshal([]byte(returnResult.([]byte)), resPtr); err != nil { + return err + } + return nil + } + + resultBytes := []byte{} + for _, el := range returnResult.([]interface{}) { + resultBytes = append(resultBytes, byte(el.(float64))) + } + + if _, err := bcs.Unmarshal(resultBytes, resPtr); err != nil { + return err + } + return nil + } + + return fmt.Errorf("got empty result") +} + +func (c *Client) GetCheckpoint(ctx context.Context, checkpoint uint64) (*suitypes.CheckpointResponse, error) { + checkpointRes := suitypes.CheckpointResponse{} + if err := c.rpc.CallContext( + ctx, + &checkpointRes, + suitypes.SuiMethod("sui_getCheckpoint"), + strconv.Itoa(int(checkpoint)), + ); err != nil { + return nil, err + } + + return &checkpointRes, nil +} + +func (c *Client) GetEventsFromTxBlocks(ctx context.Context, allowedEventTypes []string, digests []string) ([]suitypes.EventResponse, error) { + txnBlockResponses := []*types.SuiTransactionBlockResponse{} + + if err := c.rpc.CallContext( + ctx, + &txnBlockResponses, + suitypes.SuiMethod("sui_multiGetTransactionBlocks"), + digests, + types.SuiTransactionBlockResponseOptions{ShowEvents: true}, + ); err != nil { + return nil, err + } + + var events []suitypes.EventResponse + for _, txRes := range txnBlockResponses { + for _, ev := range txRes.Events { + if slices.Contains(allowedEventTypes, ev.Type) { + events = append(events, suitypes.EventResponse{ + SuiEvent: ev, + Checkpoint: txRes.Checkpoint, + }) + } + } + } + + return events, nil +} + +func (c *Client) QueryTxBlocks( + ctx context.Context, + query types.SuiTransactionBlockResponseQuery, + cursor *sui_types.TransactionDigest, + limit *uint, + descendingOrder bool, +) (*types.TransactionBlocksPage, error) { + return c.rpc.QueryTransactionBlocks(ctx, query, cursor, limit, descendingOrder) +} + +func (c *Client) GetEvents( + ctx context.Context, + txDigest sui_types.TransactionDigest, +) ([]types.SuiEvent, error) { + return c.rpc.GetEvents(ctx, txDigest) +} + +func (c *Client) MultiGetTxBlocks(ctx context.Context, digests []string) ([]*types.SuiTransactionBlockResponse, error) { + txnBlockResponses := []*types.SuiTransactionBlockResponse{} + + if err := c.rpc.CallContext( + ctx, + &txnBlockResponses, + suitypes.SuiMethod("sui_multiGetTransactionBlocks"), + digests, + types.SuiTransactionBlockResponseOptions{ShowEvents: true}, + ); err != nil { + return nil, err + } + + return txnBlockResponses, nil +} diff --git a/relayer/chains/sui/config.go b/relayer/chains/sui/config.go new file mode 100644 index 00000000..9611143a --- /dev/null +++ b/relayer/chains/sui/config.go @@ -0,0 +1,83 @@ +package sui + +import ( + "context" + "sync" + + suisdkClient "github.com/coming-chat/go-sui/v2/client" + "github.com/icon-project/centralized-relay/relayer/provider" + + "go.uber.org/zap" +) + +type Config struct { + ChainName string `yaml:"-" json:"-"` + ChainID string `yaml:"chain-id" json:"chain-id"` + RPCUrl string `yaml:"rpc-url" json:"rpc-url"` + Address string `yaml:"address" json:"address"` + NID string `yaml:"nid" json:"nid"` + + // list of xcall package ids in order of latest to oldest in descending order + XcallPkgIDs []string `yaml:"xcall-package-ids" json:"xcall-package-ids"` + XcallStorageID string `yaml:"xcall-storage-id" json:"xcall-storage-id"` + + ConnectionID string `yaml:"connection-id" json:"connection-id"` + ConnectionCapID string `yaml:"connection-cap-id" json:"connection-cap-id"` + + DappPkgID string `yaml:"dapp-package-id" json:"dapp-package-id"` + DappModules []DappModule `yaml:"dapp-modules" json:"dapp-modules"` + + HomeDir string `yaml:"home-dir" json:"home-dir"` + GasLimit uint64 `yaml:"gas-limit" json:"gas-limit"` + Disabled bool `json:"disabled" yaml:"disabled"` + + // Start tx-digest cursor to begin querying for events. + // Should be empty if we want to query using last saved tx-digest + // from database. + StartTxDigest string `json:"start-tx-digest" yaml:"start-tx-digest"` +} + +type DappModule struct { + Name string `yaml:"name" json:"name"` + CapID string `yaml:"cap-id" json:"cap-id"` + ConfigID string `yaml:"config-id" json:"config-id"` +} + +func (pc *Config) NewProvider(ctx context.Context, logger *zap.Logger, homePath string, debug bool, chainName string) (provider.ChainProvider, error) { + pc.HomeDir = homePath + pc.ChainName = chainName + + if err := pc.Validate(); err != nil { + return nil, err + } + rpcClient, err := suisdkClient.Dial(pc.RPCUrl) + if err != nil { + return nil, err + } + client := NewClient(rpcClient, logger) + + return &Provider{ + log: logger.With(zap.String("nid ", pc.NID), zap.String("name", pc.ChainName)), + cfg: pc, + client: client, + txmut: &sync.Mutex{}, + }, nil +} + +func (pc *Config) SetWallet(addr string) { + pc.Address = addr +} + +func (pc *Config) GetWallet() string { + return pc.Address +} + +func (pc *Config) Validate() error { + //Todo + return nil +} + +// Enabled returns true if the chain is enabled +func (c *Config) Enabled() bool { + return !c.Disabled +} diff --git a/relayer/chains/sui/keys.go b/relayer/chains/sui/keys.go new file mode 100644 index 00000000..b58ed879 --- /dev/null +++ b/relayer/chains/sui/keys.go @@ -0,0 +1,113 @@ +package sui + +import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" + "os" + "path" + + "github.com/cometbft/cometbft/libs/rand" + "github.com/coming-chat/go-sui/v2/account" + "github.com/coming-chat/go-sui/v2/sui_types" +) + +type KeyPair byte + +const ( + Ed25519Flag KeyPair = 0 + Secp256k1Flag KeyPair = 1 + suiAddressLength = 64 + ed25519PublicKeyLength = 32 +) + +// fetches Ed25519 keypair from the privatekey with flag +func fetchKeyPair(privateKey string) (*account.Account, error) { + return account.NewAccountWithKeystore(privateKey) +} + +// Restores the addres configured +func (p *Provider) RestoreKeystore(ctx context.Context) error { + path := p.keystorePath(p.cfg.Address) + keystore, err := os.ReadFile(path) + if err != nil { + return fmt.Errorf("error restoring account: %w", err) + } + privateKey, err := p.kms.Decrypt(ctx, keystore) + if err != nil { + return fmt.Errorf("error restoring account: %w", err) + } + p.wallet, err = fetchKeyPair(string(privateKey)) + if err != nil { + return fmt.Errorf("error restoring account: %w", err) + } + return nil +} + +// Creates new Ed25519 key +func (p *Provider) NewKeystore(password string) (string, error) { + signatureScheme, err := sui_types.NewSignatureScheme(byte(Ed25519Flag)) + if err != nil { + return "", err + } + account := account.NewAccount(signatureScheme, rand.Bytes(32)) + privateKeyWithFlag := append([]byte{byte(Ed25519Flag)}, account.KeyPair.PrivateKey()[:ed25519PublicKeyLength]...) + encodedPkey := base64.StdEncoding.EncodeToString([]byte(privateKeyWithFlag)) + keyStoreContent, err := p.kms.Encrypt(context.Background(), []byte(encodedPkey)) + if err != nil { + return "", fmt.Errorf("error adding new account: %w", err) + } + passphraseCipher, err := p.kms.Encrypt(context.Background(), []byte(password)) + if err != nil { + return "", fmt.Errorf("error adding new account: %w", err) + } + path := p.keystorePath(account.Address) + if err = os.WriteFile(path, keyStoreContent, 0o644); err != nil { + return "", fmt.Errorf("error adding new account: %w", err) + } + if err = os.WriteFile(path+".pass", passphraseCipher, 0o644); err != nil { + return "", fmt.Errorf("error adding new account: %w", err) + } + return account.Address, nil +} + +// Imports first ed25519 key pair from the keystore +func (p *Provider) ImportKeystore(ctx context.Context, keyPath, passphrase string) (string, error) { + privFile, err := os.ReadFile(keyPath) + if err != nil { + return "", fmt.Errorf("error importing key: %w", err) + } + var ksData []string + err = json.Unmarshal(privFile, &ksData) + if err != nil { + return "", fmt.Errorf("error importing key: %w", err) + } + //decode base64 for first key + firstKeyPairString := string(ksData[0]) + keyPair, err := fetchKeyPair(firstKeyPairString) + if err != nil { + return "", fmt.Errorf("error importing key: %w", err) + } + keyStoreContent, err := p.kms.Encrypt(ctx, []byte(firstKeyPairString)) + if err != nil { + return "", fmt.Errorf("error importing key: %w", err) + } + passphraseCipher, err := p.kms.Encrypt(ctx, []byte(passphrase)) + if err != nil { + return "", fmt.Errorf("error importing key: %w", err) + } + path := p.keystorePath(keyPair.Address) + if err = os.WriteFile(path, keyStoreContent, 0o644); err != nil { + return "", fmt.Errorf("error importing key: %w", err) + } + if err = os.WriteFile(path+".pass", passphraseCipher, 0o644); err != nil { + return "", fmt.Errorf("error importing key: %w", err) + } + return keyPair.Address, nil +} + +// keystorePath is the path to the keystore file +func (p *Provider) keystorePath(addr string) string { + return path.Join(p.cfg.HomeDir, "keystore", p.NID(), addr) +} diff --git a/relayer/chains/sui/keys_test.go b/relayer/chains/sui/keys_test.go new file mode 100644 index 00000000..0cadb1d9 --- /dev/null +++ b/relayer/chains/sui/keys_test.go @@ -0,0 +1,21 @@ +package sui + +import ( + "encoding/hex" + "testing" + + "github.com/stretchr/testify/assert" +) + +var ( + expectedAddr = "0xe847098636459aa93f4da105414edca4790619b291ffdac49419f5adc19c4d21" + expectedPrivKey = "b592e26293b6081673c807f9ae5b14b150d0078d6d9a5474323fff73a9015cac" +) + +func TestRestoreKey(t *testing.T) { + encodedWithFlag := "ALWS4mKTtggWc8gH+a5bFLFQ0AeNbZpUdDI//3OpAVys" + key, err := fetchKeyPair(encodedWithFlag) + assert.NoError(t, err) + assert.Equal(t, expectedAddr, key.Address) + assert.Equal(t, expectedPrivKey, hex.EncodeToString(key.KeyPair.PrivateKey()[:32])) +} diff --git a/relayer/chains/sui/listener.go b/relayer/chains/sui/listener.go new file mode 100644 index 00000000..edf88ede --- /dev/null +++ b/relayer/chains/sui/listener.go @@ -0,0 +1,332 @@ +package sui + +import ( + "context" + "encoding/hex" + "encoding/json" + "fmt" + "math/big" + "strings" + "time" + + "github.com/coming-chat/go-sui/v2/lib" + "github.com/coming-chat/go-sui/v2/sui_types" + cctypes "github.com/coming-chat/go-sui/v2/types" + "github.com/icon-project/centralized-relay/relayer/chains/sui/types" + relayerEvents "github.com/icon-project/centralized-relay/relayer/events" + relayertypes "github.com/icon-project/centralized-relay/relayer/types" + "github.com/icon-project/centralized-relay/utils/sorter" + "go.uber.org/zap" +) + +func (p *Provider) Listener(ctx context.Context, lastProcessedTx relayertypes.LastProcessedTx, blockInfo chan *relayertypes.BlockInfo) error { + txInfo := new(types.TxInfo) + + if lastProcessedTx.Info != nil { + if err := txInfo.Deserialize(lastProcessedTx.Info); err != nil { + p.log.Error("failed to deserialize last processed tx digest", zap.Error(err)) + return err + } + } + + if p.cfg.StartTxDigest != "" { + txInfo.TxDigest = p.cfg.StartTxDigest + } + + return p.listenByPolling(ctx, txInfo.TxDigest, blockInfo) +} + +func (p *Provider) allowedEventTypes() []string { + allowedEvents := []string{} + for _, xcallPkgId := range p.cfg.XcallPkgIDs { + allowedEvents = append(allowedEvents, []string{ + fmt.Sprintf("%s::%s::%s", xcallPkgId, ModuleConnection, "Message"), + fmt.Sprintf("%s::%s::%s", xcallPkgId, ModuleMain, "CallMessage"), + fmt.Sprintf("%s::%s::%s", xcallPkgId, ModuleMain, "RollbackMessage"), + }...) + } + return allowedEvents +} + +func (p *Provider) shouldSkipMessage(msg *relayertypes.Message) bool { + // if relayer is not an executor then skip CallMessage and RollbackMessage events. + if p.cfg.DappPkgID == "" && + (msg.EventType == relayerEvents.CallMessage || + msg.EventType == relayerEvents.RollbackMessage) { + return true + } + return false +} + +func (p *Provider) parseMessagesFromEvents(events []types.EventResponse) ([]relayertypes.BlockInfo, error) { + checkpointMessages := make(map[uint64][]*relayertypes.Message) + for _, ev := range events { + msg, err := p.parseMessageFromEvent(ev) + if err != nil { + if err.Error() == types.InvalidEventError { + continue + } + return nil, err + } + + if p.shouldSkipMessage(msg) { + continue + } + + p.log.Info("Detected event log: ", + zap.Uint64("checkpoint", msg.MessageHeight), + zap.String("event-type", msg.EventType), + zap.Any("sn", msg.Sn), + zap.String("dst", msg.Dst), + zap.Any("req-id", msg.ReqID), + zap.String("dapp-module-cap-id", msg.DappModuleCapID), + zap.Any("data", hex.EncodeToString(msg.Data)), + ) + checkpointMessages[ev.Checkpoint.Uint64()] = append(checkpointMessages[ev.Checkpoint.Uint64()], msg) + } + + var blockInfoList []relayertypes.BlockInfo + for checkpoint, messages := range checkpointMessages { + blockInfoList = append(blockInfoList, relayertypes.BlockInfo{ + Height: checkpoint, + Messages: messages, + }) + } + + sorter.Sort(blockInfoList, func(bi1, bi2 relayertypes.BlockInfo) bool { + return bi1.Height < bi2.Height //ascending order + }) + + return blockInfoList, nil +} + +func (p *Provider) parseMessageFromEvent(ev types.EventResponse) (*relayertypes.Message, error) { + msg := relayertypes.Message{ + MessageHeight: ev.Checkpoint.Uint64(), + Src: p.cfg.NID, + } + + txInfo := types.TxInfo{TxDigest: ev.Id.TxDigest.String()} + txInfoBytes, err := txInfo.Serialize() + if err != nil { + return nil, err + } + msg.TxInfo = txInfoBytes + + eventBytes, err := json.Marshal(ev.ParsedJson) + if err != nil { + return nil, err + } + + eventParts := strings.Split(ev.Type, "::") + eventSuffix := strings.Join(eventParts[1:], "::") + + switch eventSuffix { + case fmt.Sprintf("%s::%s", ModuleConnection, "Message"): + msg.EventType = relayerEvents.EmitMessage + var emitEvent types.EmitEvent + if err := json.Unmarshal(eventBytes, &emitEvent); err != nil { + return nil, err + } + if emitEvent.ConnectionID != p.cfg.ConnectionID { + return nil, fmt.Errorf(types.InvalidEventError) + } + sn, ok := new(big.Int).SetString(emitEvent.Sn, 10) + if !ok { + return nil, err + } + msg.Sn = sn + msg.Data = emitEvent.Msg + msg.Src = p.cfg.NID + msg.Dst = emitEvent.To + + case fmt.Sprintf("%s::%s", ModuleMain, "CallMessage"): + msg.EventType = relayerEvents.CallMessage + var callMsgEvent types.CallMsgEvent + if err := json.Unmarshal(eventBytes, &callMsgEvent); err != nil { + return nil, err + } + msg.Src = callMsgEvent.From.NetID + msg.Data = callMsgEvent.Data + + sn, ok := new(big.Int).SetString(callMsgEvent.Sn, 10) + if !ok { + return nil, err + } + + reqID, ok := new(big.Int).SetString(callMsgEvent.ReqId, 10) + if !ok { + return nil, err + } + + msg.Sn = sn + msg.ReqID = reqID + msg.DappModuleCapID = callMsgEvent.DappModuleCapId + msg.Dst = p.cfg.NID + + case fmt.Sprintf("%s::%s", ModuleMain, "RollbackMessage"): + msg.EventType = relayerEvents.RollbackMessage + var rollbackMsgEvent types.RollbackMsgEvent + if err := json.Unmarshal(eventBytes, &rollbackMsgEvent); err != nil { + return nil, err + } + + sn, ok := new(big.Int).SetString(rollbackMsgEvent.Sn, 10) + if !ok { + return nil, fmt.Errorf("failed to parse sn from rollback event") + } + msg.Sn = sn + msg.DappModuleCapID = rollbackMsgEvent.DappModuleCapId + msg.Src = p.cfg.NID + msg.Dst = p.cfg.NID + msg.Data = rollbackMsgEvent.Data + + default: + return nil, fmt.Errorf(types.InvalidEventError) + } + + return &msg, nil +} + +func (p *Provider) handleEventNotification(ctx context.Context, ev types.EventResponse, blockStream chan *relayertypes.BlockInfo) { + for ev.Checkpoint == nil { + p.log.Warn("checkpoint not found for transaction", zap.String("tx-digest", ev.Id.TxDigest.String())) + time.Sleep(1 * time.Second) + txRes, err := p.client.GetTransaction(ctx, ev.Id.TxDigest.String()) + if err != nil { + p.log.Error("failed to get transaction while handling event notification", + zap.Error(err), zap.Any("event", ev)) + return + } + ev.Checkpoint = txRes.Checkpoint + } + + msg, err := p.parseMessageFromEvent(ev) + if err != nil { + if err.Error() == types.InvalidEventError { + return + } + p.log.Error("failed to parse message from event while handling event notification", + zap.Error(err), + zap.Any("event", ev)) + return + } + + if p.shouldSkipMessage(msg) { + return + } + + p.log.Info("Detected event log: ", + zap.Uint64("checkpoint", msg.MessageHeight), + zap.String("event-type", msg.EventType), + zap.Any("sn", msg.Sn), + zap.String("dst", msg.Dst), + zap.Any("req-id", msg.ReqID), + zap.String("dapp-module-cap-id", msg.DappModuleCapID), + zap.Any("data", hex.EncodeToString(msg.Data)), + ) + + blockStream <- &relayertypes.BlockInfo{ + Height: msg.MessageHeight, + Messages: []*relayertypes.Message{msg}, + } +} + +func (p *Provider) listenByPolling(ctx context.Context, lastSavedTxDigestStr string, blockStream chan *relayertypes.BlockInfo) error { + done := make(chan interface{}) + defer close(done) + + var lastSavedTxDigest *sui_types.TransactionDigest + + if lastSavedTxDigestStr != "" { //process probably unexplored events of last saved tx digest + var err error + lastSavedTxDigest, err = sui_types.NewDigest(lastSavedTxDigestStr) + if err != nil { + return err + } + currentEvents, err := p.client.GetEvents(ctx, *lastSavedTxDigest) + if err != nil { + return err + } + + for _, ev := range currentEvents { + p.handleEventNotification(ctx, types.EventResponse{SuiEvent: ev}, blockStream) + } + } + + eventStream := p.getObjectEventStream(done, p.cfg.XcallStorageID, lastSavedTxDigest) + + p.log.Info("event query started from last saved tx digest", zap.String("last-saved-tx-digest", lastSavedTxDigestStr)) + + for { + select { + case <-ctx.Done(): + return ctx.Err() + case ev, ok := <-eventStream: + if ok { + p.handleEventNotification(ctx, ev, blockStream) + } + } + } +} + +func (p *Provider) getObjectEventStream(done chan interface{}, objectID string, afterTxDigest *sui_types.TransactionDigest) <-chan types.EventResponse { + eventStream := make(chan types.EventResponse) + + go func() { + defer close(eventStream) + + inputObj, err := sui_types.NewObjectIdFromHex(objectID) + if err != nil { + p.log.Panic("failed to create object from hex string", zap.Error(err)) + } + + query := cctypes.SuiTransactionBlockResponseQuery{ + Filter: &cctypes.TransactionFilter{ + InputObject: inputObj, + }, + Options: &cctypes.SuiTransactionBlockResponseOptions{ + ShowEvents: true, + }, + } + + cursor := afterTxDigest + + limit := uint(100) + + ticker := time.NewTicker(3 * time.Second) + + for { + select { + case <-done: + return + case <-ticker.C: + res, err := p.client.QueryTxBlocks(context.Background(), query, cursor, &limit, false) + if err != nil { + p.log.Error("failed to query tx blocks", zap.Error(err), zap.Any("cursor", cursor)) + break + } + + p.log.Debug("tx block query successful", zap.Any("cursor", cursor)) + + if len(res.Data) > 0 { + var nextCursor *lib.Base58 + for _, blockRes := range res.Data { + for _, ev := range blockRes.Events { + eventStream <- types.EventResponse{ + SuiEvent: ev, + Checkpoint: blockRes.Checkpoint, + } + nextCursor = &ev.Id.TxDigest + } + } + if nextCursor != nil { + cursor = nextCursor + } + } + } + } + }() + + return eventStream +} diff --git a/relayer/chains/sui/msg.go b/relayer/chains/sui/msg.go new file mode 100644 index 00000000..b5887cd1 --- /dev/null +++ b/relayer/chains/sui/msg.go @@ -0,0 +1,35 @@ +package sui + +import ( + jsoniter "github.com/json-iterator/go" +) + +type SuiCallArg struct { + Val interface{} + Type string +} +type SuiMessage struct { + Params []SuiCallArg + TypeArgs []string + Method string + PackageId string + Module string +} + +func (m *SuiMessage) Type() string { + return m.Method +} + +func (m *SuiMessage) MsgBytes() ([]byte, error) { + return jsoniter.Marshal(m.Params) +} + +func (p *Provider) NewSuiMessage(typeArgs []string, params []SuiCallArg, packageId, module, method string) *SuiMessage { + return &SuiMessage{ + Params: params, + TypeArgs: typeArgs, + PackageId: packageId, + Module: module, + Method: method, + } +} diff --git a/relayer/chains/sui/provider.go b/relayer/chains/sui/provider.go new file mode 100644 index 00000000..243fadf3 --- /dev/null +++ b/relayer/chains/sui/provider.go @@ -0,0 +1,232 @@ +package sui + +import ( + "context" + "fmt" + "math/big" + "strconv" + "sync" + + "github.com/coming-chat/go-sui/v2/account" + "github.com/icon-project/centralized-relay/relayer/chains/sui/types" + "github.com/icon-project/centralized-relay/relayer/kms" + "github.com/icon-project/centralized-relay/relayer/provider" + relayertypes "github.com/icon-project/centralized-relay/relayer/types" + "go.uber.org/zap" +) + +var ( + MethodClaimFee = "claim_fees" + MethodGetReceipt = "get_receipt" + MethodSetFee = "set_fee" + MethodGetFee = "get_fee" + MethodRevertMessage = "revert_message" + MethodSetAdmin = "set_admin" + MethodGetAdmin = "get_admin" + MethodRecvMessage = "receive_message" + MethodExecuteCall = "execute_call" + MethodExecuteRollback = "execute_rollback" + MethodGetWithdrawTokentype = "get_withdraw_token_type" + + ModuleConnection = "centralized_connection" + ModuleEntry = "centralized_entry" + ModuleMain = "main" + XcallModule = "xcall" + + ModuleMockDapp = "mock_dapp" + ModuleXcallManager = "xcall_manager" + ModuleAssetManager = "asset_manager" + ModuleBalancedDollar = "balanced_dollar_crosschain" + + suiCurrencyDenom = "SUI" + suiBaseFee = 1000 + + suiClockObjectId = "0x6" +) + +type Provider struct { + log *zap.Logger + cfg *Config + client IClient + wallet *account.Account + kms kms.KMS + txmut *sync.Mutex + LastSavedHeightFunc func() uint64 +} + +func (p *Provider) QueryLatestHeight(ctx context.Context) (uint64, error) { + return p.client.GetLatestCheckpointSeq(ctx) +} + +// SetLastSavedBlockHeightFunc sets the function to save the last saved block height +func (p *Provider) SetLastSavedHeightFunc(f func() uint64) { + p.LastSavedHeightFunc = f +} + +func (p *Provider) NID() string { + return p.cfg.NID +} + +func (p *Provider) Name() string { + return p.cfg.ChainName +} + +func (p *Provider) Init(ctx context.Context, homePath string, kms kms.KMS) error { + p.kms = kms + return nil +} + +// Type returns chain-type +func (p *Provider) Type() string { + return types.ChainType +} + +func (p *Provider) Config() provider.Config { + return p.cfg +} + +func (p *Provider) Wallet() (*account.Account, error) { + if p.wallet == nil { + if err := p.RestoreKeystore(context.Background()); err != nil { + return nil, err + } + } + return p.wallet, nil +} + +// FinalityBlock returns the number of blocks the chain has to advance from current block inorder to +// consider it as final. In Sui checkpoints are analogues to blocks and checkpoints once published are +// final. So Sui doesn't need to be checked for block/checkpoint finality. +func (p *Provider) FinalityBlock(ctx context.Context) uint64 { + return 0 +} + +func (p *Provider) GenerateMessages(ctx context.Context, messageKey *relayertypes.MessageKeyWithMessageHeight) ([]*relayertypes.Message, error) { + checkpoint, err := p.client.GetCheckpoint(ctx, messageKey.Height) + if err != nil { + p.log.Error("failed to fetch checkpoint", zap.Error(err)) + return nil, err + } + + var messages []*relayertypes.Message + + eventResponse, err := p.client.GetEventsFromTxBlocks(ctx, p.allowedEventTypes(), checkpoint.Transactions) + if err != nil { + p.log.Error("failed to query events", zap.Error(err)) + return nil, err + } + + blockInfoList, err := p.parseMessagesFromEvents(eventResponse) + if err != nil { + p.log.Error("failed to parse messages from events", zap.Error(err)) + return nil, err + } + + for _, bi := range blockInfoList { + messages = append(messages, bi.Messages...) + } + + return messages, nil +} + +// SetAdmin transfers the ownership of sui connection module to new address +func (p *Provider) SetAdmin(ctx context.Context, adminAddr string) error { + //implementation not needed in sui + return fmt.Errorf("set_admin is not implmented in sui contract") +} + +func (p *Provider) RevertMessage(ctx context.Context, sn *big.Int) error { + //implementation not needed in sui + return fmt.Errorf("revert_message is not implemented in sui contract") +} + +func (p *Provider) GetFee(ctx context.Context, networkID string, responseFee bool) (uint64, error) { + suiMessage := p.NewSuiMessage( + []string{}, + []SuiCallArg{ + {Type: CallArgObject, Val: p.cfg.XcallStorageID}, + {Type: CallArgPure, Val: p.cfg.ConnectionID}, + {Type: CallArgPure, Val: networkID}, + {Type: CallArgPure, Val: responseFee}, + }, p.xcallPkgIDLatest(), ModuleEntry, MethodGetFee) + var fee uint64 + wallet, err := p.Wallet() + if err != nil { + return fee, err + } + txBytes, err := p.preparePTB(suiMessage) + if err != nil { + return fee, err + } + if err := p.client.QueryContract(ctx, wallet.Address, txBytes, &fee); err != nil { + return fee, err + } + return fee, nil +} + +func (p *Provider) SetFee(ctx context.Context, networkID string, msgFee, resFee *big.Int) error { + suiMessage := p.NewSuiMessage( + []string{}, + []SuiCallArg{ + {Type: CallArgObject, Val: p.cfg.XcallStorageID}, + {Type: CallArgObject, Val: p.cfg.ConnectionCapID}, + {Type: CallArgPure, Val: networkID}, + {Type: CallArgPure, Val: strconv.Itoa(int(msgFee.Int64()))}, + {Type: CallArgPure, Val: strconv.Itoa(int(resFee.Int64()))}, + }, p.xcallPkgIDLatest(), ModuleEntry, MethodSetFee) + txBytes, err := p.prepareTxMoveCall(suiMessage) + if err != nil { + return err + } + res, err := p.SendTransaction(ctx, txBytes) + if err != nil { + return err + } + p.log.Info("set fee txn successful", + zap.String("network-id", networkID), + zap.String("tx-hash", res.Digest.String()), + ) + return nil +} + +func (p *Provider) ClaimFee(ctx context.Context) error { + suiMessage := p.NewSuiMessage( + []string{}, + []SuiCallArg{ + {Type: CallArgObject, Val: p.cfg.XcallStorageID}, + {Type: CallArgObject, Val: p.cfg.ConnectionCapID}, + }, + p.xcallPkgIDLatest(), ModuleEntry, MethodClaimFee) + txBytes, err := p.prepareTxMoveCall(suiMessage) + if err != nil { + return err + } + res, err := p.SendTransaction(ctx, txBytes) + if err != nil { + return err + } + p.log.Info("claim fee txn successful", + zap.String("tx-hash", res.Digest.String()), + ) + return nil +} + +func (p *Provider) QueryBalance(ctx context.Context, addr string) (*relayertypes.Coin, error) { + balance, err := p.client.GetTotalBalance(ctx, addr) + if err != nil { + return nil, err + } + return &relayertypes.Coin{Amount: balance, Denom: suiCurrencyDenom}, nil +} + +func (p *Provider) ShouldReceiveMessage(ctx context.Context, messagekey *relayertypes.Message) (bool, error) { + return true, nil +} + +func (p *Provider) ShouldSendMessage(ctx context.Context, messageKey *relayertypes.Message) (bool, error) { + return true, nil +} + +func (p *Provider) xcallPkgIDLatest() string { + return p.cfg.XcallPkgIDs[0] +} diff --git a/relayer/chains/sui/provider_test.go b/relayer/chains/sui/provider_test.go new file mode 100644 index 00000000..0c0472ef --- /dev/null +++ b/relayer/chains/sui/provider_test.go @@ -0,0 +1,192 @@ +package sui + +import ( + "context" + "encoding/hex" + "fmt" + "os" + "testing" + "time" + + "github.com/coming-chat/go-sui/v2/account" + suisdkClient "github.com/coming-chat/go-sui/v2/client" + "github.com/coming-chat/go-sui/v2/lib" + "github.com/coming-chat/go-sui/v2/sui_types" + "github.com/coming-chat/go-sui/v2/types" + suitypes "github.com/icon-project/centralized-relay/relayer/chains/sui/types" + "github.com/stretchr/testify/assert" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +var ( + privateKeyEncodedWithFlag = "ALWS4mKTtggWc8gH+a5bFLFQ0AeNbZpUdDI//3OpAVys" + expectedDecodedAddr = "0xe847098636459aa93f4da105414edca4790619b291ffdac49419f5adc19c4d21" + expectedDecodedPrivKey = "b592e26293b6081673c807f9ae5b14b150d0078d6d9a5474323fff73a9015cac" +) + +type mockKms struct { +} + +func (*mockKms) Init(context.Context) (*string, error) { + initcompleted := "yes" + return &initcompleted, nil +} + +func (*mockKms) Encrypt(ctx context.Context, input []byte) ([]byte, error) { + return input, nil +} + +func (*mockKms) Decrypt(ctx context.Context, input []byte) ([]byte, error) { + return input, nil +} + +type mockClient struct { +} + +func (*mockClient) GetLatestCheckpointSeq(ctx context.Context) (uint64, error) { + panic("not implemented") +} +func (*mockClient) GetTotalBalance(ctx context.Context, addr string) (uint64, error) { + panic("not implemented") +} +func (*mockClient) EstimateGas(ctx context.Context, txBytes lib.Base64Data) (*types.DryRunTransactionBlockResponse, int64, error) { + return &types.DryRunTransactionBlockResponse{ + Effects: lib.TagJson[types.SuiTransactionBlockEffects]{ + Data: types.SuiTransactionBlockEffects{ + V1: &types.SuiTransactionBlockEffectsV1{ + Status: types.ExecutionStatus{Status: "success"}, + }, + }, + }, + }, 100, nil +} +func (*mockClient) ExecuteContract(ctx context.Context, suiMessage *SuiMessage, address string, gasBudget uint64) (*types.TransactionBytes, error) { + return &types.TransactionBytes{ + TxBytes: []byte("txbytes"), + }, nil +} +func (*mockClient) CommitTx(ctx context.Context, wallet *account.Account, txBytes lib.Base64Data, signatures []any) (*types.SuiTransactionBlockResponse, error) { + return &types.SuiTransactionBlockResponse{}, nil +} +func (*mockClient) GetTransaction(ctx context.Context, txDigest string) (*types.SuiTransactionBlockResponse, error) { + panic("not implemented") +} +func (*mockClient) QueryContract(ctx context.Context, suiMessage *SuiMessage, address string, gasBudget uint64) (any, error) { + panic("not implemented") +} + +func (*mockClient) GetEventsFromTxBlocks(ctx context.Context, packageID string, digests []string) ([]suitypes.EventResponse, error) { + panic("not implemented") +} + +func GetSuiProvider() (*Provider, error) { + pc := Config{ + NID: "sui.testnet", + Address: "0xe847098636459aa93f4da105414edca4790619b291ffdac49419f5adc19c4d21", + RPCUrl: "https://sui-devnet-endpoint.blockvision.org", + HomeDir: "./tmp/", + } + logger := zap.NewNop() + ctx := context.Background() + prov, err := pc.NewProvider(ctx, logger, "./tmp/", true, "sui.testnet") + if err != nil { + return nil, err + } + + suiProvider, ok := prov.(*Provider) + if !ok { + return nil, fmt.Errorf("unable to type cast to sui chain provider") + } + suiProvider.Init(ctx, "./tmp/", &mockKms{}) + err = os.MkdirAll(suiProvider.keystorePath("test"), 0777) + if err != nil { + fmt.Println(err) + } + return suiProvider, nil +} + +func TestNewKeystore(t *testing.T) { + pro, err := GetSuiProvider() + assert.NoError(t, err) + generatedKeyStore, err := pro.NewKeystore("password") + assert.NoError(t, err) + pro.cfg.Address = generatedKeyStore + err = pro.RestoreKeystore(context.Background()) + assert.NoError(t, err) + assert.Equal(t, generatedKeyStore, pro.wallet.Address) +} + +func TestImportKeystore(t *testing.T) { + pro, err := GetSuiProvider() + assert.NoError(t, err) + data := []byte("[\"" + privateKeyEncodedWithFlag + "\"]") + os.WriteFile("./tmp/ks.keystore", data, 0644) + restoredKeyStore, err := pro.ImportKeystore(context.TODO(), "./tmp/ks.keystore", "passphrase") + assert.NoError(t, err) + pro.cfg.Address = restoredKeyStore + err = pro.RestoreKeystore(context.Background()) + assert.NoError(t, err) + assert.Equal(t, expectedDecodedAddr, pro.wallet.Address) + assert.Equal(t, expectedDecodedPrivKey, hex.EncodeToString(pro.wallet.KeyPair.PrivateKey()[:32])) +} + +func newRootLogger() *zap.Logger { + config := zap.NewProductionEncoderConfig() + config.EncodeTime = func(ts time.Time, encoder zapcore.PrimitiveArrayEncoder) { + encoder.AppendString(ts.UTC().Format("2006-01-02T15:04:05.000000Z07:00")) + } + config.LevelKey = "lvl" + + enc := zapcore.NewJSONEncoder(config) + level := zap.InfoLevel + + core := zapcore.NewTee(zapcore.NewCore(enc, os.Stderr, level)) + + return zap.New(core) +} +func TestQueryTxBlocks(t *testing.T) { + rpcClient, err := suisdkClient.Dial("https://fullnode.testnet.sui.io:443") + assert.NoError(t, err) + + client := NewClient(rpcClient, newRootLogger()) + + inputObj, err := sui_types.NewObjectIdFromHex("0xde9b85d02710e2651f530e83ba2fb1daea45fd05e72f1c0dd2398239b917b46c") + assert.NoError(t, err) + + query := types.SuiTransactionBlockResponseQuery{ + Filter: &types.TransactionFilter{ + InputObject: inputObj, + }, + Options: &types.SuiTransactionBlockResponseOptions{ + ShowEvents: true, + }, + } + + cursor, err := sui_types.NewDigest("HGjoM1cL5dzR7B6radZ1woPFESe2cvwAaN6z46rBN9c5") + assert.NoError(t, err) + + limit := uint(100) + res, err := client.QueryTxBlocks(context.Background(), query, cursor, &limit, false) + assert.NoError(t, err) + + count := 0 + for _, blockRes := range res.Data { + checkpoint := "" + if blockRes.Checkpoint != nil { + checkpoint = blockRes.Checkpoint.Decimal().String() + } + for _, ev := range blockRes.Events { + count++ + client.log.Info("event", + zap.String("checkpoint", checkpoint), + zap.String("package-id", ev.PackageId.String()), + zap.String("module", ev.TransactionModule), + zap.String("event-type", ev.Type), + zap.String("tx-digest", ev.Id.TxDigest.String()), + ) + } + } + + fmt.Println("Total Events: ", count) +} diff --git a/relayer/chains/sui/tx.go b/relayer/chains/sui/tx.go new file mode 100644 index 00000000..af9d5a44 --- /dev/null +++ b/relayer/chains/sui/tx.go @@ -0,0 +1,519 @@ +package sui + +import ( + "context" + "encoding/base64" + "encoding/hex" + "fmt" + "math/big" + "strconv" + "time" + + "cosmossdk.io/errors" + "github.com/coming-chat/go-sui/v2/lib" + "github.com/coming-chat/go-sui/v2/move_types" + "github.com/coming-chat/go-sui/v2/sui_types" + "github.com/coming-chat/go-sui/v2/types" + "github.com/fardream/go-bcs/bcs" + "github.com/icon-project/centralized-relay/relayer/events" + relayertypes "github.com/icon-project/centralized-relay/relayer/types" + "github.com/icon-project/centralized-relay/utils/hexstr" + "go.uber.org/zap" +) + +func (p *Provider) Route(ctx context.Context, message *relayertypes.Message, callback relayertypes.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), + zap.String("data", hex.EncodeToString(message.Data))) + + suiMessage, err := p.MakeSuiMessage(message) + if err != nil { + return err + } + + p.txmut.Lock() + defer p.txmut.Unlock() + + txBytes, err := p.prepareTxMoveCall(suiMessage) + if err != nil { + return err + } + + txRes, err := p.SendTransaction(ctx, txBytes) + go p.executeRouteCallBack(txRes, message.MessageKey(), suiMessage.Method, callback, err) + if err != nil { + return errors.Wrapf(err, "error occured while sending transaction in sui") + } + return nil +} + +func (p *Provider) MakeSuiMessage(message *relayertypes.Message) (*SuiMessage, error) { + switch message.EventType { + case events.EmitMessage: + snU128, err := bcs.NewUint128FromBigInt(message.Sn) + if err != nil { + return nil, err + } + callParams := []SuiCallArg{ + {Type: CallArgObject, Val: p.cfg.XcallStorageID}, + {Type: CallArgObject, Val: p.cfg.ConnectionCapID}, + {Type: CallArgPure, Val: message.Src}, + {Type: CallArgPure, Val: snU128}, + {Type: CallArgPure, Val: "0x" + hex.EncodeToString(message.Data)}, + } + return p.NewSuiMessage([]string{}, callParams, p.xcallPkgIDLatest(), ModuleEntry, MethodRecvMessage), nil + case events.CallMessage: + if _, err := p.Wallet(); err != nil { + return nil, err + } + + coins, err := p.client.GetCoins(context.Background(), p.wallet.Address) + if err != nil { + return nil, err + } + _, coin, err := coins.PickSUICoinsWithGas(big.NewInt(int64(suiBaseFee)), p.cfg.GasLimit, types.PickBigger) + if err != nil { + return nil, err + } + + module, err := p.getModule(func(mod DappModule) bool { + return hexstr.NewFromString(mod.CapID) == hexstr.NewFromString(message.DappModuleCapID) + }) + if err != nil { + return nil, fmt.Errorf("module cap id %s not found: %w", message.DappModuleCapID, err) + } + + var callParams []SuiCallArg + typeArgs := []string{} + + switch module.Name { + case ModuleMockDapp: + callParams = []SuiCallArg{ + {Type: CallArgObject, Val: module.ConfigID}, + {Type: CallArgObject, Val: p.cfg.XcallStorageID}, + {Type: CallArgObject, Val: coin.CoinObjectId.String()}, + {Type: CallArgPure, Val: strconv.Itoa(int(message.ReqID.Int64()))}, + {Type: CallArgPure, Val: "0x" + hex.EncodeToString(message.Data)}, + } + case ModuleXcallManager: + callParams = []SuiCallArg{ + {Type: CallArgObject, Val: module.ConfigID}, + {Type: CallArgObject, Val: p.cfg.XcallStorageID}, + {Type: CallArgObject, Val: coin.CoinObjectId.String()}, + {Type: CallArgPure, Val: strconv.Itoa(int(message.ReqID.Int64()))}, + {Type: CallArgPure, Val: "0x" + hex.EncodeToString(message.Data)}, + } + case ModuleAssetManager: + xcallManagerModule, err := p.getModule(func(mod DappModule) bool { + return mod.Name == ModuleXcallManager + }) + if err != nil { + return nil, fmt.Errorf("failed to find xcall manager module: %w", err) + } + + withdrawTokenType, err := p.getWithdrawTokentype(context.Background(), message) + if err != nil { + return nil, fmt.Errorf("failed to get withdraw token type: %w", err) + } + + typeArgs = append(typeArgs, *withdrawTokenType) + + callParams = []SuiCallArg{ + {Type: CallArgObject, Val: module.ConfigID}, + {Type: CallArgObject, Val: xcallManagerModule.ConfigID}, + {Type: CallArgObject, Val: p.cfg.XcallStorageID}, + {Type: CallArgObject, Val: coin.CoinObjectId.String()}, + {Type: CallArgObject, Val: suiClockObjectId}, + {Type: CallArgPure, Val: strconv.Itoa(int(message.ReqID.Int64()))}, + {Type: CallArgPure, Val: "0x" + hex.EncodeToString(message.Data)}, + } + case ModuleBalancedDollar: + xcallManagerModule, err := p.getModule(func(mod DappModule) bool { + return mod.Name == ModuleXcallManager + }) + if err != nil { + return nil, fmt.Errorf("failed to find xcall manager module: %w", err) + } + callParams = []SuiCallArg{ + {Type: CallArgObject, Val: module.ConfigID}, + {Type: CallArgObject, Val: xcallManagerModule.ConfigID}, + {Type: CallArgObject, Val: p.cfg.XcallStorageID}, + {Type: CallArgObject, Val: coin.CoinObjectId.String()}, + {Type: CallArgPure, Val: strconv.Itoa(int(message.ReqID.Int64()))}, + {Type: CallArgPure, Val: "0x" + hex.EncodeToString(message.Data)}, + } + + default: + return nil, fmt.Errorf("received unknown dapp module cap id: %s", message.DappModuleCapID) + } + + return p.NewSuiMessage(typeArgs, callParams, p.cfg.DappPkgID, module.Name, MethodExecuteCall), nil + + case events.RollbackMessage: + module, err := p.getModule(func(mod DappModule) bool { + return hexstr.NewFromString(mod.CapID) == hexstr.NewFromString(message.DappModuleCapID) + }) + if err != nil { + return nil, fmt.Errorf("failed to get module cap id %s: %w", message.DappModuleCapID, err) + } + + snU128, err := bcs.NewUint128FromBigInt(message.Sn) + if err != nil { + return nil, err + } + + var callParams []SuiCallArg + typeArgs := []string{} + + switch module.Name { + case ModuleMockDapp: + callParams = []SuiCallArg{ + {Type: CallArgObject, Val: module.ConfigID}, + {Type: CallArgObject, Val: p.cfg.XcallStorageID}, + {Type: CallArgPure, Val: snU128}, + } + case ModuleAssetManager: + withdrawTokenType, err := p.getWithdrawTokentype(context.Background(), message) + if err != nil { + return nil, fmt.Errorf("failed to get withdraw token type: %w", err) + } + + typeArgs = append(typeArgs, *withdrawTokenType) + + callParams = []SuiCallArg{ + {Type: CallArgObject, Val: module.ConfigID}, + {Type: CallArgObject, Val: p.cfg.XcallStorageID}, + {Type: CallArgPure, Val: snU128}, + {Type: CallArgObject, Val: suiClockObjectId}, + } + case ModuleBalancedDollar: + callParams = []SuiCallArg{ + {Type: CallArgObject, Val: module.ConfigID}, + {Type: CallArgObject, Val: p.cfg.XcallStorageID}, + {Type: CallArgPure, Val: snU128}, + } + + default: + return nil, fmt.Errorf("received unknown dapp module cap id: %s", message.DappModuleCapID) + } + + return p.NewSuiMessage(typeArgs, callParams, p.cfg.DappPkgID, module.Name, MethodExecuteRollback), nil + + default: + return nil, fmt.Errorf("can't generate message for unknown event type: %s ", message.EventType) + } +} + +func (p *Provider) getModule(condition func(module DappModule) bool) (*DappModule, error) { + for _, mod := range p.cfg.DappModules { + if condition(mod) { + return &mod, nil + } + } + return nil, fmt.Errorf("module not found") +} + +func (p *Provider) preparePTB(msg *SuiMessage) (lib.Base64Data, error) { + builder := sui_types.NewProgrammableTransactionBuilder() + packageId, err := move_types.NewAccountAddressHex(msg.PackageId) + if err != nil { + return nil, err + } + + callArgs, err := p.paramsToCallArgs(msg.Params) + if err != nil { + return nil, err + } + + err = builder.MoveCall( + *packageId, + move_types.Identifier(msg.Module), + move_types.Identifier(msg.Method), + []move_types.TypeTag{}, + callArgs, + ) + if err != nil { + return nil, err + } + bcsBytes, err := bcs.Marshal(builder.Finish()) + if err != nil { + return nil, err + } + txBytes := append([]byte{0}, bcsBytes...) + b64Data, err := lib.NewBase64Data(base64.StdEncoding.EncodeToString(txBytes)) + if err != nil { + return nil, err + } + return *b64Data, nil +} + +func (p *Provider) prepareTxMoveCall(msg *SuiMessage) (lib.Base64Data, error) { + if _, err := p.Wallet(); err != nil { + return nil, err + } + accountAddress, err := move_types.NewAccountAddressHex(p.wallet.Address) + if err != nil { + return nil, fmt.Errorf("error getting account address sender: %w", err) + } + packageId, err := move_types.NewAccountAddressHex(msg.PackageId) + if err != nil { + return nil, fmt.Errorf("invalid packageId: %w", err) + } + + var args []interface{} + for _, param := range msg.Params { + args = append(args, param.Val) + } + + res, err := p.client.MoveCall( + context.Background(), + *accountAddress, + *packageId, + msg.Module, + msg.Method, + msg.TypeArgs, + args, + nil, + types.NewSafeSuiBigInt(p.cfg.GasLimit), + ) + if err != nil { + return nil, err + } + return res.TxBytes, nil +} + +func (p *Provider) paramsToCallArgs(params []SuiCallArg) ([]sui_types.CallArg, error) { + var callArgs []sui_types.CallArg + for _, param := range params { + switch param.Type { + case CallArgObject: + arg, err := p.getCallArgObject(param.Val.(string)) + if err != nil { + return nil, err + } + callArgs = append(callArgs, *arg) + case CallArgPure: + arg, err := p.getCallArgPure(param.Val) + if err != nil { + return nil, err + } + callArgs = append(callArgs, *arg) + default: + return nil, fmt.Errorf("invalid call arg type") + } + } + return callArgs, nil +} + +func (p *Provider) getCallArgPure(arg interface{}) (*sui_types.CallArg, error) { + byteParam, err := bcs.Marshal(arg) + if err != nil { + return nil, err + } + return &sui_types.CallArg{ + Pure: &byteParam, + }, nil +} + +func (p *Provider) getCallArgObject(arg string) (*sui_types.CallArg, error) { + objectId, err := sui_types.NewAddressFromHex(arg) + if err != nil { + return nil, err + } + object, err := p.client.GetObject(context.Background(), *objectId, &types.SuiObjectDataOptions{ + ShowType: true, + ShowOwner: true, + }) + if err != nil { + return nil, fmt.Errorf("failed to get object: %v", err) + } + + if object.Data.Owner != nil && object.Data.Owner.Shared != nil { + return &sui_types.CallArg{ + Object: &sui_types.ObjectArg{ + SharedObject: &struct { + Id sui_types.ObjectID + InitialSharedVersion sui_types.SequenceNumber + Mutable bool + }{ + Id: object.Data.ObjectId, + InitialSharedVersion: *object.Data.Owner.Shared.InitialSharedVersion, + Mutable: true, + }, + }, + }, nil + } + + objRef := object.Data.Reference() + + return &sui_types.CallArg{ + Object: &sui_types.ObjectArg{ + ImmOrOwnedObject: &objRef, + }, + }, nil +} + +func (p *Provider) SendTransaction(ctx context.Context, txBytes lib.Base64Data) (*types.SuiTransactionBlockResponse, error) { + wallet, err := p.Wallet() + if err != nil { + return nil, err + } + + dryRunResp, gasRequired, err := p.client.SimulateTx(ctx, txBytes) + if err != nil { + return nil, fmt.Errorf("failed simulating tx: %w", err) + } + if gasRequired > int64(p.cfg.GasLimit) { + return nil, fmt.Errorf("gas requirement is too high: %d", gasRequired) + } + if !dryRunResp.Effects.Data.IsSuccess() { + return nil, fmt.Errorf(dryRunResp.Effects.Data.V1.Status.Error) + } + signature, err := wallet.SignSecureWithoutEncode(txBytes, sui_types.DefaultIntent()) + if err != nil { + return nil, err + } + signatures := []any{signature} + txnResp, err := p.client.ExecuteTx(ctx, wallet, txBytes, signatures) + + return txnResp, err +} + +func (p *Provider) executeRouteCallBack(txRes *types.SuiTransactionBlockResponse, messageKey *relayertypes.MessageKey, method string, callback relayertypes.TxResponseFunc, err error) { + // if error occurred before txn processing + if err != nil || txRes == nil || txRes.Digest == nil { + if err == nil { + err = fmt.Errorf("txn execution failed; received empty tx digest") + } + callback(messageKey, &relayertypes.TxResponse{}, err) + p.log.Error("failed to execute transaction", zap.Error(err), zap.String("method", method)) + return + } + + res := &relayertypes.TxResponse{ + TxHash: txRes.Digest.String(), + } + + txnData, err := p.client.GetTransaction(context.Background(), txRes.Digest.String()) + if err != nil { + callback(messageKey, res, err) + p.log.Error("failed to execute transaction", zap.Error(err), zap.String("method", method), zap.String("tx_hash", txRes.Digest.String())) + return + } + + for txnData.Checkpoint == nil { + p.log.Warn("transaction not included in checkpoint", zap.String("tx-digest", txRes.Digest.String())) + time.Sleep(3 * time.Second) //time to wait until tx is included in some checkpoint + txnData, err = p.client.GetTransaction(context.Background(), txRes.Digest.String()) + if err != nil { + callback(messageKey, res, err) + p.log.Error("failed to execute transaction", zap.Error(err), zap.String("method", method), zap.String("tx_hash", txRes.Digest.String())) + return + } + } + + // assign tx successful height + res.Height = txnData.Checkpoint.Int64() + success := txRes.Effects.Data.IsSuccess() + if !success { + err = fmt.Errorf("error: %s", txRes.Effects.Data.V1.Status.Error) + callback(messageKey, res, err) + p.log.Info("failed transaction", + zap.Any("message-key", messageKey), + zap.String("method", method), + zap.String("tx_hash", txRes.Digest.String()), + zap.Int64("height", txnData.Checkpoint.Int64()), + zap.Error(err), + ) + return + } + res.Code = relayertypes.Success + callback(messageKey, res, nil) + p.log.Info("successful transaction", + zap.Any("message-key", messageKey), + zap.String("method", method), + zap.String("tx_hash", txRes.Digest.String()), + zap.Int64("height", txnData.Checkpoint.Int64()), + ) +} + +func (p *Provider) QueryTransactionReceipt(ctx context.Context, txDigest string) (*relayertypes.Receipt, error) { + txBlock, err := p.client.GetTransaction(ctx, txDigest) + if err != nil { + return nil, err + } + receipt := &relayertypes.Receipt{ + TxHash: txDigest, + Height: txBlock.Checkpoint.Uint64(), + Status: txBlock.Effects.Data.IsSuccess(), + } + return receipt, nil +} + +func (p *Provider) MessageReceived(ctx context.Context, messageKey *relayertypes.MessageKey) (bool, error) { + switch messageKey.EventType { + case events.EmitMessage: + snU128, err := bcs.NewUint128FromBigInt(messageKey.Sn) + if err != nil { + return false, err + } + suiMessage := p.NewSuiMessage( + []string{}, + []SuiCallArg{ + {Type: CallArgObject, Val: p.cfg.XcallStorageID}, + {Type: CallArgPure, Val: p.cfg.ConnectionID}, + {Type: CallArgPure, Val: messageKey.Src}, + {Type: CallArgPure, Val: snU128}, + }, p.xcallPkgIDLatest(), ModuleEntry, MethodGetReceipt) + var msgReceived bool + wallet, err := p.Wallet() + if err != nil { + return msgReceived, err + } + + txBytes, err := p.preparePTB(suiMessage) + if err != nil { + return msgReceived, err + } + + if err := p.client.QueryContract(ctx, wallet.Address, txBytes, &msgReceived); err != nil { + return msgReceived, err + } + + return msgReceived, nil + case events.CallMessage: + return false, nil + case events.RollbackMessage: + return false, nil + default: + return true, fmt.Errorf("unknown event type") + } + +} + +func (p *Provider) getWithdrawTokentype(ctx context.Context, message *relayertypes.Message) (*string, error) { + suiMessage := p.NewSuiMessage( + []string{}, + []SuiCallArg{ + {Type: CallArgPure, Val: message.Data}, + }, p.cfg.DappPkgID, ModuleAssetManager, MethodGetWithdrawTokentype) + var tokenType string + wallet, err := p.Wallet() + if err != nil { + return nil, err + } + + txBytes, err := p.preparePTB(suiMessage) + if err != nil { + return nil, err + } + + if err := p.client.QueryContract(ctx, wallet.Address, txBytes, &tokenType); err != nil { + return nil, err + } + + return &tokenType, nil +} diff --git a/relayer/chains/sui/types/txInfo.go b/relayer/chains/sui/types/txInfo.go new file mode 100644 index 00000000..7a77e4c3 --- /dev/null +++ b/relayer/chains/sui/types/txInfo.go @@ -0,0 +1,15 @@ +package types + +import "encoding/json" + +type TxInfo struct { + TxDigest string `json:"tx_digest"` +} + +func (txi *TxInfo) Serialize() ([]byte, error) { + return json.Marshal(txi) +} + +func (txi *TxInfo) Deserialize(bytesVal []byte) error { + return json.Unmarshal(bytesVal, &txi) +} diff --git a/relayer/chains/sui/types/types.go b/relayer/chains/sui/types/types.go new file mode 100644 index 00000000..a02acc46 --- /dev/null +++ b/relayer/chains/sui/types/types.go @@ -0,0 +1,69 @@ +package types + +import ( + cctypes "github.com/coming-chat/go-sui/v2/types" +) + +const ( + ChainType = "sui" + XcallContract = "xcall" + ConnectionContract = "connection" + + InvalidEventError = "invalid_event_err" +) + +type EpochRollingGasCostSummary struct { + ComputationCost string `json:"computationCost"` + StorageCost string `json:"storageCost"` + StorageRebate string `json:"storageRebate"` + NonRefundableStorageFee string `json:"nonRefundableStorageFee"` +} + +type CheckpointResponse struct { + Epoch string `json:"epoch"` + SequenceNumber string `json:"sequenceNumber"` + Digest string `json:"digest"` + NetworkTotalTransactions string `json:"networkTotalTransactions"` + PreviousDigest string `json:"previousDigest"` + EpochRollingGasCostSummary EpochRollingGasCostSummary `json:"epochRollingGasCostSummary"` + TimestampMs string `json:"timestampMs"` + Transactions []string `json:"transactions"` + CheckpointCommitments []interface{} `json:"checkpointCommitments"` + ValidatorSignature string `json:"validatorSignature"` +} + +type EventResponse struct { + cctypes.SuiEvent + Checkpoint *cctypes.SafeSuiBigInt[uint64] +} + +type EmitEvent struct { + Sn string `json:"conn_sn"` + Msg []byte `json:"msg"` + To string `json:"to"` + ConnectionID string `json:"connection_id"` +} + +type NetworkAddress struct { + Addr string `json:"addr"` + NetID string `json:"net_id"` +} +type CallMsgEvent struct { + Sn string `json:"sn"` + From NetworkAddress `json:"from"` + ReqId string `json:"req_id"` + Data []byte `json:"data"` + DappModuleCapId string `json:"to"` +} + +type RollbackMsgEvent struct { + Sn string `json:"sn"` + Data []byte `json:"data"` + DappModuleCapId string `json:"dapp"` +} + +type SuiMethod string + +func (sm SuiMethod) String() string { + return string(sm) +} diff --git a/relayer/chains/wasm/provider.go b/relayer/chains/wasm/provider.go index 320c871d..87bba6d8 100644 --- a/relayer/chains/wasm/provider.go +++ b/relayer/chains/wasm/provider.go @@ -98,13 +98,15 @@ func (p *Provider) Config() provider.Config { return p.cfg } -func (p *Provider) Listener(ctx context.Context, lastSavedHeight uint64, blockInfoChan chan *relayTypes.BlockInfo) error { +func (p *Provider) Listener(ctx context.Context, lastProcessedTx relayTypes.LastProcessedTx, blockInfoChan chan *relayTypes.BlockInfo) error { latestHeight, err := p.QueryLatestHeight(ctx) if err != nil { p.logger.Error("failed to get latest block height", zap.Error(err)) return err } + lastSavedHeight := lastProcessedTx.Height + startHeight, err := p.getStartHeight(latestHeight, lastSavedHeight) if err != nil { p.logger.Error("failed to determine start height", zap.Error(err)) diff --git a/relayer/provider/provider.go b/relayer/provider/provider.go index 9b8cb8aa..17987037 100644 --- a/relayer/provider/provider.go +++ b/relayer/provider/provider.go @@ -30,7 +30,7 @@ type ChainProvider interface { Init(context.Context, string, kms.KMS) error Type() string Config() Config - Listener(ctx context.Context, lastSavedHeight uint64, blockInfo chan *types.BlockInfo) error + Listener(ctx context.Context, lastProcessedTx types.LastProcessedTx, blockInfo chan *types.BlockInfo) error Route(ctx context.Context, message *types.Message, callback types.TxResponseFunc) error ShouldReceiveMessage(ctx context.Context, message *types.Message) (bool, error) ShouldSendMessage(ctx context.Context, message *types.Message) (bool, error) diff --git a/relayer/relay.go b/relayer/relay.go index a25def45..b98c69d2 100644 --- a/relayer/relay.go +++ b/relayer/relay.go @@ -24,6 +24,8 @@ var ( prefixMessageStore = "message" prefixBlockStore = "block" prefixFinalityStore = "finality" + + prefixLastProcessedTx = "lastProcessedTx" ) // main start loop @@ -52,12 +54,13 @@ func (r *Relayer) Start(ctx context.Context, flushInterval time.Duration, fresh } type Relayer struct { - log *zap.Logger - db store.Store - chains map[string]*ChainRuntime - messageStore *store.MessageStore - blockStore *store.BlockStore - finalityStore *store.FinalityStore + log *zap.Logger + db store.Store + chains map[string]*ChainRuntime + messageStore *store.MessageStore + blockStore *store.BlockStore + finalityStore *store.FinalityStore + lastProcessedTxStore *store.LastProcessedTxStore } func NewRelayer(log *zap.Logger, db store.Store, chains map[string]*Chain, fresh bool) (*Relayer, error) { @@ -77,6 +80,9 @@ func NewRelayer(log *zap.Logger, db store.Store, chains map[string]*Chain, fresh // finality store finalityStore := store.NewFinalityStore(db, prefixFinalityStore) + //last processed tx store + lastProcessedTxStore := store.NewLastProcessedTxStore(db, prefixLastProcessedTx) + chainRuntimes := make(map[string]*ChainRuntime, len(chains)) for _, chain := range chains { chainRuntime, err := NewChainRuntime(log, chain) @@ -96,12 +102,13 @@ func NewRelayer(log *zap.Logger, db store.Store, chains map[string]*Chain, fresh } return &Relayer{ - log: log, - db: db, - chains: chainRuntimes, - messageStore: messageStore, - blockStore: blockStore, - finalityStore: finalityStore, + log: log, + db: db, + chains: chainRuntimes, + messageStore: messageStore, + blockStore: blockStore, + finalityStore: finalityStore, + lastProcessedTxStore: lastProcessedTxStore, }, nil } @@ -120,7 +127,15 @@ func (r *Relayer) StartChainListeners(ctx context.Context, errCh chan error) { for _, chainRuntime := range r.chains { eg.Go(func() error { - return chainRuntime.Provider.Listener(ctx, chainRuntime.LastSavedHeight, chainRuntime.listenerChan) + lastProcessedTxInfo, err := r.lastProcessedTxStore.Get(chainRuntime.Provider.NID()) + if err != nil { + r.log.Warn("failed to get last processed tx", zap.Error(err), zap.String("nid", chainRuntime.Provider.NID())) + } + lastProcessedTx := types.LastProcessedTx{ + Height: chainRuntime.LastSavedHeight, + Info: lastProcessedTxInfo, + } + return chainRuntime.Provider.Listener(ctx, lastProcessedTx, chainRuntime.listenerChan) }) } if err := eg.Wait(); err != nil { @@ -266,6 +281,11 @@ func (r *Relayer) processBlockInfo(ctx context.Context, src *ChainRuntime, block if err := r.messageStore.StoreMessage(msg); err != nil { r.log.Error("failed to store a message in db", zap.Error(err)) } + if err := r.lastProcessedTxStore.Set(src.Provider.NID(), msg.TxInfo); err != nil { + r.log.Error("failed to save last processed tx", + zap.Error(err), + zap.Any("msg", msg)) + } } } @@ -304,7 +324,7 @@ func (r *Relayer) callback(ctx context.Context, src, dst *ChainRuntime, key *typ zap.String("src", src.Provider.NID()), zap.String("dst", dst.Provider.NID()), zap.String("event_type", routeMessage.EventType), - zap.Uint64("sn", key.Sn.Uint64()), + zap.Any("sn", key.Sn), zap.String("tx_hash", response.TxHash), ) diff --git a/relayer/socket/client.go b/relayer/socket/client.go index 38566367..ef8ed4fb 100644 --- a/relayer/socket/client.go +++ b/relayer/socket/client.go @@ -109,7 +109,11 @@ func (c *Client) parseEvent(msg *Message) (interface{}, error) { } return res, nil case EventError: - return nil, ErrUnknown + res := new(ChainProviderError) + if err := jsoniter.Unmarshal(msg.Data, res); err != nil { + return nil, err + } + return res, fmt.Errorf(res.Message) case EventRevertMessage: res := new(ResRevertMessage) if err := jsoniter.Unmarshal(msg.Data, res); err != nil { diff --git a/relayer/socket/types.go b/relayer/socket/types.go index 642d08a0..f08fcf11 100644 --- a/relayer/socket/types.go +++ b/relayer/socket/types.go @@ -119,3 +119,7 @@ type ReqClaimFee struct { type ResClaimFee struct { Status string } + +type ChainProviderError struct { + Message string +} diff --git a/relayer/store/txStore.go b/relayer/store/txStore.go new file mode 100644 index 00000000..0ab9316d --- /dev/null +++ b/relayer/store/txStore.go @@ -0,0 +1,28 @@ +// Copyright 2021 ChainSafe Systems +// SPDX-License-Identifier: LGPL-3.0-only + +package store + +type LastProcessedTxStore struct { + db Store + prefix string +} + +func NewLastProcessedTxStore(db Store, prefix string) *LastProcessedTxStore { + return &LastProcessedTxStore{ + db: db, + prefix: prefix, + } +} + +func (s *LastProcessedTxStore) getKey(nId string) []byte { + return GetKey([]string{s.prefix, nId}) +} + +func (s *LastProcessedTxStore) Set(nId string, txInfo []byte) error { + return s.db.SetByKey(s.getKey(nId), txInfo) +} + +func (s *LastProcessedTxStore) Get(nId string) ([]byte, error) { + return s.db.GetByKey(s.getKey(nId)) +} diff --git a/relayer/types/types.go b/relayer/types/types.go index b054a7e1..a66a79c2 100644 --- a/relayer/types/types.go +++ b/relayer/types/types.go @@ -25,13 +25,16 @@ type BlockInfo struct { } type Message struct { - Dst string `json:"dst"` - Src string `json:"src"` - Sn *big.Int `json:"sn"` - Data []byte `json:"data"` - MessageHeight uint64 `json:"messageHeight"` - EventType string `json:"eventType"` - ReqID *big.Int `json:"reqID,omitempty"` + Dst string `json:"dst"` + Src string `json:"src"` + Sn *big.Int `json:"sn"` + Data []byte `json:"data"` + MessageHeight uint64 `json:"messageHeight"` + EventType string `json:"eventType"` + ReqID *big.Int `json:"reqID,omitempty"` + DappModuleCapID string `json:"dappModuleCapID,omitempty"` + + TxInfo []byte `json:"-"` } type ContractConfigMap map[string]string @@ -238,3 +241,8 @@ type Receipt struct { Height uint64 Status bool } + +type LastProcessedTx struct { + Height uint64 + Info []byte +} diff --git a/scripts/execute-test.sh b/scripts/execute-test.sh index 802554be..f7e003c4 100755 --- a/scripts/execute-test.sh +++ b/scripts/execute-test.sh @@ -26,8 +26,9 @@ xcall_branch="main" clean_contracts() { echo "Cleaning contract directories..." find artifacts/icon -type f -exec rm {} \; - # find artifacts/archway -type f -exec rm {} \; not required right now + find artifacts/archway -type f -exec rm {} \; find artifacts/evm -type f -exec rm {} \; + find artifacts/sui -type f -exec rm {} \; } e2e_test() { @@ -78,6 +79,7 @@ fi if [ "$build_xcall" = "true" ]; then echo "building xCall contracts..." build_xCall_contracts "$xcall_branch" + build_sui_docker fi # Run the selected test diff --git a/scripts/optimize-xcall-build.sh b/scripts/optimize-xcall-build.sh index eea967e8..0d41b3e8 100755 --- a/scripts/optimize-xcall-build.sh +++ b/scripts/optimize-xcall-build.sh @@ -3,29 +3,41 @@ set -e mkdir -p artifacts/icon mkdir -p artifacts/archway mkdir -p artifacts/evm +mkdir -p artifacts/sui LOCAL_X_CALL_REPO=".xcall-multi" +LOCAL_ARTIFACT_XCALL_SUI="xcall" clone_xCall_multi() { echo "Cloning xcall-multi repo..." X_CALL_BRANCH="${1:-main}" rm -rf "$LOCAL_X_CALL_REPO" git clone -b "$X_CALL_BRANCH" --single-branch "https://github.com/icon-project/xcall-multi.git" "$LOCAL_X_CALL_REPO" + cd artifacts/sui + git clone --bare -b "$X_CALL_BRANCH" --single-branch "https://github.com/icon-project/xcall-multi.git" "$LOCAL_ARTIFACT_XCALL_SUI" + cd - } build_xCall_contracts() { echo "Generating optimized contracts of xcall-multi contracts..." clone_xCall_multi "${1:-main}" cd "$LOCAL_X_CALL_REPO" - # ./scripts/optimize-cosmwasm.sh //not required right now + make build-wasm-docker make build-java-docker make build-solidity-docker - # cp artifacts/archway/*.wasm ../artifacts/archway/ + cp artifacts/archway/*.wasm ../artifacts/archway/ cp artifacts/icon/*.jar ../artifacts/icon/ cp -R artifacts/evm/ ../artifacts/evm/ cd - } +build_sui_docker(){ + cd test/chains/sui/data + docker build -t mysten/sui-tools-w-git . + cd - +} + if [ "$1" = "build" ]; then shift build_xCall_contracts "$@" + build_sui_docker fi diff --git a/test/chains/cosmos/localnet.go b/test/chains/cosmos/localnet.go index ac55c080..1ad7e5c6 100644 --- a/test/chains/cosmos/localnet.go +++ b/test/chains/cosmos/localnet.go @@ -109,6 +109,9 @@ func (c *CosmosRemotenet) GetRelayConfig(ctx context.Context, rlyHome string, ke } func (c *CosmosRemotenet) SetupConnection(ctx context.Context, target chains.Chain) error { + if c.testconfig.Environment == "preconfigured" { + return nil + } xcall := c.IBCAddresses["xcall"] denom := c.Config().Denom connectionCodeId, err := c.StoreContractRemote(ctx, c.filepath["connection"]) @@ -122,20 +125,17 @@ func (c *CosmosRemotenet) SetupConnection(ctx context.Context, target chains.Cha return err } c.IBCAddresses["connection"] = connectionAddress - // methodName := "set_fee" - // _, err = c.ExecuteContract(ctx, connectionAddress, keyName, methodName, map[string]interface{}{ - // "network_id": target.Config().ChainID, - // "message_fee": "0x0", - // "response_fee": "0x0", - // }, - // ) - // if err != nil { - // return err - // } return nil } func (c *CosmosRemotenet) SetupXCall(ctx context.Context) error { + if c.testconfig.Environment == "preconfigured" { + testcase := ctx.Value("testcase").(string) + c.IBCAddresses["xcall"] = "archway1u3kd42ns0m5fdlw8xpe3kp87dpfds68vhsfwt28hen7x8y8tjfuq9avr2n" + c.IBCAddresses["connection"] = "archway1mrhm2xy5yzlagl62zt2qt2dmrwrjwsag4pcc57uc44z04etn9slsa257y3" + c.IBCAddresses[fmt.Sprintf("dapp-%s", testcase)] = "archway1x8ejvuzjs9m40sljx4u6z0x2x7tc2q9k25a92v3hp5u4r30vurls5qujxr" + return nil + } denom := c.Config().Denom xCallCodeId, err := c.StoreContractRemote(ctx, c.filepath["xcall"]) if err != nil { @@ -159,6 +159,9 @@ func (c *CosmosRemotenet) GetIBCAddress(key string) string { } func (c *CosmosRemotenet) DeployXCallMockApp(ctx context.Context, keyname string, connections []chains.XCallConnection) error { + if c.testconfig.Environment == "preconfigured" { + return nil + } testcase := ctx.Value("testcase").(string) // connectionKey := fmt.Sprintf("connection-%s", testcase) // xCallKey := fmt.Sprintf("xcall-%s", testcase) @@ -219,6 +222,7 @@ func (c *CosmosRemotenet) XCall(ctx context.Context, targetChain chains.Chain, k if err != nil { return nil, err } + return c.FindTargetXCallMessage(ctx, targetChain, height, strings.Split(to, "/")[1]) } @@ -607,12 +611,8 @@ func (c *CosmosRemotenet) Height(ctx context.Context) (uint64, error) { } func (c *CosmosRemotenet) FindRollbackExecutedMessage(ctx context.Context, startHeight uint64, sn string) (string, error) { - xCallKey := "xcall" //fmt.Sprintf("xcall-%s", testcase) + xCallKey := "xcall" index := fmt.Sprintf("wasm-RollbackExecuted.sn CONTAINS '%s'", sn) _, err := c.FindEvent(ctx, startHeight, xCallKey, index) - if err != nil { - return "", err - } - - return "0", nil + return "0", err } diff --git a/test/chains/evm/localnet.go b/test/chains/evm/localnet.go index 1c535bdb..b043379f 100644 --- a/test/chains/evm/localnet.go +++ b/test/chains/evm/localnet.go @@ -164,6 +164,9 @@ func (an *EVMRemotenet) Height(ctx context.Context) (uint64, error) { } func (an *EVMRemotenet) SetupConnection(ctx context.Context, target chains.Chain) error { + if an.testconfig.Environment == "preconfigured" { + return nil + } xcall := common.HexToAddress(an.IBCAddresses["xcall"]) connection, err := an.DeployContractRemote(ctx, an.scorePaths["connection"], an.testconfig.KeystorePassword) if err != nil { @@ -188,6 +191,13 @@ func (an *EVMRemotenet) SetupConnection(ctx context.Context, target chains.Chain } func (an *EVMRemotenet) SetupXCall(ctx context.Context) error { + if an.testconfig.Environment == "preconfigured" { + testcase := ctx.Value("testcase").(string) + an.IBCAddresses["xcall"] = "0x2538a10b7fFb1B78c890c870FC152b10be121f04" + an.IBCAddresses["connection"] = "0x90b97E83e22AFa2e6A96b3549A0E495D5Bae61aF" + an.IBCAddresses[fmt.Sprintf("dapp-%s", testcase)] = "0xccA9728291bC98ff4F97EF57Be3466227b0eb06C" + return nil + } nid := an.cfg.ChainID xcall, err := an.DeployContractRemote(ctx, an.scorePaths["xcall"], an.testconfig.KeystorePassword) if err != nil { @@ -204,6 +214,9 @@ func (an *EVMRemotenet) SetupXCall(ctx context.Context) error { } func (an *EVMRemotenet) DeployXCallMockApp(ctx context.Context, keyName string, connections []chains.XCallConnection) error { + if an.testconfig.Environment == "preconfigured" { + return nil + } testcase := ctx.Value("testcase").(string) //an.CheckForKeyStore(ctx, keyName) //xCallKey := fmt.Sprintf("xcall-%s", testcase) @@ -329,7 +342,6 @@ func (an *EVMRemotenet) FindCallMessage(ctx context.Context, startHeight uint64, event, err := an.FindEvent(ctx, startHeight, CallMessage, topics) if err != nil { - fmt.Printf("Topics %v\n", topics) return "", "", err } return event["_reqId"].(*big.Int).String(), string(event["_data"].([]byte)), nil @@ -628,6 +640,5 @@ func (an *EVMRemotenet) FindRollbackExecutedMessage(ctx context.Context, startHe fmt.Printf("Topics %v", topics) return "", err } - return "0", nil } diff --git a/test/chains/icon/localnet.go b/test/chains/icon/localnet.go index e52eba94..3bf8194d 100644 --- a/test/chains/icon/localnet.go +++ b/test/chains/icon/localnet.go @@ -4,6 +4,7 @@ import ( "context" "encoding/hex" "encoding/json" + "errors" "fmt" "log" "path/filepath" @@ -170,6 +171,9 @@ func (in *IconRemotenet) GetGasFeesInNativeDenom(gasPaid int64) int64 { } func (in *IconRemotenet) SetupConnection(ctx context.Context, target chains.Chain) error { + if in.testconfig.Environment == "preconfigured" { + return nil + } xcall := in.IBCAddresses["xcall"] connection, err := in.DeployContractRemote(ctx, in.scorePaths["connection"], in.keystorePath, `{"_xCall":"`+xcall+`","_relayer":"`+in.testconfig.RelayWalletAddress+`"}`) @@ -187,6 +191,13 @@ func (in *IconRemotenet) SetupConnection(ctx context.Context, target chains.Chai } func (in *IconRemotenet) SetupXCall(ctx context.Context) error { + if in.testconfig.Environment == "preconfigured" { + testcase := ctx.Value("testcase").(string) + in.IBCAddresses["xcall"] = "cx4df1d24b5c5d6cae7e9f885d941a9c123005c598" + in.IBCAddresses["connection"] = "cx5bc2fae446d43d458902e9b922b9cc66633c40eb" + in.IBCAddresses[fmt.Sprintf("dapp-%s", testcase)] = "cx6f86fc01ce8dffcf8c54f22cd07236050e3ca8a3" + return nil + } nid := in.cfg.ChainID xcall, err := in.DeployContractRemote(ctx, in.scorePaths["xcall"], in.keystorePath, `{"networkId":"`+nid+`"}`) if err != nil { @@ -198,6 +209,9 @@ func (in *IconRemotenet) SetupXCall(ctx context.Context) error { } func (in *IconRemotenet) DeployXCallMockApp(ctx context.Context, keyName string, connections []chains.XCallConnection) error { + if in.testconfig.Environment == "preconfigured" { + return nil + } testcase := ctx.Value("testcase").(string) xCall := in.IBCAddresses["xcall"] @@ -337,7 +351,7 @@ func (in *IconRemotenet) FindEvent(ctx context.Context, startHeight uint64, cont Indexed: index, } // Create a context with a timeout of 16 seconds. - _ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + _ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) defer cancel() // Create an event request with the given filter and start height. @@ -360,13 +374,15 @@ func (in *IconRemotenet) FindEvent(ctx context.Context, startHeight uint64, cont if err := in.IconClient.MonitorEvent(ctx, req, response, errRespose); err != nil { log.Printf("MonitorEvent error: %v", err) } + defer in.IconClient.CloseAllMonitor() }(ctx, req, response, errRespose) select { case v := <-channel: return v, nil case <-_ctx.Done(): - return nil, fmt.Errorf(fmt.Sprintf("timeout : Event %s not found after %d block", signature, startHeight)) + latestHeight, _ := in.Height(ctx) + return nil, errors.New(fmt.Sprintf("timeout : Event %s not found after %d block to %d block ", signature, startHeight, latestHeight)) } } diff --git a/test/chains/sui/data/Dockerfile b/test/chains/sui/data/Dockerfile new file mode 100644 index 00000000..f8208543 --- /dev/null +++ b/test/chains/sui/data/Dockerfile @@ -0,0 +1,6 @@ +FROM mysten/sui-tools:devnet + +RUN apt update && apt-get install git jq -y + + + diff --git a/test/chains/sui/data/client.yaml b/test/chains/sui/data/client.yaml new file mode 100644 index 00000000..c711df69 --- /dev/null +++ b/test/chains/sui/data/client.yaml @@ -0,0 +1,8 @@ +keystore: + File: /root/.sui/sui_config/sui.keystore +envs: + - alias: devnet + rpc: "https://tt.net.solidwallet.io:443/sui-rpc" + ws: ~ +active_env: devnet +active_address: "0xe847098636459aa93f4da105414edca4790619b291ffdac49419f5adc19c4d21" \ No newline at end of file diff --git a/test/chains/sui/data/sui.aliases b/test/chains/sui/data/sui.aliases new file mode 100644 index 00000000..06ed410a --- /dev/null +++ b/test/chains/sui/data/sui.aliases @@ -0,0 +1,6 @@ +[ + { + "alias": "vigilant-emerald", + "public_key_base64": "AIGFX48ig8raLzNifU6IZefknPHr1TrG7PsHeHmxJBlo" + } +] \ No newline at end of file diff --git a/test/chains/sui/data/sui.keystore b/test/chains/sui/data/sui.keystore new file mode 100644 index 00000000..1c13fb23 --- /dev/null +++ b/test/chains/sui/data/sui.keystore @@ -0,0 +1,3 @@ +[ + "ALWS4mKTtggWc8gH+a5bFLFQ0AeNbZpUdDI//3OpAVys" +] \ No newline at end of file diff --git a/test/chains/sui/msg.go b/test/chains/sui/msg.go new file mode 100644 index 00000000..5c309492 --- /dev/null +++ b/test/chains/sui/msg.go @@ -0,0 +1,33 @@ +package sui + +import ( + jsoniter "github.com/json-iterator/go" +) + +type SuiCallArg struct { + Val interface{} + Type string +} +type SuiMessage struct { + Params []SuiCallArg + Method string + PackageObjectId string + Module string +} + +func (m *SuiMessage) Type() string { + return m.Method +} + +func (m *SuiMessage) MsgBytes() ([]byte, error) { + return jsoniter.Marshal(m.Params) +} + +func (p *SuiRemotenet) NewSuiMessage(params []SuiCallArg, packageId, module, method string) *SuiMessage { + return &SuiMessage{ + Params: params, + PackageObjectId: packageId, + Module: module, + Method: method, + } +} diff --git a/test/chains/sui/remotenet.go b/test/chains/sui/remotenet.go new file mode 100644 index 00000000..64c78a33 --- /dev/null +++ b/test/chains/sui/remotenet.go @@ -0,0 +1,780 @@ +package sui + +import ( + "context" + "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "math/big" + "os" + "strconv" + "strings" + "time" + + "github.com/coming-chat/go-sui/v2/account" + suisdkClient "github.com/coming-chat/go-sui/v2/client" + "github.com/coming-chat/go-sui/v2/lib" + "github.com/coming-chat/go-sui/v2/move_types" + "github.com/coming-chat/go-sui/v2/sui_types" + "github.com/coming-chat/go-sui/v2/types" + "github.com/docker/docker/client" + "github.com/fardream/go-bcs/bcs" + "github.com/icon-project/centralized-relay/test/chains" + "github.com/icon-project/centralized-relay/test/interchaintest/_internal/dockerutil" + ibcLocal "github.com/icon-project/centralized-relay/test/interchaintest/ibc" + "github.com/icon-project/centralized-relay/test/interchaintest/relayer/centralized" + "github.com/icon-project/centralized-relay/test/testsuite/testconfig" + "github.com/pelletier/go-toml/v2" + "go.uber.org/zap" + "gopkg.in/yaml.v2" +) + +const ( + suiCurrencyType = "0x2::sui::SUI" + pickMethod = 1 + baseSuiFee = 1000 + suiStringType = "0x1::string::String" + suiU64 = "u64" + suiBool = "bool" + moveCall suisdkClient.UnsafeMethod = "moveCall" + publish suisdkClient.UnsafeMethod = "publish" + queryEvents suisdkClient.SuiXMethod = "queryEvents" + callGasBudget = 500000000 + deployGasBudget = "500000000" + xcallAdmin = "xcall-admin" + xcallStorage = "xcall-storage" + sui_rlp_path = "libs/sui_rlp" + adminCap = "AdminCap" + upgradeCap = "UpgradeCap" + connectionCap = "ConnCap" + IdCapSuffix = "-idcap" + StateSuffix = "-state" + WitnessSuffix = "-witness" + witnessCarrier = "WitnessCarrier" + storage = "Storage" + CentralConnModule = "centralized_entry" + MockAppModule = "mock_dapp" + RegisterXcall = "register_xcall" + CallArgObject = "object" + CallArgPure = "pure" + connectionName = "centralized-1" +) + +func NewSuiRemotenet(testName string, log *zap.Logger, chainConfig chains.ChainConfig, client *client.Client, network string, testconfig *testconfig.Chain) chains.Chain { + suiClient, err := suisdkClient.Dial(testconfig.RPCUri) + if err != nil { + panic("error connecting sui rpc") + } + return &SuiRemotenet{ + testName: testName, + cfg: chainConfig, + log: log, + IBCAddresses: make(map[string]string), + filepath: testconfig.Contracts, + client: suiClient, + DockerClient: client, + testconfig: testconfig, + Network: network, + } +} + +func (an *SuiRemotenet) Config() chains.ChainConfig { + return an.cfg +} + +// DeployContract implements chains.Chain. +func (an *SuiRemotenet) DeployContract(ctx context.Context, keyName string) (context.Context, error) { + filePath := "/xcall/" + keyName + stdout, _, err := an.ExecBin(ctx, "sui", "client", "publish", filePath, "--skip-dependency-verification", "--gas-budget", deployGasBudget, "--json") + if err != nil { + return ctx, err + } + var resp *types.SuiTransactionBlockResponse + err = json.Unmarshal(stdout, &resp) + if err != nil { + return ctx, err + } + an.log.Info("Deploy completed ", zap.Any("txDigest", resp.Digest), zap.Any("status", resp.Effects.Data.IsSuccess())) + if resp.Effects.Data.V1.Status.Status != "success" { + return nil, fmt.Errorf("error while committing tx : %s", resp.Effects.Data.V1.Status.Error) + } + depoymentInfo := DepoymentInfo{} + for _, changes := range resp.ObjectChanges { + if changes.Data.Published != nil { + depoymentInfo.PackageId = changes.Data.Published.PackageId.String() + } + if changes.Data.Created != nil && strings.Contains(changes.Data.Created.ObjectType, adminCap) { + depoymentInfo.AdminCap = changes.Data.Created.ObjectId.String() + } + if changes.Data.Created != nil && strings.Contains(changes.Data.Created.ObjectType, upgradeCap) { + depoymentInfo.UpgradeCap = changes.Data.Created.ObjectId.String() + } + if changes.Data.Created != nil && strings.Contains(changes.Data.Created.ObjectType, storage) { + depoymentInfo.Storage = changes.Data.Created.ObjectId.String() + } + if changes.Data.Created != nil && strings.Contains(changes.Data.Created.ObjectType, witnessCarrier) { + depoymentInfo.Witness = changes.Data.Created.ObjectId.String() + } + } + return context.WithValue(ctx, "objId", depoymentInfo), nil +} + +// DeployXCallMockApp implements chains.Chain. +func (an *SuiRemotenet) DeployXCallMockApp(ctx context.Context, keyName string, connections []chains.XCallConnection) error { + if an.testconfig.Environment == "preconfigured" { + return nil + } + testcase := ctx.Value("testcase").(string) + dappKey := fmt.Sprintf("dapp-%s", testcase) + ctx, err := an.DeployContract(ctx, MockAppModule) + if err != nil { + return err + } + deploymentInfo := ctx.Value("objId").(DepoymentInfo) + an.IBCAddresses[dappKey] = deploymentInfo.PackageId + an.IBCAddresses[dappKey+WitnessSuffix] = deploymentInfo.Witness + an.log.Info("setup Dapp completed ", zap.Any("packageId", deploymentInfo.PackageId), zap.Any("witness", deploymentInfo.Witness)) + + // register xcall + params := []SuiCallArg{ + {Type: CallArgObject, Val: an.IBCAddresses[xcallStorage]}, + {Type: CallArgObject, Val: an.IBCAddresses[dappKey+WitnessSuffix]}, + } + + msg := an.NewSuiMessage(params, an.IBCAddresses[dappKey], MockAppModule, RegisterXcall) + resp, err := an.callContract(ctx, msg) + for _, changes := range resp.ObjectChanges { + if changes.Data.Created != nil && strings.Contains(changes.Data.Created.ObjectType, "DappState") { + an.IBCAddresses[dappKey+StateSuffix] = changes.Data.Created.ObjectId.String() + time.Sleep(2 * time.Second) + response, err := an.client.GetObject(ctx, changes.Data.Created.ObjectId, &types.SuiObjectDataOptions{ + ShowContent: true, + }) + if err != nil { + return err + } + fields := response.Data.Content.Data.MoveObject.Fields.(map[string]interface{}) + js, _ := json.Marshal(fields) + var objRes ObjectResult + json.Unmarshal(js, &objRes) + an.IBCAddresses[dappKey+IdCapSuffix] = objRes.XcallCap.Fields.ID.ID + } + } + + an.log.Info("register xcall completed ", zap.Any("dapp-state", an.IBCAddresses[dappKey+StateSuffix]), zap.Any("dapp-state-idcap", an.IBCAddresses[dappKey+IdCapSuffix])) + if err != nil { + return err + } + // add connections + for _, connection := range connections { + params = []SuiCallArg{ + {Type: CallArgObject, Val: an.IBCAddresses[dappKey+StateSuffix]}, + {Type: CallArgPure, Val: connection.Nid}, + {Type: CallArgPure, Val: connectionName}, + {Type: CallArgPure, Val: connection.Destination}, + } + + msg = an.NewSuiMessage(params, an.IBCAddresses[dappKey], MockAppModule, "add_connection") + resp, err = an.callContract(ctx, msg) + for _, changes := range resp.ObjectChanges { + if changes.Data.Created != nil && strings.Contains(changes.Data.Created.ObjectType, "DappState") { + an.IBCAddresses[dappKey+connection.Connection+StateSuffix] = changes.Data.Created.ObjectId.String() + } + } + if err != nil { + return err + } + } + + return nil +} + +func (an *SuiRemotenet) ExecBin(ctx context.Context, command ...string) ([]byte, []byte, error) { + return an.Exec(ctx, command, nil) +} + +// Exec implements chains.Chain. +// Subtle: this method shadows the method (*CosmosChain).Exec of SuiRemotenet.CosmosChain. +func (an *SuiRemotenet) Exec(ctx context.Context, cmd []string, env []string) (stdout []byte, stderr []byte, err error) { + job := dockerutil.NewImage(an.log, an.DockerClient, an.Network, an.testName, an.cfg.Images.Repository, an.cfg.Images.Version) + + bindPaths := []string{ + an.testconfig.ContractsPath + ":/xcall", + an.testconfig.ConfigPath + ":/root/.sui/sui_config/", + } + opts := dockerutil.ContainerOptions{ + Binds: bindPaths, + } + res := job.Run(ctx, cmd, opts) + return res.Stdout, res.Stderr, res.Err +} + +// FindCallMessage implements chains.Chain. +func (an *SuiRemotenet) FindCallMessage(ctx context.Context, startHeight uint64, from string, to string, sn string) (string, string, error) { + index := sn + event, err := an.FindEvent(ctx, startHeight, "xcall", index, "::main::CallMessage", CentralConnModule) + if err != nil { + return "", "", err + } + jsonData := (event.ParsedJson.(map[string]interface{})) + data := jsonData["data"].([]interface{}) + valueSlice := make([]byte, len(data)) + for i, v := range data { + valueSlice[i] = byte(v.(float64)) + } + return jsonData["sn"].(string), string(valueSlice), nil +} + +// FindRollbackExecutedMessage implements chains.Chain. +func (an *SuiRemotenet) FindRollbackExecutedMessage(ctx context.Context, startHeight uint64, sn string) (string, error) { + testcase := ctx.Value("testcase").(string) + dappKey := fmt.Sprintf("dapp-%s", testcase) + index := sn + event, err := an.FindEvent(ctx, startHeight, dappKey, index, "::main::RollbackExecuted", MockAppModule) + if err != nil { + return "", err + } + jsonData := (event.ParsedJson.(map[string]interface{})) + return jsonData["sn"].(string), nil +} + +func (an *SuiRemotenet) getEvent(ctx context.Context, sn, eventType, module, packageKey string) (*types.SuiEvent, error) { + limit := uint(100) + query := MoveEventRequest{ + MoveModule: MoveModule{ + Package: an.IBCAddresses[packageKey], + Module: module, + }, + } + var resp types.EventPage + err := an.client.CallContext(ctx, &resp, queryEvents, query, nil, limit, true) + + if err != nil { + return nil, err + } + for _, event := range resp.Data { + jsonData := (event.ParsedJson.(map[string]interface{})) + if jsonData["sn"] == sn && strings.Contains(event.Type, eventType) { + return &event, nil + } + } + return nil, fmt.Errorf("event not found") +} + +func (an *SuiRemotenet) FindEvent(ctx context.Context, startHeight uint64, packageKey, index, eventType, module string) (*types.SuiEvent, error) { + timeout := time.After(60 * time.Second) + ticker := time.NewTicker(5 * time.Second) + defer ticker.Stop() + + for { + select { + case <-timeout: + return nil, fmt.Errorf("failed to find eventLog") + case <-ticker.C: + data, err := an.getEvent(ctx, index, eventType, module, packageKey) + if err != nil { + continue + } + return data, nil + } + } + // // wss not working in devnet/testnet due to limited wss connections +} + +// FindCallResponse implements chains.Chain. +func (an *SuiRemotenet) FindCallResponse(ctx context.Context, startHeight uint64, sn string) (string, error) { + index := sn + event, err := an.FindEvent(ctx, startHeight, "xcall", index, "::main::ResponseMessage", CentralConnModule) + if err != nil { + return "", err + } + jsonData := (event.ParsedJson.(map[string]interface{})) + responseCode := jsonData["response_code"].(float64) + return strconv.FormatFloat(responseCode, 'f', -1, 64), nil + +} + +// FindTargetXCallMessage implements chains.Chain. +func (an *SuiRemotenet) FindTargetXCallMessage(ctx context.Context, target chains.Chain, height uint64, to string) (*chains.XCallResponse, error) { + testcase := ctx.Value("testcase").(string) + dappKey := fmt.Sprintf("dapp-%s", testcase) + sn := ctx.Value("sn").(string) + reqId, destData, err := target.FindCallMessage(ctx, height, an.cfg.ChainID+"/"+an.IBCAddresses[dappKey+IdCapSuffix], to, sn) + return &chains.XCallResponse{SerialNo: sn, RequestID: reqId, Data: destData}, err +} + +// GetContractAddress implements chains.Chain. +func (an *SuiRemotenet) GetContractAddress(key string) string { + if key == "connection" { + return connectionName + } + value, exist := an.IBCAddresses[key] + if !exist { + panic(fmt.Sprintf(`IBC address not exist %s`, key)) + } + + return value +} + +// GetGRPCAddress implements chains.Chain. +// Subtle: this method shadows the method (*CosmosChain).GetGRPCAddress of SuiRemotenet.CosmosChain. +func (an *SuiRemotenet) GetGRPCAddress() string { + return an.testconfig.RPCUri +} + +// GetHostRPCAddress implements chains.Chain. +// Subtle: this method shadows the method (*CosmosChain).GetHostRPCAddress of SuiRemotenet.CosmosChain. +func (an *SuiRemotenet) GetHostRPCAddress() string { + return an.testconfig.RPCUri +} + +// GetRPCAddress implements chains.Chain. +// Subtle: this method shadows the method (*CosmosChain).GetRPCAddress of SuiRemotenet.CosmosChain. +func (an *SuiRemotenet) GetRPCAddress() string { + return an.testconfig.RPCUri +} + +// GetRelayConfig implements chains.Chain. +func (an *SuiRemotenet) GetRelayConfig(ctx context.Context, rlyHome string, keyName string) ([]byte, error) { + testcase := ctx.Value("testcase").(string) + dappKey := fmt.Sprintf("dapp-%s", testcase) + contracts := make(map[string]string) + contracts["xcall"] = an.GetContractAddress("xcall") + dappModule := centralized.SuiDappModule{ + Name: MockAppModule, + CapId: an.GetContractAddress(dappKey + IdCapSuffix)[2:], + ConfigId: an.GetContractAddress(dappKey + StateSuffix), + } + config := ¢ralized.SUIRelayerChainConfig{ + Type: "sui", + Value: centralized.SUIRelayerChainConfigValue{ + NID: an.Config().ChainID, + RPCURL: an.GetRPCAddress(), + WebsocketUrl: an.testconfig.WebsocketUrl, + XcallPkgIds: []string{an.GetContractAddress("xcall")}, + XcallStorageId: an.GetContractAddress(xcallStorage), + ConnectionId: an.GetContractAddress("connection"), + ConnectionCapId: an.GetContractAddress("connectionCap"), + DappPkgId: an.GetContractAddress(dappKey), + DappModules: []centralized.SuiDappModule{ + dappModule, + }, + StartHeight: 0, + BlockInterval: "0s", + Address: an.testconfig.RelayWalletAddress, + FinalityBlock: uint64(0), + GasPrice: 4000000, + GasLimit: 50000000, + }, + } + return yaml.Marshal(config) +} + +// Height implements chains.Chain. +// Subtle: this method shadows the method (*CosmosChain).Height of SuiRemotenet.CosmosChain. +func (an *SuiRemotenet) Height(ctx context.Context) (uint64, error) { + checkPoint, err := an.client.GetLatestCheckpointSequenceNumber(ctx) + if err != nil { + return 0, err + } + return strconv.ParseUint(checkPoint, 10, 64) +} + +// HomeDir implements chains.Chain. +// Subtle: this method shadows the method (*CosmosChain).HomeDir of SuiRemotenet.CosmosChain. +func (an *SuiRemotenet) HomeDir() string { + return "" +} + +// InitEventListener implements chains.Chain. +func (an *SuiRemotenet) InitEventListener(ctx context.Context, contract string) chains.EventListener { + panic("unimplemented") +} + +// QueryContract implements chains.Chain. +// Subtle: this method shadows the method (*CosmosChain).QueryContract of SuiRemotenet.CosmosChain. +func (an *SuiRemotenet) QueryContract(ctx context.Context, contractAddress string, methodName string, params map[string]interface{}) (context.Context, error) { + panic("unimplemented") +} + +// RecoverKey implements chains.Chain. +// Subtle: this method shadows the method (*CosmosChain).RecoverKey of SuiRemotenet.CosmosChain. +func (an *SuiRemotenet) RecoverKey(ctx context.Context, name string, mnemonic string) error { + panic("unimplemented") +} + +// SendFunds implements chains.Chain. +// Subtle: this method shadows the method (*CosmosChain).SendFunds of SuiRemotenet.CosmosChain. +func (an *SuiRemotenet) SendFunds(ctx context.Context, keyName string, amount ibcLocal.WalletAmount) error { + panic("unimplemented") +} + +// SendPacketXCall implements chains.Chain. +func (an *SuiRemotenet) SendPacketXCall(ctx context.Context, keyName string, _to string, data []byte, rollback []byte) (context.Context, error) { + testcase := ctx.Value("testcase").(string) + dappKey := fmt.Sprintf("dapp-%s", testcase) + if rollback == nil { + rollback = make([]byte, 0) + } + gasFeeCoin := an.getGasCoinId(ctx, an.testconfig.RelayWalletAddress, callGasBudget).CoinObjectId + coinId := an.getAnotherGasCoinId(ctx, an.testconfig.RelayWalletAddress, callGasBudget, gasFeeCoin) + params := []SuiCallArg{ + {Type: CallArgObject, Val: an.IBCAddresses[dappKey+StateSuffix]}, + {Type: CallArgObject, Val: an.IBCAddresses[xcallStorage]}, + {Type: CallArgObject, Val: coinId.CoinObjectId}, + {Type: CallArgPure, Val: _to}, + {Type: CallArgPure, Val: "0x" + hex.EncodeToString(data)}, + {Type: CallArgPure, Val: "0x" + hex.EncodeToString(rollback)}, + } + msg := an.NewSuiMessage(params, an.IBCAddresses[dappKey], MockAppModule, "send_message") + resp, err := an.callContract(ctx, msg) + if err != nil { + return ctx, err + } + return context.WithValue(ctx, "sn", an.findSn(resp, "::main::CallMessageSent")), nil +} + +func (an *SuiRemotenet) findSn(tx *types.SuiTransactionBlockResponse, eType string) string { + for _, event := range tx.Events { + if event.Type == (an.IBCAddresses["xcall"] + eType) { + jsonData := (event.ParsedJson.(map[string]interface{})) + return jsonData["sn"].(string) + } + } + return "" +} + +// SetupConnection implements chains.Chain. +func (an *SuiRemotenet) SetupConnection(ctx context.Context, target chains.Chain) error { + if an.testconfig.Environment == "preconfigured" { + return nil + } + return nil +} + +func (an *SuiRemotenet) callContract(ctx context.Context, msg *SuiMessage) (*types.SuiTransactionBlockResponse, error) { + txnMetadata, err := an.ExecuteContractRemote(ctx, msg, an.testconfig.RelayWalletAddress, uint64(callGasBudget)) + if err != nil { + return nil, err + } + + walletAccount, err := account.NewAccountWithKeystore(an.testconfig.KeystorePassword) + if err != nil { + return nil, err + } + + signature, err := walletAccount.SignSecureWithoutEncode(txnMetadata.TxBytes, sui_types.DefaultIntent()) + if err != nil { + return nil, err + } + signatures := []any{signature} + + resp, err := an.CommitTx(ctx, walletAccount, txnMetadata.TxBytes, signatures) + if err != nil { + return nil, err + } + an.log.Info("Txn created", zap.Any("ID", resp.Digest), zap.Any("status", resp.Effects.Data.IsSuccess())) + if !resp.Effects.Data.IsSuccess() { + if strings.Contains(resp.Effects.Data.V1.Status.Error, "send_call_inner") { + return resp, fmt.Errorf("MaxDataSizeExceeded") + } + return resp, fmt.Errorf("txn execution failed") + } + return resp, nil +} + +// SetupXCall implements chains.Chain. +func (an *SuiRemotenet) SetupXCall(ctx context.Context) error { + if an.testconfig.Environment == "preconfigured" { + testcase := ctx.Value("testcase").(string) + an.IBCAddresses["xcall"] = "0x024bb2ef51d49bace743297d18a7ce17ee0a39d541832826f9d1ed9516b31a95" + an.IBCAddresses[xcallAdmin] = "0xe1c8d2e988ffc4ba8080dce6e490192c63717d25899025d97eab99e8548d8862" + an.IBCAddresses[xcallStorage] = "0xbc74501f4a771b9126e67d4eec781c13dcc6c790d54af789e96f9264b1eed2d8" + an.IBCAddresses["connectionCap"] = "0xba6d692ff0e2ef4deb2676f24fda5bced79abac2026b4b1f70c51f3651da02d2" + dappKey := fmt.Sprintf("dapp-%s", testcase) + an.IBCAddresses[dappKey] = "0x42c6f06edd37db92d68a6cd08713972fae7be8e7e358678400cb10d3657fa210" + an.IBCAddresses[dappKey+WitnessSuffix] = "0xa43e19bc8e56e236e4756e23ed011d1d65980b835778ac2d4f7c77d21ab0c2c9" + an.IBCAddresses[dappKey+StateSuffix] = "0xa28f7dda0671e405e0684867de55c9f3fdc7bdf50bba2e9d485ab2ad081d6a9a" + an.IBCAddresses[dappKey+IdCapSuffix] = "0x33c9150bca7c5f05b3e20ac7c82efdff0ceb4a73d7c7ed907067f4787b5534b1" + return nil + } + //deploy rlp + ctx, err := an.DeployContract(ctx, sui_rlp_path) + if err != nil { + return err + } + deploymentInfo := ctx.Value("objId").(DepoymentInfo) + err = an.updateTomlFile(sui_rlp_path, deploymentInfo.PackageId) + if err != nil { + return err + } + + // deploy xcall + ctx, err = an.DeployContract(ctx, "xcall") + if err != nil { + return err + } + deploymentInfo = ctx.Value("objId").(DepoymentInfo) + an.IBCAddresses["xcall"] = deploymentInfo.PackageId + an.IBCAddresses[xcallAdmin] = deploymentInfo.AdminCap + an.IBCAddresses[xcallStorage] = deploymentInfo.Storage + err = an.updateTomlFile("xcall", deploymentInfo.PackageId) + if err != nil { + return err + } + an.log.Info("setup xcall completed ", zap.Any("packageId", deploymentInfo.PackageId), + zap.Any("admin", deploymentInfo.AdminCap), zap.Any("storage", deploymentInfo.Storage), + zap.Any("upgradeCap", deploymentInfo.UpgradeCap)) + //configuing nid + //init + params := []SuiCallArg{ + {Type: CallArgObject, Val: an.IBCAddresses[xcallStorage]}, + {Type: CallArgObject, Val: deploymentInfo.UpgradeCap}, + {Type: CallArgPure, Val: "sui"}, + } + msg := an.NewSuiMessage(params, an.IBCAddresses["xcall"], "main", "configure_nid") + _, err = an.callContract(ctx, msg) + if err != nil { + return err + } + //init + params = []SuiCallArg{ + {Type: CallArgObject, Val: an.IBCAddresses[xcallStorage]}, + {Type: CallArgObject, Val: an.IBCAddresses[xcallAdmin]}, + {Type: CallArgPure, Val: "sui"}, + {Type: CallArgPure, Val: connectionName}, + {Type: CallArgPure, Val: an.testconfig.RelayWalletAddress}, + } + msg = an.NewSuiMessage(params, an.IBCAddresses["xcall"], "main", "register_connection") + resp, err := an.callContract(ctx, msg) + if err != nil { + return err + } + for _, changes := range resp.ObjectChanges { + if changes.Data.Created != nil && strings.Contains(changes.Data.Created.ObjectType, connectionCap) { + an.IBCAddresses["connectionCap"] = changes.Data.Created.ObjectId.String() + } + + } + an.log.Info("connection registered", zap.Any("connectionCap", an.IBCAddresses["connectionCap"])) + return err +} + +func (an *SuiRemotenet) updateTomlFile(keyName, deployedPackageId string) error { + var cfg MoveTomlConfig + filePath := an.testconfig.ContractsPath + "/" + keyName + file, err := os.Open(filePath + "/Move.toml") + if err != nil { + return err + } + defer file.Close() + moveConfig, err := io.ReadAll(file) + if err != nil { + return err + } + err = toml.Unmarshal(moveConfig, &cfg) + if err != nil { + return err + } + pkgName := cfg.Package["name"] + cfg.Addresses[pkgName] = deployedPackageId + cfg.Package["published-at"] = deployedPackageId + b, err := toml.Marshal(cfg) + if err != nil { + return err + } + err = os.WriteFile(filePath+"/Move.toml", b, 0644) + if err != nil { + return err + } + return nil +} + +// Start implements chains.Chain. +// Subtle: this method shadows the method (*CosmosChain).Start of SuiRemotenet.CosmosChain. +func (an *SuiRemotenet) Start(testName string, ctx context.Context, additionalGenesisWallets ...ibcLocal.WalletAmount) error { + panic("unimplemented") +} + +// XCall implements chains.Chain. +func (an *SuiRemotenet) XCall(ctx context.Context, targetChain chains.Chain, keyName string, _to string, data []byte, rollback []byte) (*chains.XCallResponse, error) { + height, err := targetChain.Height(ctx) + if err != nil { + return nil, err + } + ctx, err = an.SendPacketXCall(ctx, keyName, _to, data, rollback) + if err != nil { + return nil, err + } + return an.FindTargetXCallMessage(ctx, targetChain, height, strings.Split(_to, "/")[1]) +} + +func (an *SuiRemotenet) CommitTx(ctx context.Context, wallet *account.Account, txBytes lib.Base64Data, signatures []any) (*types.SuiTransactionBlockResponse, error) { + return an.client.ExecuteTransactionBlock(ctx, txBytes, signatures, &types.SuiTransactionBlockResponseOptions{ + ShowEffects: true, + ShowEvents: true, + ShowObjectChanges: true, + }, types.TxnRequestTypeWaitForLocalExecution) +} + +func (an *SuiRemotenet) getGasCoinId(ctx context.Context, addr string, gasCost uint64) *types.Coin { + accountAddress, err := move_types.NewAccountAddressHex(addr) + if err != nil { + an.log.Error(fmt.Sprintf("error getting account address sender %s", addr), zap.Error(err)) + return nil + } + result, err := an.client.GetSuiCoinsOwnedByAddress(ctx, *accountAddress) + if err != nil { + an.log.Error(fmt.Sprintf("error getting gas coins for address %s", addr), zap.Error(err)) + return nil + } + _, t, err := result.PickSUICoinsWithGas(big.NewInt(baseSuiFee), gasCost, pickMethod) + if err != nil { + an.log.Error(fmt.Sprintf("error getting gas coins with enough gas for address %s", addr), zap.Error(err)) + return nil + } + return t +} + +func (an *SuiRemotenet) getAnotherGasCoinId(ctx context.Context, addr string, gasCost uint64, existingGasAddress move_types.AccountAddress) *types.Coin { + accountAddress, err := move_types.NewAccountAddressHex(addr) + if err != nil { + an.log.Error(fmt.Sprintf("error getting account address sender %s", addr), zap.Error(err)) + return nil + } + coins, err := an.client.GetAllCoins(ctx, *accountAddress, nil, 1000) + if err != nil { + an.log.Error(fmt.Sprintf("error getting gas coins for address %s", addr), zap.Error(err)) + return nil + } + for _, coin := range coins.Data { + if coin.Balance.Uint64() > gasCost && coin.CoinObjectId != existingGasAddress { + return &coin + } + } + return nil +} + +func (an *SuiRemotenet) ExecuteContractRemote(ctx context.Context, suiMessage *SuiMessage, address string, gasBudget uint64) (*types.TransactionBytes, error) { + accountAddress, err := move_types.NewAccountAddressHex(an.testconfig.RelayWalletAddress) + if err != nil { + return &types.TransactionBytes{}, fmt.Errorf("error getting account address sender: %w", err) + } + packageId, err := move_types.NewAccountAddressHex(suiMessage.PackageObjectId) + if err != nil { + return &types.TransactionBytes{}, fmt.Errorf("invalid packageId: %w", err) + } + coinId := an.getGasCoinId(ctx, an.testconfig.RelayWalletAddress, gasBudget) + coinAddress, err := move_types.NewAccountAddressHex(coinId.CoinObjectId.String()) + if err != nil { + return &types.TransactionBytes{}, fmt.Errorf("error getting gas coinid : %w", err) + } + typeArgs := []string{} + var args []interface{} + for _, param := range suiMessage.Params { + args = append(args, param.Val) + } + + resp := types.TransactionBytes{} + err = an.client.CallContext( + ctx, + &resp, + moveCall, + *accountAddress, + packageId, + suiMessage.Module, + suiMessage.Method, + typeArgs, + args, + coinAddress, + types.NewSafeSuiBigInt(gasBudget), + "DevInspect", + ) + return &resp, err +} + +func (an *SuiRemotenet) QueryContractRemote(ctx context.Context, suiMessage *SuiMessage, address string, gasBudget uint64) (any, error) { + builder := sui_types.NewProgrammableTransactionBuilder() + packageId, err := move_types.NewAccountAddressHex(suiMessage.PackageObjectId) + if err != nil { + return nil, err + } + senderAddress, err := move_types.NewAccountAddressHex(address) + if err != nil { + return nil, err + } + callArgs, err := paramsToCallArgs(suiMessage) + if err != nil { + return nil, err + } + err = builder.MoveCall( + *packageId, + move_types.Identifier(suiMessage.Module), + move_types.Identifier(suiMessage.Method), + []move_types.TypeTag{}, + callArgs, + ) + if err != nil { + return nil, err + } + transaction := builder.Finish() + bcsBytes, err := bcs.Marshal(transaction) + if err != nil { + return nil, err + } + txBytes := append([]byte{0}, bcsBytes...) + b64Data, err := lib.NewBase64Data(base64.StdEncoding.EncodeToString(txBytes)) + if err != nil { + return nil, err + } + res, err := an.client.DevInspectTransactionBlock(context.Background(), *senderAddress, *b64Data, nil, nil) + if err != nil { + return nil, err + } + if res.Error != nil { + return nil, fmt.Errorf("error occurred while calling sui contract: %s", *res.Error) + } + result := (res.Results[0].ReturnValues[0]).([]interface{}) + resultType := result[1] + byteSlice, ok := result[0].([]byte) + if !ok { + return nil, err + } + return extractResult(resultType, byteSlice, result[0]) +} + +func extractResult(resultType interface{}, byteSlice []byte, defResult interface{}) (any, error) { + switch resultType { + case suiU64: + var u64Value uint64 + bcs.Unmarshal(byteSlice, &u64Value) + return u64Value, nil + case suiStringType: + var strValue string + bcs.Unmarshal(byteSlice, &strValue) + return strValue, nil + case suiBool: + var booleanValue bool + bcs.Unmarshal(byteSlice, &booleanValue) + return booleanValue, nil + default: + return defResult, nil + } +} + +// convert native params to bcs encoded params +func paramsToCallArgs(suiMessage *SuiMessage) ([]sui_types.CallArg, error) { + var callArgs []sui_types.CallArg + for _, param := range suiMessage.Params { + byteParam, err := bcs.Marshal(param) + if err != nil { + return nil, err + } + callArgs = append(callArgs, sui_types.CallArg{ + Pure: &byteParam, + }) + } + return callArgs, nil +} diff --git a/test/chains/sui/types.go b/test/chains/sui/types.go new file mode 100644 index 00000000..92aea848 --- /dev/null +++ b/test/chains/sui/types.go @@ -0,0 +1,77 @@ +package sui + +import ( + suisdkClient "github.com/coming-chat/go-sui/v2/client" + "github.com/docker/docker/client" + "github.com/icon-project/centralized-relay/test/chains" + "github.com/icon-project/centralized-relay/test/testsuite/testconfig" + "github.com/strangelove-ventures/interchaintest/v8/ibc" + "go.uber.org/zap" +) + +type SuiRemotenet struct { + cfg chains.ChainConfig + filepath map[string]string + IBCAddresses map[string]string `json:"addresses"` + Wallets map[string]ibc.Wallet `json:"wallets"` + log *zap.Logger + DockerClient *client.Client + Network string + testconfig *testconfig.Chain + testName string + client *suisdkClient.Client +} + +type MoveTomlConfig struct { + Package map[string]string `toml:"package"` + Dependencies map[string]Dependency `toml:"dependencies"` + Addresses map[string]string `toml:"addresses"` + DevDependencies map[string]Dependency `toml:"dev-dependencies"` + DevAddresses map[string]string `toml:"dev-addresses"` +} + +type Dependency struct { + Git string `toml:"git,omitempty"` + Subdir string `toml:"subdir,omitempty"` + Rev string `toml:"rev,omitempty"` + Local string `toml:"local,omitempty"` +} + +type DepoymentInfo struct { + PackageId string + AdminCap string + UpgradeCap string + Storage string + Witness string + IdCap string +} + +type PackageInfo struct { + Modules []string `json:"modules"` + Dependencies []string `json:"dependencies"` + Digest []int `json:"digest"` +} + +type FieldFilter struct { + Path string `json:"path"` + Value interface{} `json:"value"` +} + +type MoveModule struct { + Package string `json:"package"` + Module string `json:"module"` +} + +type MoveEventRequest struct { + MoveModule MoveModule `json:"MoveModule"` +} + +type ObjectResult struct { + XcallCap struct { + Fields struct { + ID struct { + ID string `json:"id,omitempty"` + } `json:"id,omitempty"` + } `json:"fields,omitempty"` + } `json:"xcall_cap,omitempty"` +} diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 645df84e..0c67b5d9 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -18,7 +18,7 @@ type E2ETest struct { } func (s *E2ETest) TestE2E_all() { - //go panicOnTimeout(10 * time.Hour) // custom timeout + // go panicOnTimeout(10 * time.Hour) // custom timeout t := s.T() testcase := "xcall" diff --git a/test/e2e/tests/xcall.go b/test/e2e/tests/xcall.go index e3e0b43b..b7cbe994 100644 --- a/test/e2e/tests/xcall.go +++ b/test/e2e/tests/xcall.go @@ -13,6 +13,11 @@ import ( "github.com/stretchr/testify/assert" ) +const ( + CS_RESP_FAILURE = "0" + CS_RESP_SUCCESS = "1" +) + type XCallTestSuite struct { *testsuite.E2ETestSuite T *testing.T @@ -20,162 +25,125 @@ type XCallTestSuite struct { func (x *XCallTestSuite) TextXCall() { testcase := "xcall" - portId := "transfer" - ctx := context.WithValue(context.TODO(), "testcase", testcase) - x.Require().NoError(x.DeployXCallMockApp(ctx, portId), "fail to deploy xcall demo dapp") + ctx := context.WithValue(context.Background(), "testcase", testcase) createdChains := x.GetChains() - if len(createdChains) == 3 { - test3Chains(ctx, createdChains, x) - } - if len(createdChains) == 2 { - test2Chains(ctx, createdChains, x) - } + testChains(ctx, createdChains, x) } -func test3Chains(ctx context.Context, createdChains []chains.Chain, x *XCallTestSuite) { - chainA, chainB, chainC := createdChains[0], createdChains[1], createdChains[2] - fmt.Println("ChainA", chainA.Config().Name) - fmt.Println("ChainB", chainB.Config().Name) - fmt.Println("ChainC", chainC.Config().Name) - x.T.Run("xcall one way message chainA-chainB", func(t *testing.T) { - fmt.Println("Sending message from src to dst", chainA.Config().Name, chainB.Config().Name) - err := x.testOneWayMessage(ctx, t, chainA, chainB) - assert.NoErrorf(t, err, "fail xCall one way message chainA-chainB ::%v\n ", err) - }) - x.T.Run("xcall one way message chainB-chainA", func(t *testing.T) { - fmt.Println("Sending message from src to dst", chainB.Config().Name, chainA.Config().Name) - err := x.testOneWayMessage(ctx, t, chainB, chainA) - assert.NoErrorf(t, err, "fail xCall one way message chainB-chainA ::%v\n ", err) - }) - x.T.Run("xcall one way message chainB-chainC", func(t *testing.T) { - fmt.Println("Sending message from src to dst", chainB.Config().Name, chainC.Config().Name) - err := x.testOneWayMessage(ctx, t, chainB, chainC) - assert.NoErrorf(t, err, "fail xCall one way message chainB-chainc ::%v\n ", err) - }) - x.T.Run("xcall one way message chainC-chainB", func(t *testing.T) { - fmt.Println("Sending message from src to dst", chainC.Config().Name, chainB.Config().Name) - err := x.testOneWayMessage(ctx, t, chainC, chainB) - assert.NoErrorf(t, err, "fail xCall one way message chainC-chainB ::%v\n ", err) - }) - x.T.Run("xcall one way message chainA-chainC", func(t *testing.T) { - fmt.Println("Sending message from src to dst", chainA.Config().Name, chainC.Config().Name) - err := x.testOneWayMessage(ctx, t, chainA, chainC) - assert.NoErrorf(t, err, "fail xCall one way message chainA-chainC ::%v\n ", err) - }) - x.T.Run("xcall one way message chainC-chainA", func(t *testing.T) { - fmt.Println("Sending message from src to dst", chainC.Config().Name, chainA.Config().Name) - err := x.testOneWayMessage(ctx, t, chainC, chainA) - assert.NoErrorf(t, err, "fail xCall one way message chainC-chainA ::%v\n ", err) - }) - - x.T.Run("xcall test rollback chainA-chainB", func(t *testing.T) { - err := x.testRollback(ctx, t, chainA, chainB) - assert.NoErrorf(t, err, "fail xCall rollback message chainA-chainB ::%v\n ", err) +func isInList(processedList []string, item string) bool { + for _, val := range processedList { + if val == item { + return true + } + } + return false +} - }) +func testChains(ctx context.Context, createdChains []chains.Chain, x *XCallTestSuite) { + var processedList []string + for index, chain := range createdChains { + for innerIndex, innerChain := range createdChains { + if index != innerIndex { + chainFlowIdentifier := chain.Config().Name + "-" + innerChain.Config().Name + if !isInList(processedList, chainFlowIdentifier) { + processedList = append(processedList, chainFlowIdentifier) + chainFlowName := chain.Config().Name + "->" + innerChain.Config().Name + x.T.Run("xcall one way message chainA-chainB "+chainFlowName, func(t *testing.T) { + fmt.Println("Sending message from src to dst", chain.Config().Name, innerChain.Config().Name) + err := x.testOneWayMessage(ctx, t, chain, innerChain) + assert.NoErrorf(t, err, "fail xCall one way message chainA-chainB( %s) ::%v\n ", chainFlowIdentifier, err) + }) + x.T.Run("xcall test rollback chainA-chainB "+chainFlowName, func(t *testing.T) { + fmt.Println("Sending rollback message from src to dst", chain.Config().Name, innerChain.Config().Name) + err := x.testRollback(ctx, t, chain, innerChain) + assert.NoErrorf(t, err, "fail xCall rollback message chainA-chainB( %s) ::%v\n ", chainFlowIdentifier, err) + }) - x.T.Run("2xcall test rollback chainA-chainC", func(t *testing.T) { - err := x.testRollback(ctx, t, chainA, chainC) - assert.NoErrorf(t, err, "fail xCall rollback message chainA-chainC ::%v\n ", err) - }) + x.T.Run("xcall test rollback data chainA-chainB without rollback "+chainFlowName, func(t *testing.T) { + fmt.Println("Sending rollback message from src to dst", chain.Config().Name, innerChain.Config().Name) + err := x.testRollbackDataWithoutRollback(ctx, t, chain, innerChain) + assert.NoErrorf(t, err, "fail xCall rollback message chainA-chainB( %s) ::%v\n ", chainFlowIdentifier, err) + }) - x.T.Run("xcall test rollback chainB-chainA", func(t *testing.T) { - err := x.testRollback(ctx, t, chainB, chainA) - assert.NoErrorf(t, err, "fail xcCll rollback message chainB-chainA ::%v\n ", err) - }) - x.T.Run("2xcall test rollback chainB-chainC", func(t *testing.T) { - err := x.testRollback(ctx, t, chainB, chainC) - assert.NoErrorf(t, err, "fail xcCll rollback message chainB-chainC ::%v\n ", err) - }) + x.T.Run("xcall test rollback data reply chainA-chainB without rollback "+chainFlowName, func(t *testing.T) { + fmt.Println("Sending rollback message from src to dst", chain.Config().Name, innerChain.Config().Name) + err := x.testRollbackDataReplyWithoutRollback(ctx, t, chain, innerChain) + assert.NoErrorf(t, err, "fail xCall rollback message chainA-chainB( %s) ::%v\n ", chainFlowIdentifier, err) + }) - x.T.Run("xcall test rollback chainC-chainA", func(t *testing.T) { - err := x.testRollback(ctx, t, chainC, chainA) - assert.NoErrorf(t, err, "fail xcCll rollback message chainC-chainA ::%v\n ", err) - }) + x.T.Run("xcall test send maxSize Data: 2048 bytes A-> B "+chainFlowName, func(t *testing.T) { + fmt.Println("Sending allowed size data from src to dst", chain.Config().Name, innerChain.Config().Name) + x.testOneWayMessageWithSize(ctx, t, 1300, chain, innerChain) + }) - x.T.Run("2xcall test rollback chainC-chainB", func(t *testing.T) { - err := x.testRollback(ctx, t, chainC, chainB) - assert.NoErrorf(t, err, "fail xcCll rollback message chainC-chainB ::%v\n ", err) - }) + x.T.Run("xcall test send maxSize Data: 2049bytes "+chainFlowName, func(t *testing.T) { + fmt.Println("Sending more than max size data from src to dst", chain.Config().Name, innerChain.Config().Name) + x.testOneWayMessageWithSizeExpectingError(ctx, t, 2000, chain, innerChain) + }) - x.T.Run("xcall test send maxSize Data: 2048 bytes", func(t *testing.T) { - x.T.Run("xcall test send maxSize Data: 2048 bytes A->B", func(t *testing.T) { - x.testOneWayMessageWithSize(ctx, t, 1200, chainA, chainB) - }) - x.T.Run("xcall test send maxSize Data: 2048 bytes B->A", func(t *testing.T) { - x.testOneWayMessageWithSize(ctx, t, 1200, chainB, chainA) - }) - x.T.Run("xcall test send maxSize Data: 2048 bytes C->A", func(t *testing.T) { - x.testOneWayMessageWithSize(ctx, t, 1200, chainC, chainA) - }) - x.T.Run("xcall test send maxSize Data: 2048 bytes A->C", func(t *testing.T) { - x.testOneWayMessageWithSize(ctx, t, 1200, chainA, chainC) - }) - }) + } + reverseChainFlowIdentifier := innerChain.Config().Name + "-" + chain.Config().Name + if !isInList(processedList, reverseChainFlowIdentifier) { + processedList = append(processedList, reverseChainFlowIdentifier) + reverseChainFlowName := innerChain.Config().Name + "->" + chain.Config().Name + x.T.Run("xcall one way message chainB-chainA "+reverseChainFlowName, func(t *testing.T) { + fmt.Println("Sending message from src to dst", innerChain.Config().Name, chain.Config().Name) + err := x.testOneWayMessage(ctx, t, innerChain, chain) + assert.NoErrorf(t, err, "fail xCall one way message chainB-chainA (%s) ::%v \n ", reverseChainFlowIdentifier, err) + }) - x.T.Run("xcall test send maxSize Data: 2049bytes", func(t *testing.T) { - x.T.Run("xcall test send maxSize Data: 2049 bytes B->A", func(t *testing.T) { - x.testOneWayMessageWithSizeExpectingError(ctx, t, 2000, chainB, chainA) - }) - x.T.Run("xcall test send maxSize Data: 2049 bytes A->B", func(t *testing.T) { - x.testOneWayMessageWithSizeExpectingError(ctx, t, 2100, chainA, chainB) - }) - x.T.Run("xcall test send maxSize Data: 2049 bytes C->A", func(t *testing.T) { - x.testOneWayMessageWithSizeExpectingError(ctx, t, 2100, chainC, chainA) - }) - x.T.Run("xcall test send maxSize Data: 2049 bytes A->C", func(t *testing.T) { - x.testOneWayMessageWithSizeExpectingError(ctx, t, 2100, chainA, chainC) - }) - }) -} + x.T.Run("xcall test rollback chainB-chainA"+reverseChainFlowName, func(t *testing.T) { + fmt.Println("Sending rollback message from src to dst", chain.Config().Name, innerChain.Config().Name) + err := x.testRollback(ctx, t, innerChain, chain) + assert.NoErrorf(t, err, "fail xCall rollback message chainB-chainA( %s) ::%v\n ", reverseChainFlowIdentifier, err) + }) -func test2Chains(ctx context.Context, createdChains []chains.Chain, x *XCallTestSuite) { - chainA, chainB := createdChains[0], createdChains[1] - fmt.Println("ChainA", chainA.Config().Name) - fmt.Println("ChainB", chainB.Config().Name) - x.T.Run("xcall one way message chainA-chainB", func(t *testing.T) { - fmt.Println("Sending message from src to dst", chainA.Config().Name, chainB.Config().Name) - err := x.testOneWayMessage(ctx, t, chainA, chainB) - assert.NoErrorf(t, err, "fail xCall one way message chainA-chainB ::%v\n ", err) - }) - x.T.Run("xcall one way message chainB-chainA", func(t *testing.T) { + x.T.Run("xcall test rollback data chainB-chainA without rollback "+reverseChainFlowName, func(t *testing.T) { + fmt.Println("Sending rollback message from src to dst", chain.Config().Name, innerChain.Config().Name) + err := x.testRollbackDataWithoutRollback(ctx, t, innerChain, chain) + assert.NoErrorf(t, err, "fail xCall rollback message chainB-chainA( %s) ::%v\n ", reverseChainFlowIdentifier, err) + }) - fmt.Println("Sending message from src to dst", chainB.Config().Name, chainA.Config().Name) - err := x.testOneWayMessage(ctx, t, chainB, chainA) - assert.NoErrorf(t, err, "fail xCall one way message chainB-chainA ::%v\n ", err) - }) - x.T.Run("2xcall test rollback chainA-chainB", func(t *testing.T) { - fmt.Println("Sending rollback message from src to dst", chainA.Config().Name, chainB.Config().Name) - err := x.testRollback(ctx, t, chainA, chainB) - assert.NoErrorf(t, err, "fail xCall rollback message chainA-chainB ::%v\n ", err) - }) + x.T.Run("xcall test rollback data reply data chainB-chainA without rollback "+reverseChainFlowName, func(t *testing.T) { + fmt.Println("Sending rollback message from src to dst", chain.Config().Name, innerChain.Config().Name) + err := x.testRollbackDataReplyWithoutRollback(ctx, t, innerChain, chain) + assert.NoErrorf(t, err, "fail xCall rollback message chainB-chainA( %s) ::%v\n ", reverseChainFlowIdentifier, err) + }) - x.T.Run("xcall test rollback chainB-chainA", func(t *testing.T) { - err := x.testRollback(ctx, t, chainB, chainA) - assert.NoErrorf(t, err, "fail xcCll rollback message chainB-chainA ::%v\n ", err) - }) + x.T.Run("xcall test send maxSize Data: 2048 bytes B-> A "+reverseChainFlowName, func(t *testing.T) { + fmt.Println("Sending allowed size data from src to dst", innerChain.Config().Name, chain.Config().Name) + x.testOneWayMessageWithSize(ctx, t, 1300, innerChain, chain) + }) - x.T.Run("xcall test send maxSize Data: 2048 bytes A-> B", func(t *testing.T) { - x.testOneWayMessageWithSize(ctx, t, 1300, chainA, chainB) - }) + x.T.Run("xcall test send maxSize Data: 2049bytes "+reverseChainFlowName, func(t *testing.T) { + fmt.Println("ending more than max size data from src to dst", innerChain.Config().Name, chain.Config().Name) + x.testOneWayMessageWithSizeExpectingError(ctx, t, 2000, innerChain, chain) + }) + } - x.T.Run("xcall test send maxSize Data: 2048 bytes B-> A", func(t *testing.T) { - x.testOneWayMessageWithSize(ctx, t, 1300, chainB, chainA) - }) + } + } + } +} - x.T.Run("xcall test send maxSize Data: 2049bytes", func(t *testing.T) { - x.testOneWayMessageWithSizeExpectingError(ctx, t, 2000, chainB, chainA) - x.testOneWayMessageWithSizeExpectingError(ctx, t, 2100, chainA, chainB) - }) +func handlePanicAndGetContractAddress(chain chains.Chain, contractName, fallbackContractName string) (address string) { + defer func() { + if r := recover(); r != nil { + address = chain.GetContractAddress(fallbackContractName) + return + } + }() + address = chain.GetContractAddress(contractName) + return address } func (x *XCallTestSuite) testOneWayMessage(ctx context.Context, t *testing.T, chainA, chainB chains.Chain) error { testcase := ctx.Value("testcase").(string) dappKey := fmt.Sprintf("dapp-%s", testcase) msg := "MessageTransferTestingWithoutRollback" - dst := chainB.Config().ChainID + "/" + chainB.GetContractAddress(dappKey) - + dAppAddress := handlePanicAndGetContractAddress(chainB, dappKey+"-idcap", dappKey) + dst := chainB.Config().ChainID + "/" + dAppAddress res, err := chainA.XCall(ctx, chainB, chainB.Config().Name, dst, []byte(msg), nil) result := assert.NoErrorf(t, err, "error on sending packet- %v", err) if !result { @@ -199,7 +167,8 @@ func (x *XCallTestSuite) testRollback(ctx context.Context, t *testing.T, chainA, dappKey := fmt.Sprintf("dapp-%s", testcase) msg := "rollback" rollback := "RollbackDataTesting" - dst := chainB.Config().ChainID + "/" + chainB.GetContractAddress(dappKey) + dAppAddress := handlePanicAndGetContractAddress(chainB, dappKey+"-idcap", dappKey) + dst := chainB.Config().ChainID + "/" + dAppAddress res, err := chainA.XCall(ctx, chainB, chainB.Config().Name, dst, []byte(msg), []byte(rollback)) isSuccess := assert.NoErrorf(t, err, "error on sending packet- %v", err) if !isSuccess { @@ -209,13 +178,61 @@ func (x *XCallTestSuite) testRollback(ctx context.Context, t *testing.T, chainA, assert.NoErrorf(t, err, "error getting height %v", err) code, err := chainA.FindCallResponse(ctx, height, res.SerialNo) assert.NoErrorf(t, err, "no call response found %v", err) - isSuccess = assert.Equal(t, "0", code) + isSuccess = assert.Equal(t, CS_RESP_FAILURE, code) if !isSuccess { return err } - time.Sleep(3 * time.Second) _, err = chainA.FindRollbackExecutedMessage(ctx, height, res.SerialNo) - assert.NoErrorf(t, err, "error on excute rollback- %w", err) + assert.NoErrorf(t, err, "no rollback executed message found %v", err) + fmt.Println("Data Transfer Testing With Rollback from " + chainA.Config().ChainID + " to " + chainB.Config().ChainID + " with data " + msg + " and rollback:" + rollback + " PASSED") + return err +} + +func (x *XCallTestSuite) testRollbackDataWithoutRollback(ctx context.Context, t *testing.T, chainA, chainB chains.Chain) error { + testcase := ctx.Value("testcase").(string) + dappKey := fmt.Sprintf("dapp-%s", testcase) + msg := "MessageTransferTestingWithoutRollback" + rollback := "rollbackData" + dAppAddress := handlePanicAndGetContractAddress(chainB, dappKey+"-idcap", dappKey) + dst := chainB.Config().ChainID + "/" + dAppAddress + res, err := chainA.XCall(ctx, chainB, chainB.Config().Name, dst, []byte(msg), []byte(rollback)) + isSuccess := assert.NoErrorf(t, err, "error on sending packet- %v", err) + if !isSuccess { + return err + } + height, err := chainA.Height(ctx) + assert.NoErrorf(t, err, "error getting height %v", err) + code, err := chainA.FindCallResponse(ctx, height, res.SerialNo) + assert.NoErrorf(t, err, "no call response found %v", err) + isSuccess = assert.Equal(t, CS_RESP_SUCCESS, code) + if !isSuccess { + return err + } + fmt.Println("Data Transfer Testing Without Rollback from " + chainA.Config().ChainID + " to " + chainB.Config().ChainID + " with data " + msg + " and rollback:" + rollback + " PASSED") + return nil +} + +func (x *XCallTestSuite) testRollbackDataReplyWithoutRollback(ctx context.Context, t *testing.T, chainA, chainB chains.Chain) error { + testcase := ctx.Value("testcase").(string) + dappKey := fmt.Sprintf("dapp-%s", testcase) + msg := "reply-reponse" + rollback := "rollbackData" + dAppAddress := handlePanicAndGetContractAddress(chainB, dappKey+"-idcap", dappKey) + dst := chainB.Config().ChainID + "/" + dAppAddress + res, err := chainA.XCall(ctx, chainB, chainB.Config().Name, dst, []byte(msg), []byte(rollback)) + isSuccess := assert.NoErrorf(t, err, "error on sending packet- %v", err) + if !isSuccess { + return err + } + height, err := chainA.Height(ctx) + assert.NoErrorf(t, err, "error getting height %v", err) + code, err := chainA.FindCallResponse(ctx, height, res.SerialNo) + assert.NoErrorf(t, err, "no call response found %v", err) + isSuccess = assert.Equal(t, CS_RESP_SUCCESS, code) + if !isSuccess { + return err + } + time.Sleep(3 * time.Second) fmt.Println("Data Transfer Testing Without Rollback from " + chainA.Config().ChainID + " to " + chainB.Config().ChainID + " with data " + msg + " and rollback:" + rollback + " PASSED") return err } @@ -224,16 +241,22 @@ func (x *XCallTestSuite) testOneWayMessageWithSize(ctx context.Context, t *testi testcase := ctx.Value("testcase").(string) dappKey := fmt.Sprintf("dapp-%s", testcase) _msg := make([]byte, dataSize) - dst := chainB.Config().ChainID + "/" + chainB.GetContractAddress(dappKey) - _, err := chainA.XCall(ctx, chainB, chainB.Config().Name, dst, _msg, nil) + + dAppAddress := handlePanicAndGetContractAddress(chainB, dappKey+"-idcap", dappKey) + dst := chainB.Config().ChainID + "/" + dAppAddress + res, err := chainA.XCall(ctx, chainB, chainB.Config().Name, dst, _msg, nil) + assert.NoErrorf(t, err, "error on sending packet- %v", err) + assert.NotEmpty(t, res.RequestID, "retrieved requestId should not be empty") assert.NoError(t, err) + fmt.Println("Data Transfer Testing With Message Size from " + chainA.Config().ChainID + " to " + chainB.Config().ChainID + " with data " + string(_msg) + " PASSED") } func (x *XCallTestSuite) testOneWayMessageWithSizeExpectingError(ctx context.Context, t *testing.T, dataSize int, chainA, chainB chains.Chain) { testcase := ctx.Value("testcase").(string) dappKey := fmt.Sprintf("dapp-%s", testcase) _msg := make([]byte, dataSize) - dst := chainB.Config().ChainID + "/" + chainB.GetContractAddress(dappKey) + dAppAddress := handlePanicAndGetContractAddress(chainB, dappKey+"-idcap", dappKey) + dst := chainB.Config().ChainID + "/" + dAppAddress _, err := chainA.XCall(ctx, chainB, chainB.Config().Name, dst, _msg, nil) result := assert.Errorf(t, err, "large data transfer should failed") if result { @@ -250,6 +273,7 @@ func (x *XCallTestSuite) testOneWayMessageWithSizeExpectingError(ctx context.Con } if result { t.Logf("Test passed: %v", err) + fmt.Println("Data Transfer Testing With Message Size expecting error from " + chainA.Config().ChainID + " to " + chainB.Config().ChainID + " with data " + string(_msg) + " PASSED") } else { t.Errorf("Test failed: %v", err) } diff --git a/test/go.mod b/test/go.mod index 4dcc865a..2d7c1379 100644 --- a/test/go.mod +++ b/test/go.mod @@ -6,12 +6,16 @@ require ( github.com/BurntSushi/toml v1.3.2 github.com/avast/retry-go/v4 v4.6.0 github.com/cometbft/cometbft v0.38.6 + github.com/coming-chat/go-sui/v2 v2.0.1 github.com/cosmos/cosmos-sdk v0.50.6 github.com/docker/docker v24.0.7+incompatible github.com/docker/go-connections v0.5.0 github.com/ethereum/go-ethereum v1.14.0 + github.com/fardream/go-bcs v0.4.0 github.com/gorilla/websocket v1.5.1 github.com/icon-project/icon-bridge v0.0.11 + github.com/json-iterator/go v1.1.12 + github.com/pelletier/go-toml/v2 v2.2.2 github.com/spf13/viper v1.18.2 github.com/strangelove-ventures/interchaintest/v8 v8.2.0 github.com/stretchr/testify v1.9.0 @@ -47,6 +51,7 @@ require ( github.com/bshuster-repo/logrus-logstash-hook v0.4.1 // indirect github.com/btcsuite/btcd v0.21.0-beta // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect + github.com/btcsuite/btcutil v1.0.2 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -56,6 +61,7 @@ require ( 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/coming-chat/go-aptos v0.0.0-20221013022715-39f91035c785 // 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 @@ -139,14 +145,16 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mtibben/percent v0.2.1 // indirect github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect github.com/oklog/run v1.1.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc2 // indirect - github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 // indirect github.com/philhofer/fwd v1.0.0 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -163,6 +171,7 @@ require ( github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect + github.com/shopspring/decimal v1.3.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect @@ -177,6 +186,7 @@ require ( github.com/tinylib/msgp v1.1.2 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // 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 github.com/vmihailenco/msgpack/v4 v4.3.11 // indirect diff --git a/test/go.sum b/test/go.sum index 2c78b60c..fba7f394 100644 --- a/test/go.sum +++ b/test/go.sum @@ -195,6 +195,7 @@ github.com/btcsuite/btcd/btcutil v1.1.3/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9E github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts= github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= @@ -260,6 +261,10 @@ github.com/cometbft/cometbft v0.38.6 h1:QSgpCzrGWJ2KUq1qpw+FCfASRpE27T6LQbfEHscd github.com/cometbft/cometbft v0.38.6/go.mod h1:8rSPxzUJYquCN8uuBgbUHOMg2KAwvr7CyUw+6ukO4nw= github.com/cometbft/cometbft-db v0.9.1 h1:MIhVX5ja5bXNHF8EYrThkG9F7r9kSfv8BX4LWaxWJ4M= github.com/cometbft/cometbft-db v0.9.1/go.mod h1:iliyWaoV0mRwBJoizElCwwRA9Tf7jZJOURcRZF9m60U= +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= +github.com/coming-chat/go-sui/v2 v2.0.1/go.mod h1:0/cgsi6HcHEfPFC05mY/ovzWuxxpmKxiY0NIEFgMP4g= github.com/consensys/bavard v0.1.8-0.20210406032232-f3452dc9b572/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= @@ -410,6 +415,8 @@ github.com/ethereum/go-ethereum v1.14.0 h1:xRWC5NlB6g1x7vNy4HDBLuqVNbtLrc7v8S6+U github.com/ethereum/go-ethereum v1.14.0/go.mod h1:1STrq471D0BQbCX9He0hUj4bHxX2k6mt5nOQJhDNOJ8= 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= +github.com/fardream/go-bcs v0.4.0/go.mod h1:UsoxhIoe2GsVexX0s5NDLIChxeb/JUbjw7IWzzgF3Xk= github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= @@ -1197,6 +1204,8 @@ github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eI github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -1351,8 +1360,8 @@ github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7ir github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.0.1-0.20170904195809-1d6b12b7cb29/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= -github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +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/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= @@ -1478,6 +1487,7 @@ github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= +github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= diff --git a/test/interchaintest/relayer/centralized/centralized_relayer.go b/test/interchaintest/relayer/centralized/centralized_relayer.go index f094c788..1f00d506 100644 --- a/test/interchaintest/relayer/centralized/centralized_relayer.go +++ b/test/interchaintest/relayer/centralized/centralized_relayer.go @@ -52,6 +52,31 @@ type ICONRelayerChainConfigValue struct { StepLimit int64 `yaml:"step-limit"` } +type SUIRelayerChainConfigValue struct { + NID string `yaml:"nid"` + RPCURL string `yaml:"rpc-url"` + WebsocketUrl string `yaml:"ws-url"` + StartHeight int `yaml:"start-height"` + XcallPkgIds []string `yaml:"xcall-package-ids"` + ConnectionId string `yaml:"connection-id"` + ConnectionCapId string `yaml:"connection-cap-id"` + DappPkgId string `yaml:"dapp-package-id"` + XcallStorageId string `yaml:"xcall-storage-id"` + NetworkID int `yaml:"network-id"` + BlockInterval string `yaml:"block-interval"` + Address string `yaml:"address"` + FinalityBlock uint64 `yaml:"finality-block"` + GasPrice int64 `yaml:"gas-price"` + GasLimit int `yaml:"gas-limit"` + DappModules []SuiDappModule `yaml:"dapp-modules"` +} + +type SuiDappModule struct { + Name string `yaml:"name"` + CapId string `yaml:"cap-id"` + ConfigId string `yaml:"config-id"` +} + type EVMRelayerChainConfigValue struct { NID string `yaml:"nid"` RPCURL string `yaml:"rpc-url"` @@ -105,6 +130,11 @@ type CosmosRelayerChainConfig struct { Value CosmosRelayerChainConfigValue `json:"value"` } +type SUIRelayerChainConfig struct { + Type string `json:"type"` + Value SUIRelayerChainConfigValue `json:"value"` +} + const ( DefaultContainerImage = "centralized-relay" DefaultContainerVersion = "latest" diff --git a/test/relayer/data/keystore/sui/0xe847098636459aa93f4da105414edca4790619b291ffdac49419f5adc19c4d21 b/test/relayer/data/keystore/sui/0xe847098636459aa93f4da105414edca4790619b291ffdac49419f5adc19c4d21 new file mode 100644 index 00000000..7ea81d39 Binary files /dev/null and b/test/relayer/data/keystore/sui/0xe847098636459aa93f4da105414edca4790619b291ffdac49419f5adc19c4d21 differ diff --git a/test/relayer/data/keystore/sui/0xe847098636459aa93f4da105414edca4790619b291ffdac49419f5adc19c4d21.pass b/test/relayer/data/keystore/sui/0xe847098636459aa93f4da105414edca4790619b291ffdac49419f5adc19c4d21.pass new file mode 100644 index 00000000..e1ee1ec5 Binary files /dev/null and b/test/relayer/data/keystore/sui/0xe847098636459aa93f4da105414edca4790619b291ffdac49419f5adc19c4d21.pass differ diff --git a/test/sample-config.yaml b/test/sample-config.yaml index ff4fe45a..765116b6 100644 --- a/test/sample-config.yaml +++ b/test/sample-config.yaml @@ -1,40 +1,37 @@ chains: - - name: archway + - name: sui version: "3" - environment: local - 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 + 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: wasm - name: archway - chain_id: localnet-1 - bin: archwayd + type: sui + name: sui + chain_id: sui image: - repository: ghcr.io/archway-network/archwayd-dev - version: v6.0.1-amd64 + repository: mysten/sui-tools-w-git + version: devnet uid_gid: "" - bech32_prefix: archway + bin: sui + bech32_prefix: 0x denom: arch coin_type: 118 - gas_prices: 0.000arch + gas_prices: 0.001sui gas_adjustment: 1.3 trusting_period: 508h no_host_mount: false - nid: "archway.local" 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" + 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: icon version: "3" - environment: local - rpc_uri: https://tt.net.solidwallet.io/jvm-rpc/api/v3/ + environment: remote + rpc_uri: https://tt.net.solidwallet.io/jvm-rpc/api/v3/ keystore_file: godwallet.json keystore_password: gochain relay_wallet : hxb6b5791be0b5ef67063b3c10b840fb81514db2fd @@ -56,9 +53,42 @@ 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: 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: foundry version: "3" - environment: local + environment: remote rpc_uri: https://tt.net.solidwallet.io/hardhat-rpc websocket_uri: wss://tt.net.solidwallet.io/hardhat-rpc relay_wallet : 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 @@ -73,9 +103,9 @@ chains: uid_gid: "" bin: cast bech32_prefix: 0x - denom: arch + denom: gwei coin_type: 118 - gas_prices: 0.001arch + gas_prices: 0.001gwei gas_adjustment: 1.3 trusting_period: 508h no_host_mount: false @@ -85,7 +115,7 @@ chains: dapp: "$BASE_PATH/artifacts/evm/MultiProtocolSampleDapp" relayer: image: centralized-relay - tag: event-subscription + tag: latest kms_id: 5ef77041-d1e6-4af1-9a41-e49a4b45efb6 # kms_url is required in case of local kms is being used kms_url: http://docker.for.mac.host.internal:8088 diff --git a/test/testsuite/testsuite.go b/test/testsuite/testsuite.go index a5873b6a..0be28574 100644 --- a/test/testsuite/testsuite.go +++ b/test/testsuite/testsuite.go @@ -8,6 +8,7 @@ import ( "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/sui" "github.com/icon-project/centralized-relay/test/interchaintest" "github.com/icon-project/centralized-relay/test/testsuite/testconfig" @@ -100,6 +101,10 @@ func (s *E2ETestSuite) SetupRelayer(ctx context.Context, name string) (ibc.Relay if err := s.SetupXCall(ctx); err != nil { return nil, err } + portId := "transfer" + if err := s.DeployXCallMockApp(ctx, portId); err != nil { + return nil, err + } if err := ic.BuildRelayer(ctx, eRep, buildOptions, s.cfg.RelayerConfig.KMS_ID); err != nil { return nil, err @@ -123,7 +128,6 @@ func (s *E2ETestSuite) SetupRelayer(ctx context.Context, name string) (ibc.Relay func (s *E2ETestSuite) DeployXCallMockApp(ctx context.Context, port string) error { createdChains := s.GetChains() - // chainA, chainB := createdChains[0], createdChains[1] for idx, chain := range createdChains { var connections []chains.XCallConnection for id, cn := range createdChains { @@ -277,7 +281,6 @@ func buildChain(log *zap.Logger, testName string, s *E2ETestSuite, cfg *testconf var ( chain chains.Chain ) - // ibcChainConfig := cfg.ChainConfig.GetIBCChainConfig(&chain) switch cfg.ChainConfig.Type { case "icon": chain = icon.NewIconRemotenet(testName, log, cfg.ChainConfig, s.DockerClient, s.network, cfg) @@ -286,9 +289,11 @@ func buildChain(log *zap.Logger, testName string, s *E2ETestSuite, cfg *testconf chain = evm.NewEVMRemotenet(testName, log, cfg.ChainConfig, s.DockerClient, s.network, cfg) return chain, nil case "wasm", "cosmos": - // interchainTestConfig := toInterchantestConfig(ibcChainConfig) chain, err := cosmos.NewCosmosRemotenet(testName, log, cfg.ChainConfig, s.DockerClient, s.network, cfg) return chain, err + case "sui": + chain := sui.NewSuiRemotenet(testName, log, cfg.ChainConfig, s.DockerClient, s.network, cfg) + return chain, nil default: return nil, fmt.Errorf("unexpected error, unknown chain type: %s for chain: %s", cfg.ChainConfig.Type, cfg.Name) }