diff --git a/changelog.md b/changelog.md index ad0deb58d3..c80a744c33 100644 --- a/changelog.md +++ b/changelog.md @@ -38,6 +38,7 @@ * [1525](https://github.com/zeta-chain/node/pull/1525) - relax EVM chain block header length check 1024->4096 * [1522](https://github.com/zeta-chain/node/pull/1522/files) - block `distribution` module account from receiving zeta * [1528](https://github.com/zeta-chain/node/pull/1528) - fix panic caused on decoding malformed BTC addresses +* [1536](https://github.com/zeta-chain/node/pull/1536) - add index to check previously finalized inbounds * [1556](https://github.com/zeta-chain/node/pull/1556) - add emptiness check for topic array in event parsing * [1555](https://github.com/zeta-chain/node/pull/1555) - Reduce websocket message limit to 10MB diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index cb87e0dfc4..6c170fc142 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -50813,6 +50813,8 @@ definitions: inbound_tx_finalized_zeta_height: type: string format: uint64 + tx_finalization_status: + $ref: '#/definitions/crosschainTxFinalizationStatus' crosschainLastBlockHeight: type: object properties: @@ -50914,6 +50916,8 @@ definitions: format: uint64 tss_pubkey: type: string + tx_finalization_status: + $ref: '#/definitions/crosschainTxFinalizationStatus' crosschainQueryAllCctxResponse: type: object properties: @@ -51064,6 +51068,17 @@ definitions: properties: aborted_zeta_amount: type: string + crosschainTxFinalizationStatus: + type: string + enum: + - NotFinalized + - Finalized + - Executed + default: NotFinalized + title: |- + - NotFinalized: the corresponding tx is not finalized + - Finalized: the corresponding tx is finalized but not executed yet + - Executed: the corresponding tx is executed crosschainTxHashList: type: object properties: diff --git a/proto/crosschain/cross_chain_tx.proto b/proto/crosschain/cross_chain_tx.proto index ed38a74597..28f9d92452 100644 --- a/proto/crosschain/cross_chain_tx.proto +++ b/proto/crosschain/cross_chain_tx.proto @@ -16,6 +16,12 @@ enum CctxStatus { Aborted = 6; // inbound tx error or invalid paramters and cannot revert; just abort } +enum TxFinalizationStatus { + option (gogoproto.goproto_enum_stringer) = true; + NotFinalized = 0; // the corresponding tx is not finalized + Finalized = 1; // the corresponding tx is finalized but not executed yet + Executed = 2; // the corresponding tx is executed +} message InboundTxParams { string sender = 1; // this address is the immediate contract/EOA that calls the Connector.send() int64 sender_chain_id = 2; @@ -30,6 +36,7 @@ message InboundTxParams { uint64 inbound_tx_observed_external_height = 8; string inbound_tx_ballot_index = 9; uint64 inbound_tx_finalized_zeta_height = 10; + TxFinalizationStatus tx_finalization_status = 11; } message ZetaAccounting { @@ -63,6 +70,7 @@ message OutboundTxParams { ]; uint64 outbound_tx_effective_gas_limit = 22; string tss_pubkey = 11; + TxFinalizationStatus tx_finalization_status = 12; } message Status { diff --git a/proto/crosschain/genesis.proto b/proto/crosschain/genesis.proto index 46d1b18066..016fc38aee 100644 --- a/proto/crosschain/genesis.proto +++ b/proto/crosschain/genesis.proto @@ -22,4 +22,5 @@ message GenesisState { repeated InTxHashToCctx inTxHashToCctxList = 9 [(gogoproto.nullable) = false]; repeated InTxTracker in_tx_tracker_list = 11 [(gogoproto.nullable) = false]; ZetaAccounting zeta_accounting = 12 [(gogoproto.nullable) = false]; + repeated string FinalizedInbounds = 16; } diff --git a/standalone-network/change-observer-params.sh b/standalone-network/change-observer-params.sh index 209c33706e..4df238642f 100644 --- a/standalone-network/change-observer-params.sh +++ b/standalone-network/change-observer-params.sh @@ -1,2 +1,2 @@ -zetacored tx gov submit-proposal param-change proposal.json --from zeta --keyring-backend=test -b block --chain-id=localnet_101-1 --gas=auto --gas-prices=0.1azeta --gas-adjustment=1.5 --yes +zetacored tx gov submit-proposal proposal_feemarket.json --from zeta --keyring-backend=test -b block --chain-id=localnet_101-1 --gas=auto --gas-prices=0.1azeta --gas-adjustment=1.5 --yes zetacored tx gov vote 1 yes --from zeta --keyring-backend test --chain-id localnet_101-1 --yes --gas=auto --gas-prices=0.1azeta --gas-adjustment=1.5 \ No newline at end of file diff --git a/standalone-network/proposal_feemarket.json b/standalone-network/proposal_feemarket.json new file mode 100644 index 0000000000..1ec114d19a --- /dev/null +++ b/standalone-network/proposal_feemarket.json @@ -0,0 +1,15 @@ +{ + "messages": [ + { + "@type": "/ethermint.feemarket.v1.MsgUpdateParams", + "authority": "zeta10d07y265gmmuvt4z0w9aw880jnsr700jvxasvr", + "params": { + "base_fee": "7", + "min_gas_price" : "100000000000000", + "base_fee_change_denominator": "8" + } + } + ], + "metadata" : "some metadata", + "deposit": "10000000azeta" +} \ No newline at end of file diff --git a/testutil/sample/common.go b/testutil/sample/common.go index 0d41ea6862..d32ca30274 100644 --- a/testutil/sample/common.go +++ b/testutil/sample/common.go @@ -86,3 +86,8 @@ func Proof() (txIndex int64, block *ethtypes.Block, header ethtypes.Header, head tx = block.Transactions()[txIndex] return } + +func EventIndex() uint64 { + r := newRandFromSeed(1) + return r.Uint64() +} diff --git a/testutil/sample/crosschain.go b/testutil/sample/crosschain.go index a2e1e18846..35082be7d1 100644 --- a/testutil/sample/crosschain.go +++ b/testutil/sample/crosschain.go @@ -116,3 +116,22 @@ func ZetaAccounting(t *testing.T, index string) types.ZetaAccounting { AbortedZetaAmount: math.NewUint(uint64(r.Int63())), } } + +func InboundVote(coinType common.CoinType, from, to int64) types.MsgVoteOnObservedInboundTx { + return types.MsgVoteOnObservedInboundTx{ + Creator: "", + Sender: EthAddress().String(), + SenderChainId: Chain(from).GetChainId(), + Receiver: EthAddress().String(), + ReceiverChain: Chain(to).GetChainId(), + Amount: UintInRange(10000000, 1000000000), + Message: String(), + InBlockHeight: Uint64InRange(1, 10000), + GasLimit: 1000000000, + InTxHash: Hash().String(), + CoinType: coinType, + TxOrigin: EthAddress().String(), + Asset: "", + EventIndex: EventIndex(), + } +} diff --git a/testutil/sample/observer.go b/testutil/sample/observer.go index 19b186e845..b5d533c4e6 100644 --- a/testutil/sample/observer.go +++ b/testutil/sample/observer.go @@ -88,15 +88,15 @@ func ChainParams(chainID int64) *types.ChainParams { ChainId: chainID, ConfirmationCount: r.Uint64(), - GasPriceTicker: Uint64InRange(r, 1, 300), - InTxTicker: Uint64InRange(r, 1, 300), - OutTxTicker: Uint64InRange(r, 1, 300), - WatchUtxoTicker: Uint64InRange(r, 1, 300), + GasPriceTicker: Uint64InRange(1, 300), + InTxTicker: Uint64InRange(1, 300), + OutTxTicker: Uint64InRange(1, 300), + WatchUtxoTicker: Uint64InRange(1, 300), ZetaTokenContractAddress: EthAddress().String(), ConnectorContractAddress: EthAddress().String(), Erc20CustodyContractAddress: EthAddress().String(), - OutboundTxScheduleInterval: Int64InRange(r, 1, 100), - OutboundTxScheduleLookahead: Int64InRange(r, 1, 500), + OutboundTxScheduleInterval: Int64InRange(1, 100), + OutboundTxScheduleLookahead: Int64InRange(1, 500), BallotThreshold: fiftyPercent, MinObserverDelegation: sdk.NewDec(r.Int63()), IsSupported: false, diff --git a/testutil/sample/sample.go b/testutil/sample/sample.go index 37bb1883e4..4fcc9ac9e8 100644 --- a/testutil/sample/sample.go +++ b/testutil/sample/sample.go @@ -7,6 +7,7 @@ import ( "strconv" "testing" + sdkmath "cosmossdk.io/math" "github.com/zeta-chain/zetacore/cmd/zetacored/config" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" @@ -131,11 +132,18 @@ func Coins() sdk.Coins { } // Uint64InRange returns a sample uint64 in the given ranges -func Uint64InRange(r *rand.Rand, low, high uint64) uint64 { +func Uint64InRange(low, high uint64) uint64 { + r := newRandFromSeed(int64(low)) return r.Uint64()%(high-low) + low } // Int64InRange returns a sample int64 in the given ranges -func Int64InRange(r *rand.Rand, low, high int64) int64 { +func Int64InRange(low, high int64) int64 { + r := newRandFromSeed(low) return r.Int63()%(high-low) + low } + +func UintInRange(low, high uint64) sdkmath.Uint { + u := Uint64InRange(low, high) + return sdkmath.NewUint(u) +} diff --git a/typescript/crosschain/cross_chain_tx_pb.d.ts b/typescript/crosschain/cross_chain_tx_pb.d.ts index 4a00361f6f..d8216afcff 100644 --- a/typescript/crosschain/cross_chain_tx_pb.d.ts +++ b/typescript/crosschain/cross_chain_tx_pb.d.ts @@ -54,6 +54,32 @@ export declare enum CctxStatus { Aborted = 6, } +/** + * @generated from enum zetachain.zetacore.crosschain.TxFinalizationStatus + */ +export declare enum TxFinalizationStatus { + /** + * the corresponding tx is not finalized + * + * @generated from enum value: NotFinalized = 0; + */ + NotFinalized = 0, + + /** + * the corresponding tx is finalized but not executed yet + * + * @generated from enum value: Finalized = 1; + */ + Finalized = 1, + + /** + * the corresponding tx is executed + * + * @generated from enum value: Executed = 2; + */ + Executed = 2, +} + /** * @generated from message zetachain.zetacore.crosschain.InboundTxParams */ @@ -114,6 +140,11 @@ export declare class InboundTxParams extends Message { */ inboundTxFinalizedZetaHeight: bigint; + /** + * @generated from field: zetachain.zetacore.crosschain.TxFinalizationStatus tx_finalization_status = 11; + */ + txFinalizationStatus: TxFinalizationStatus; + constructor(data?: PartialMessage); static readonly runtime: typeof proto3; @@ -232,6 +263,11 @@ export declare class OutboundTxParams extends Message { */ tssPubkey: string; + /** + * @generated from field: zetachain.zetacore.crosschain.TxFinalizationStatus tx_finalization_status = 12; + */ + txFinalizationStatus: TxFinalizationStatus; + constructor(data?: PartialMessage); static readonly runtime: typeof proto3; diff --git a/typescript/crosschain/genesis_pb.d.ts b/typescript/crosschain/genesis_pb.d.ts index 7d4741170a..e8c8d5dcf0 100644 --- a/typescript/crosschain/genesis_pb.d.ts +++ b/typescript/crosschain/genesis_pb.d.ts @@ -59,6 +59,11 @@ export declare class GenesisState extends Message { */ zetaAccounting?: ZetaAccounting; + /** + * @generated from field: repeated string FinalizedInbounds = 16; + */ + FinalizedInbounds: string[]; + constructor(data?: PartialMessage); static readonly runtime: typeof proto3; diff --git a/x/crosschain/client/integrationtests/cli_helpers.go b/x/crosschain/client/integrationtests/cli_helpers.go index 7daaf2ed7e..03f565fc97 100644 --- a/x/crosschain/client/integrationtests/cli_helpers.go +++ b/x/crosschain/client/integrationtests/cli_helpers.go @@ -242,7 +242,7 @@ func BuildSignedOutboundVote( return WriteToNewTempFile(t, res.String()) } -func BuildSignedInboundVote(t testing.TB, val *network.Validator, denom string, account authtypes.AccountI, message string) *os.File { +func BuildSignedInboundVote(t testing.TB, val *network.Validator, denom string, account authtypes.AccountI, message string, eventIndex int) *os.File { cmd := cli.CmdCCTXInboundVoter() inboundVoterArgs := []string{ "0x96B05C238b99768F349135de0653b687f9c13fEE", @@ -256,7 +256,7 @@ func BuildSignedInboundVote(t testing.TB, val *network.Validator, denom string, "100", "Zeta", "", - "0", + strconv.Itoa(eventIndex), } txArgs := []string{ fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address), @@ -274,7 +274,7 @@ func BuildSignedInboundVote(t testing.TB, val *network.Validator, denom string, return WriteToNewTempFile(t, res.String()) } -func GetBallotIdentifier(message string) string { +func GetBallotIdentifier(message string, eventIndex int) string { msg := types.NewMsgVoteOnObservedInboundTx( "", "0x96B05C238b99768F349135de0653b687f9c13fEE", @@ -289,7 +289,8 @@ func GetBallotIdentifier(message string) string { 250_000, common.CoinType_Zeta, "", - 0, + // #nosec G701 always positive + uint(eventIndex), ) return msg.Digest() } diff --git a/x/crosschain/client/integrationtests/inbound_voter_test.go b/x/crosschain/client/integrationtests/inbound_voter_test.go index cd01d95381..ce0a0043e8 100644 --- a/x/crosschain/client/integrationtests/inbound_voter_test.go +++ b/x/crosschain/client/integrationtests/inbound_voter_test.go @@ -203,7 +203,7 @@ func (s *IntegrationTestSuite) TestCCTXInboundVoter() { }, ballotResult: observerTypes.BallotStatus_BallotInProgress, cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, - falseBallotIdentifier: GetBallotIdentifier("majority wrong votes incorrect ballot finalized / correct ballot still in progress" + "falseVote"), + falseBallotIdentifier: "majority wrong votes incorrect ballot finalized / correct ballot still in progress" + "falseVote", }, { name: "7 votes only just crossed threshold", @@ -223,7 +223,7 @@ func (s *IntegrationTestSuite) TestCCTXInboundVoter() { cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, }, } - for _, test := range tt { + for i, test := range tt { test := test s.Run(test.name, func() { // Vote the gas price @@ -266,14 +266,14 @@ func (s *IntegrationTestSuite) TestCCTXInboundVoter() { if vote == observerTypes.VoteType_FailureObservation { message = message + "falseVote" } - signedTx := BuildSignedInboundVote(s.T(), val, s.cfg.BondDenom, account, message) + signedTx := BuildSignedInboundVote(s.T(), val, s.cfg.BondDenom, account, message, i) out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetBroadcastCommand(), []string{signedTx.Name(), "--broadcast-mode", "sync"}) s.Require().NoError(err) } s.Require().NoError(s.network.WaitForNBlocks(2)) // Get the ballot - ballotIdentifier := GetBallotIdentifier(test.name) + ballotIdentifier := GetBallotIdentifier(test.name, i) out, err := clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, observercli.CmdBallotByIdentifier(), []string{ballotIdentifier, "--output", "json"}) s.Require().NoError(err) ballot := observerTypes.QueryBallotByIdentifierResponse{} @@ -293,7 +293,7 @@ func (s *IntegrationTestSuite) TestCCTXInboundVoter() { // Get the cctx and check its status cctxIdentifier := ballotIdentifier if test.falseBallotIdentifier != "" { - cctxIdentifier = test.falseBallotIdentifier + cctxIdentifier = GetBallotIdentifier(test.falseBallotIdentifier, i) } out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, crosschaincli.CmdShowSend(), []string{cctxIdentifier, "--output", "json"}) cctx := crosschaintypes.QueryGetCctxResponse{} diff --git a/x/crosschain/client/integrationtests/outbound_voter_test.go b/x/crosschain/client/integrationtests/outbound_voter_test.go index cb36954838..d388adc003 100644 --- a/x/crosschain/client/integrationtests/outbound_voter_test.go +++ b/x/crosschain/client/integrationtests/outbound_voter_test.go @@ -115,7 +115,9 @@ func (s *IntegrationTestSuite) TestCCTXOutBoundVoter() { valueReceived: "7991636132140714751", }, } - for _, test := range tt { + for i, test := range tt { + // Buffer event index so that it does not clash with the inbound voter test + eventIndex := i + 100 test := test s.Run(test.name, func() { broadcaster := s.network.Validators[0] @@ -148,14 +150,14 @@ func (s *IntegrationTestSuite) TestCCTXOutBoundVoter() { var account authtypes.AccountI s.NoError(val.ClientCtx.Codec.UnmarshalInterfaceJSON(out.Bytes(), &account)) message := test.name - signedTx := BuildSignedInboundVote(s.T(), val, s.cfg.BondDenom, account, message) + signedTx := BuildSignedInboundVote(s.T(), val, s.cfg.BondDenom, account, message, eventIndex) out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetBroadcastCommand(), []string{signedTx.Name(), "--broadcast-mode", "sync"}) s.Require().NoError(err) } s.Require().NoError(s.network.WaitForNBlocks(2)) // Get the ballot - cctxIdentifier := GetBallotIdentifier(test.name) + cctxIdentifier := GetBallotIdentifier(test.name, eventIndex) out, err := clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, crosschaincli.CmdShowSend(), []string{cctxIdentifier, "--output", "json"}) cctx := crosschaintypes.QueryGetCctxResponse{} s.NoError(broadcaster.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &cctx)) diff --git a/x/crosschain/genesis.go b/x/crosschain/genesis.go index 06ec239962..d152c32bb3 100644 --- a/x/crosschain/genesis.go +++ b/x/crosschain/genesis.go @@ -50,7 +50,9 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) k.SetCctxAndNonceToCctxAndInTxHashToCctx(ctx, *elem) } } - + for _, elem := range genState.FinalizedInbounds { + k.SetFinalizedInbound(ctx, elem) + } } // ExportGenesis returns the crosschain module's exported genesis. @@ -87,6 +89,7 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { if found { genesis.ZetaAccounting = amount } + genesis.FinalizedInbounds = k.GetAllFinalizedInbound(ctx) return &genesis } diff --git a/x/crosschain/keeper/finalized_inbounds.go b/x/crosschain/keeper/finalized_inbounds.go new file mode 100644 index 0000000000..8bb95ac820 --- /dev/null +++ b/x/crosschain/keeper/finalized_inbounds.go @@ -0,0 +1,34 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +func (k Keeper) SetFinalizedInbound(ctx sdk.Context, finalizedInboundIndex string) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.FinalizedInboundsKey)) + store.Set(types.KeyPrefix(finalizedInboundIndex), []byte{1}) +} + +func (k Keeper) AddFinalizedInbound(ctx sdk.Context, intxHash string, chainID int64, eventIndex uint64) { + finalizedInboundIndex := types.FinalizedInboundKey(intxHash, chainID, eventIndex) + k.SetFinalizedInbound(ctx, finalizedInboundIndex) +} +func (k Keeper) IsFinalizedInbound(ctx sdk.Context, intxHash string, chainID int64, eventIndex uint64) bool { + finalizedInboundIndex := types.FinalizedInboundKey(intxHash, chainID, eventIndex) + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.FinalizedInboundsKey)) + return store.Has(types.KeyPrefix(finalizedInboundIndex)) +} + +func (k Keeper) GetAllFinalizedInbound(ctx sdk.Context) (list []string) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.FinalizedInboundsKey)) + iterator := sdk.KVStorePrefixIterator(store, []byte{}) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + iterator.Value() + list = append(list, string(iterator.Key())) + } + return +} diff --git a/x/crosschain/keeper/finalized_inbounds_test.go b/x/crosschain/keeper/finalized_inbounds_test.go new file mode 100644 index 0000000000..9946024aa8 --- /dev/null +++ b/x/crosschain/keeper/finalized_inbounds_test.go @@ -0,0 +1,82 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + keepertest "github.com/zeta-chain/zetacore/testutil/keeper" + "github.com/zeta-chain/zetacore/testutil/sample" + "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +func TestKeeper_IsFinalizedInbound(t *testing.T) { + t.Run("check true for finalized inbound", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + intxHash := sample.Hash().String() + chainID := sample.Chain(5).ChainId + eventIndex := sample.EventIndex() + k.AddFinalizedInbound(ctx, intxHash, chainID, eventIndex) + require.True(t, k.IsFinalizedInbound(ctx, intxHash, chainID, eventIndex)) + }) + t.Run("check false for non-finalized inbound", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + intxHash := sample.Hash().String() + chainID := sample.Chain(5).ChainId + eventIndex := sample.EventIndex() + require.False(t, k.IsFinalizedInbound(ctx, intxHash, chainID, eventIndex)) + }) + t.Run("check true for finalized inbound list", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + listSize := 1000 + txHashList := make([]string, listSize) + chainIdList := make([]int64, listSize) + eventIndexList := make([]uint64, listSize) + for i := 0; i < listSize; i++ { + txHashList[i] = sample.Hash().String() + chainIdList[i] = sample.Chain(5).ChainId + eventIndexList[i] = sample.EventIndex() + k.AddFinalizedInbound(ctx, txHashList[i], chainIdList[i], eventIndexList[i]) + } + for i := 0; i < listSize; i++ { + require.True(t, k.IsFinalizedInbound(ctx, txHashList[i], chainIdList[i], eventIndexList[i])) + } + }) +} + +func TestKeeper_AddFinalizedInbound(t *testing.T) { + t.Run("check add finalized inbound", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + intxHash := sample.Hash().String() + chainID := sample.Chain(5).ChainId + eventIndex := sample.EventIndex() + k.AddFinalizedInbound(ctx, intxHash, chainID, eventIndex) + require.True(t, k.IsFinalizedInbound(ctx, intxHash, chainID, eventIndex)) + }) +} + +func TestKeeper_GetAllFinalizedInbound(t *testing.T) { + t.Run("check empty list", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + list := k.GetAllFinalizedInbound(ctx) + require.Empty(t, list) + }) + t.Run("check list", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + listSize := 1000 + txHashList := make([]string, listSize) + chainIdList := make([]int64, listSize) + eventIndexList := make([]uint64, listSize) + for i := 0; i < listSize; i++ { + txHashList[i] = sample.Hash().String() + chainIdList[i] = sample.Chain(5).ChainId + eventIndexList[i] = sample.EventIndex() + k.AddFinalizedInbound(ctx, txHashList[i], chainIdList[i], eventIndexList[i]) + } + list := k.GetAllFinalizedInbound(ctx) + require.Equal(t, listSize, len(list)) + for i := 0; i < listSize; i++ { + require.Contains(t, list, types.FinalizedInboundKey(txHashList[i], chainIdList[i], eventIndexList[i])) + } + require.NotContains(t, list, types.FinalizedInboundKey(sample.Hash().String(), sample.Chain(5).ChainId, sample.EventIndex())) + }) +} diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index 50954d1a15..57c3e54041 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/zeta-chain/zetacore/common" @@ -90,6 +91,10 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg return nil, err } if isNew { + // Check if the inbound has already been processed. + if k.IsFinalizedInbound(ctx, msg.InTxHash, msg.SenderChainId, msg.EventIndex) { + return nil, errorsmod.Wrap(types.ErrObservedTxAlreadyFinalized, fmt.Sprintf("InTxHash:%s, SenderChainID:%d, EventIndex:%d", msg.InTxHash, msg.SenderChainId, msg.EventIndex)) + } observerKeeper.EmitEventBallotCreated(ctx, ballot, msg.InTxHash, observationChain.String()) } // AddVoteToBallot adds a vote and sets the ballot @@ -98,8 +103,8 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg return nil, err } - _, isFinalized := k.zetaObserverKeeper.CheckIfFinalizingVote(ctx, ballot) - if !isFinalized { + _, isFinalizedInThisBlock := k.zetaObserverKeeper.CheckIfFinalizingVote(ctx, ballot) + if !isFinalizedInThisBlock { // Return nil here to add vote to ballot and commit state return &types.MsgVoteOnObservedInboundTxResponse{}, nil } @@ -123,8 +128,10 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg cctx := k.CreateNewCCTX(ctx, msg, index, tssPub, types.CctxStatus_PendingInbound, observationChain, receiverChain) defer func() { EmitEventInboundFinalized(ctx, &cctx) + k.AddFinalizedInbound(ctx, msg.InTxHash, msg.SenderChainId, msg.EventIndex) // #nosec G701 always positive cctx.InboundTxParams.InboundTxFinalizedZetaHeight = uint64(ctx.BlockHeight()) + cctx.InboundTxParams.TxFinalizationStatus = types.TxFinalizationStatus_Executed k.RemoveInTxTrackerIfExists(ctx, cctx.InboundTxParams.SenderChainId, cctx.InboundTxParams.InboundTxObservedHash) k.SetCctxAndNonceToCctxAndInTxHashToCctx(ctx, cctx) }() @@ -203,7 +210,6 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg commit() cctx.CctxStatus.ChangeStatus(types.CctxStatus_PendingRevert, revertMessage) return &types.MsgVoteOnObservedInboundTxResponse{}, nil - } // successful HandleEVMDeposit; commit() diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go index ef6c8fe3d1..32a0578ed8 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go @@ -1,66 +1,154 @@ -package keeper +package keeper_test import ( + "encoding/hex" "testing" + //"github.com/zeta-chain/zetacore/common" + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/assert" + "github.com/zeta-chain/zetacore/common" + keepertest "github.com/zeta-chain/zetacore/testutil/keeper" + "github.com/zeta-chain/zetacore/testutil/sample" + "github.com/zeta-chain/zetacore/x/crosschain/keeper" "github.com/zeta-chain/zetacore/x/crosschain/types" + observerTypes "github.com/zeta-chain/zetacore/x/observer/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) -// FIMXE: make it work -//func Test_CalculateGasFee(t *testing.T) { -// -// tt := []struct { -// name string -// gasPrice sdk.Uint // Sample gasPrice posted by zeta-client based on observed value and posted to core using PostGasPriceVoter -// gasLimit sdk.Uint // Sample gasLimit used in smartContract call -// rate sdk.Uint // Sample Rate obtained from UniSwapV2 / V3 and posted to core using PostGasPriceVoter -// expectedFee sdk.Uint // ExpectedFee in Zeta Tokens -// }{ -// { -// name: "Test Price1", -// gasPrice: sdk.NewUintFromString("20000000000"), -// gasLimit: sdk.NewUintFromString("90000"), -// rate: sdk.NewUintFromString("1000000000000000000"), -// expectedFee: sdk.NewUintFromString("1001800000000000000"), -// }, -// } -// for _, test := range tt { -// test := test -// t.Run(test.name, func(t *testing.T) { -// assert.Equal(t, test.expectedFee, CalculateFee(test.gasPrice, test.gasLimit, test.rate)) -// }) -// } -//} +func setObservers(t *testing.T, k *keeper.Keeper, ctx sdk.Context, zk keepertest.ZetaKeepers) []string { + validators := k.StakingKeeper.GetAllValidators(ctx) -// FIXME: make it work -//func Test_UpdateGasFees(t *testing.T) { -// keeper, ctx := setupKeeper(t) -// cctx := createNCctx(keeper, ctx, 1) -// cctx[0].Amount = sdk.NewUintFromString("8000000000000000000") -// keeper.SetGasPrice(ctx, types.GasPrice{ -// Creator: cctx[0].Creator, -// Index: cctx[0].OutboundTxParams.ReceiverChain, -// Chain: cctx[0].OutboundTxParams.ReceiverChain, -// Signers: []string{cctx[0].Creator}, -// BlockNums: nil, -// Prices: []uint64{20000000000, 20000000000, 20000000000, 20000000000}, -// MedianIndex: 0, -// }) -// //keeper.SetZetaConversionRate(ctx, types.ZetaConversionRate{ -// // Index: cctx[0].OutboundTxParams.ReceiverChain, -// // Chain: cctx[0].OutboundTxParams.ReceiverChain, -// // Signers: []string{cctx[0].Creator}, -// // BlockNums: nil, -// // ZetaConversionRates: []string{"1000000000000000000", "1000000000000000000", "1000000000000000000", "1000000000000000000"}, -// // NativeTokenSymbol: "", -// // MedianIndex: 0, -// //}) -// err := keeper.PayGasInZetaAndUpdateCctx(ctx, cctx[0].OutboundTxParams.ReceiverChain, &cctx[0]) -// assert.NoError(t, err) -// fmt.Println(cctx[0].String()) -//} + validatorAddressListFormatted := make([]string, len(validators)) + for i, validator := range validators { + valAddr, err := sdk.ValAddressFromBech32(validator.OperatorAddress) + assert.NoError(t, err) + addressTmp, err := sdk.AccAddressFromHexUnsafe(hex.EncodeToString(valAddr.Bytes())) + assert.NoError(t, err) + validatorAddressListFormatted[i] = addressTmp.String() + } + + // Add validator to the observer list for voting + zk.ObserverKeeper.SetObserverSet(ctx, observertypes.ObserverSet{ + ObserverList: validatorAddressListFormatted, + }) + return validatorAddressListFormatted +} +func TestKeeper_VoteOnObservedInboundTx(t *testing.T) { + t.Run("successfully vote on evm deposit", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + msgServer := keeper.NewMsgServerImpl(*k) + validatorList := setObservers(t, k, ctx, zk) + to, from := int64(1337), int64(101) + chains := zk.ObserverKeeper.GetSupportedChains(ctx) + for _, chain := range chains { + if common.IsEVMChain(chain.ChainId) { + from = chain.ChainId + } + if common.IsZetaChain(chain.ChainId) { + to = chain.ChainId + } + } + msg := sample.InboundVote(0, from, to) + for _, validatorAddr := range validatorList { + msg.Creator = validatorAddr + _, err := msgServer.VoteOnObservedInboundTx( + ctx, + &msg, + ) + assert.NoError(t, err) + } + ballot, _, _ := zk.ObserverKeeper.FindBallot(ctx, msg.Digest(), zk.ObserverKeeper.GetSupportedChainFromChainID(ctx, msg.SenderChainId), observerTypes.ObservationType_InBoundTx) + assert.Equal(t, ballot.BallotStatus, observerTypes.BallotStatus_BallotFinalized_SuccessObservation) + cctx, found := k.GetCrossChainTx(ctx, msg.Digest()) + assert.True(t, found) + assert.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_OutboundMined) + assert.Equal(t, cctx.InboundTxParams.TxFinalizationStatus, types.TxFinalizationStatus_Executed) + }) + // TODO : https://github.com/zeta-chain/node/issues/1542 +} + +/* +Potential Double Event Submission +*/ +func TestNoDoubleEventProtections(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + + // MsgServer for the crosschain keeper + msgServer := keeper.NewMsgServerImpl(*k) + // Set the chain ids we want to use to be valid + params := observertypes.DefaultParams() + zk.ObserverKeeper.SetParams( + ctx, params, + ) + + // Convert the validator address into a user address. + validators := k.StakingKeeper.GetAllValidators(ctx) + validatorAddress := validators[0].OperatorAddress + valAddr, _ := sdk.ValAddressFromBech32(validatorAddress) + addresstmp, _ := sdk.AccAddressFromHexUnsafe(hex.EncodeToString(valAddr.Bytes())) + validatorAddr := addresstmp.String() + + // Add validator to the observer list for voting + zk.ObserverKeeper.SetObserverSet(ctx, observertypes.ObserverSet{ + ObserverList: []string{validatorAddr}, + }) + + // Vote on the FIRST message. + msg := &types.MsgVoteOnObservedInboundTx{ + Creator: validatorAddr, + Sender: "0x954598965C2aCdA2885B037561526260764095B8", + SenderChainId: 1337, // ETH + Receiver: "0x954598965C2aCdA2885B037561526260764095B8", + ReceiverChain: 101, // zetachain + Amount: sdkmath.NewUintFromString("10000000"), + Message: "", + InBlockHeight: 1, + GasLimit: 1000000000, + InTxHash: "0x7a900ef978743f91f57ca47c6d1a1add75df4d3531da17671e9cf149e1aefe0b", + CoinType: 0, // zeta + TxOrigin: "0x954598965C2aCdA2885B037561526260764095B8", + Asset: "", + EventIndex: 1, + } + _, err := msgServer.VoteOnObservedInboundTx( + ctx, + msg, + ) + assert.NoError(t, err) + + // Check that the vote passed + ballot, found := zk.ObserverKeeper.GetBallot(ctx, msg.Digest()) + assert.True(t, found) + assert.Equal(t, ballot.BallotStatus, observerTypes.BallotStatus_BallotFinalized_SuccessObservation) + //Perform the SAME event. Except, this time, we resubmit the event. + msg2 := &types.MsgVoteOnObservedInboundTx{ + Creator: validatorAddr, + Sender: "0x954598965C2aCdA2885B037561526260764095B8", + SenderChainId: 1337, + Receiver: "0x954598965C2aCdA2885B037561526260764095B8", + ReceiverChain: 101, + Amount: sdkmath.NewUintFromString("10000000"), + Message: "", + InBlockHeight: 1, + GasLimit: 1000000001, // <---- Change here + InTxHash: "0x7a900ef978743f91f57ca47c6d1a1add75df4d3531da17671e9cf149e1aefe0b", + CoinType: 0, + TxOrigin: "0x954598965C2aCdA2885B037561526260764095B8", + Asset: "", + EventIndex: 1, + } + + _, err = msgServer.VoteOnObservedInboundTx( + ctx, + msg2, + ) + assert.ErrorIs(t, err, types.ErrObservedTxAlreadyFinalized) + _, found = zk.ObserverKeeper.GetBallot(ctx, msg2.Digest()) + assert.False(t, found) +} func TestStatus_StatusTransition(t *testing.T) { tt := []struct { Name string @@ -95,7 +183,6 @@ func TestStatus_StatusTransition(t *testing.T) { IsErr: false, }, } - _, _ = setupKeeper(t) for _, test := range tt { test := test t.Run(test.Name, func(t *testing.T) { diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx.go b/x/crosschain/keeper/msg_server_vote_outbound_tx.go index 274bbdc695..17319d1f8a 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx.go @@ -211,6 +211,7 @@ func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.Ms if err != nil { // do not commit tmpCtx cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()) + cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed ctx.Logger().Error(err.Error()) // #nosec G701 always in range k.GetObserverKeeper().RemoveFromPendingNonces(ctx, tss.TssPubkey, msg.OutTxChain, int64(msg.OutTxTssNonce)) @@ -221,6 +222,7 @@ func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.Ms commit() // Set the ballot index to the finalized ballot cctx.GetCurrentOutTxParam().OutboundTxBallotIndex = ballotIndex + cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed // #nosec G701 always in range k.GetObserverKeeper().RemoveFromPendingNonces(ctx, tss.TssPubkey, msg.OutTxChain, int64(msg.OutTxTssNonce)) k.RemoveOutTxTracker(ctx, msg.OutTxChain, msg.OutTxTssNonce) diff --git a/x/crosschain/types/cross_chain_tx.pb.go b/x/crosschain/types/cross_chain_tx.pb.go index fbcfff0e36..f74b500a81 100644 --- a/x/crosschain/types/cross_chain_tx.pb.go +++ b/x/crosschain/types/cross_chain_tx.pb.go @@ -63,6 +63,34 @@ func (CctxStatus) EnumDescriptor() ([]byte, []int) { return fileDescriptor_af3a0ad055343c21, []int{0} } +type TxFinalizationStatus int32 + +const ( + TxFinalizationStatus_NotFinalized TxFinalizationStatus = 0 + TxFinalizationStatus_Finalized TxFinalizationStatus = 1 + TxFinalizationStatus_Executed TxFinalizationStatus = 2 +) + +var TxFinalizationStatus_name = map[int32]string{ + 0: "NotFinalized", + 1: "Finalized", + 2: "Executed", +} + +var TxFinalizationStatus_value = map[string]int32{ + "NotFinalized": 0, + "Finalized": 1, + "Executed": 2, +} + +func (x TxFinalizationStatus) String() string { + return proto.EnumName(TxFinalizationStatus_name, int32(x)) +} + +func (TxFinalizationStatus) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_af3a0ad055343c21, []int{1} +} + type InboundTxParams struct { Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` SenderChainId int64 `protobuf:"varint,2,opt,name=sender_chain_id,json=senderChainId,proto3" json:"sender_chain_id,omitempty"` @@ -74,6 +102,7 @@ type InboundTxParams struct { InboundTxObservedExternalHeight uint64 `protobuf:"varint,8,opt,name=inbound_tx_observed_external_height,json=inboundTxObservedExternalHeight,proto3" json:"inbound_tx_observed_external_height,omitempty"` InboundTxBallotIndex string `protobuf:"bytes,9,opt,name=inbound_tx_ballot_index,json=inboundTxBallotIndex,proto3" json:"inbound_tx_ballot_index,omitempty"` InboundTxFinalizedZetaHeight uint64 `protobuf:"varint,10,opt,name=inbound_tx_finalized_zeta_height,json=inboundTxFinalizedZetaHeight,proto3" json:"inbound_tx_finalized_zeta_height,omitempty"` + TxFinalizationStatus TxFinalizationStatus `protobuf:"varint,11,opt,name=tx_finalization_status,json=txFinalizationStatus,proto3,enum=zetachain.zetacore.crosschain.TxFinalizationStatus" json:"tx_finalization_status,omitempty"` } func (m *InboundTxParams) Reset() { *m = InboundTxParams{} } @@ -172,6 +201,13 @@ func (m *InboundTxParams) GetInboundTxFinalizedZetaHeight() uint64 { return 0 } +func (m *InboundTxParams) GetTxFinalizationStatus() TxFinalizationStatus { + if m != nil { + return m.TxFinalizationStatus + } + return TxFinalizationStatus_NotFinalized +} + type ZetaAccounting struct { // aborted_zeta_amount stores the total aborted amount for cctx of coin-type ZETA AbortedZetaAmount github_com_cosmos_cosmos_sdk_types.Uint `protobuf:"bytes,1,opt,name=aborted_zeta_amount,json=abortedZetaAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint" json:"aborted_zeta_amount"` @@ -227,6 +263,7 @@ type OutboundTxParams struct { OutboundTxEffectiveGasPrice github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,21,opt,name=outbound_tx_effective_gas_price,json=outboundTxEffectiveGasPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"outbound_tx_effective_gas_price"` OutboundTxEffectiveGasLimit uint64 `protobuf:"varint,22,opt,name=outbound_tx_effective_gas_limit,json=outboundTxEffectiveGasLimit,proto3" json:"outbound_tx_effective_gas_limit,omitempty"` TssPubkey string `protobuf:"bytes,11,opt,name=tss_pubkey,json=tssPubkey,proto3" json:"tss_pubkey,omitempty"` + TxFinalizationStatus TxFinalizationStatus `protobuf:"varint,12,opt,name=tx_finalization_status,json=txFinalizationStatus,proto3,enum=zetachain.zetacore.crosschain.TxFinalizationStatus" json:"tx_finalization_status,omitempty"` } func (m *OutboundTxParams) Reset() { *m = OutboundTxParams{} } @@ -346,6 +383,13 @@ func (m *OutboundTxParams) GetTssPubkey() string { return "" } +func (m *OutboundTxParams) GetTxFinalizationStatus() TxFinalizationStatus { + if m != nil { + return m.TxFinalizationStatus + } + return TxFinalizationStatus_NotFinalized +} + type Status struct { Status CctxStatus `protobuf:"varint,1,opt,name=status,proto3,enum=zetachain.zetacore.crosschain.CctxStatus" json:"status,omitempty"` StatusMessage string `protobuf:"bytes,2,opt,name=status_message,json=statusMessage,proto3" json:"status_message,omitempty"` @@ -493,6 +537,7 @@ func (m *CrossChainTx) GetOutboundTxParams() []*OutboundTxParams { func init() { proto.RegisterEnum("zetachain.zetacore.crosschain.CctxStatus", CctxStatus_name, CctxStatus_value) + proto.RegisterEnum("zetachain.zetacore.crosschain.TxFinalizationStatus", TxFinalizationStatus_name, TxFinalizationStatus_value) proto.RegisterType((*InboundTxParams)(nil), "zetachain.zetacore.crosschain.InboundTxParams") proto.RegisterType((*ZetaAccounting)(nil), "zetachain.zetacore.crosschain.ZetaAccounting") proto.RegisterType((*OutboundTxParams)(nil), "zetachain.zetacore.crosschain.OutboundTxParams") @@ -503,72 +548,76 @@ func init() { func init() { proto.RegisterFile("crosschain/cross_chain_tx.proto", fileDescriptor_af3a0ad055343c21) } var fileDescriptor_af3a0ad055343c21 = []byte{ - // 1037 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0xcf, 0x6e, 0x1b, 0xb7, - 0x13, 0xf6, 0xfe, 0x24, 0xcb, 0xd2, 0x28, 0x96, 0xd6, 0xb4, 0x9c, 0xdf, 0xc2, 0x69, 0x24, 0x41, - 0x6d, 0x12, 0xa5, 0x80, 0x25, 0xd8, 0x45, 0x11, 0xa0, 0x37, 0xdb, 0x8d, 0x13, 0xa3, 0x49, 0x6c, - 0x6c, 0xed, 0x8b, 0x81, 0x62, 0x4b, 0xed, 0x8e, 0x25, 0x22, 0xd2, 0x52, 0x5d, 0x52, 0x86, 0x1c, - 0xf4, 0xd4, 0x27, 0xe8, 0x43, 0xb4, 0x40, 0xfb, 0x26, 0x39, 0xf4, 0x90, 0x63, 0xd1, 0x83, 0x51, - 0xd8, 0x6f, 0xd0, 0x27, 0x28, 0x48, 0xee, 0x4a, 0x2b, 0xd5, 0x8e, 0xfb, 0xe7, 0xb4, 0xc3, 0x21, - 0xbf, 0x8f, 0x33, 0xc3, 0x6f, 0xc8, 0x85, 0x9a, 0x1f, 0x71, 0x21, 0xfc, 0x1e, 0x65, 0x61, 0x5b, - 0x9b, 0x9e, 0xb6, 0x3d, 0x39, 0x6e, 0x0d, 0x23, 0x2e, 0x39, 0xb9, 0xff, 0x06, 0x25, 0xd5, 0xbe, - 0x96, 0xb6, 0x78, 0x84, 0xad, 0x29, 0x66, 0x7d, 0xd5, 0xe7, 0x83, 0x01, 0x0f, 0xdb, 0xe6, 0x63, - 0x30, 0xeb, 0x95, 0x2e, 0xef, 0x72, 0x6d, 0xb6, 0x95, 0x65, 0xbc, 0x8d, 0xef, 0xb2, 0x50, 0xde, - 0x0f, 0x3b, 0x7c, 0x14, 0x06, 0x47, 0xe3, 0x43, 0x1a, 0xd1, 0x81, 0x20, 0x77, 0x21, 0x27, 0x30, - 0x0c, 0x30, 0x72, 0xac, 0xba, 0xd5, 0x2c, 0xb8, 0xf1, 0x88, 0x3c, 0x84, 0xb2, 0xb1, 0xe2, 0x70, - 0x58, 0xe0, 0xfc, 0xaf, 0x6e, 0x35, 0x33, 0xee, 0xb2, 0x71, 0xef, 0x2a, 0xef, 0x7e, 0x40, 0xee, - 0x41, 0x41, 0x8e, 0x3d, 0x1e, 0xb1, 0x2e, 0x0b, 0x9d, 0x8c, 0xa6, 0xc8, 0xcb, 0xf1, 0x81, 0x1e, - 0x93, 0x0d, 0x28, 0xf8, 0x5c, 0xe5, 0x72, 0x3e, 0x44, 0x27, 0x5b, 0xb7, 0x9a, 0xa5, 0x2d, 0xbb, - 0x15, 0x07, 0xba, 0xcb, 0x59, 0x78, 0x74, 0x3e, 0x44, 0x37, 0xef, 0xc7, 0x16, 0xa9, 0xc0, 0x22, - 0x15, 0x02, 0xa5, 0xb3, 0xa8, 0x79, 0xcc, 0x80, 0x3c, 0x83, 0x1c, 0x1d, 0xf0, 0x51, 0x28, 0x9d, - 0x9c, 0x72, 0xef, 0xb4, 0xdf, 0x5e, 0xd4, 0x16, 0x7e, 0xbb, 0xa8, 0x3d, 0xea, 0x32, 0xd9, 0x1b, - 0x75, 0x14, 0x5f, 0xdb, 0xe7, 0x62, 0xc0, 0x45, 0xfc, 0xd9, 0x10, 0xc1, 0xeb, 0xb6, 0xda, 0x52, - 0xb4, 0x8e, 0x59, 0x28, 0xdd, 0x18, 0x4e, 0x9e, 0x80, 0xc3, 0x4c, 0xf6, 0x9e, 0x0a, 0xb9, 0x23, - 0x30, 0x3a, 0xc3, 0xc0, 0xeb, 0x51, 0xd1, 0x73, 0x96, 0xf4, 0x8e, 0x6b, 0x2c, 0xa9, 0xce, 0x41, - 0x3c, 0xfb, 0x9c, 0x8a, 0x1e, 0x79, 0x01, 0x1f, 0x5e, 0x07, 0xc4, 0xb1, 0xc4, 0x28, 0xa4, 0x7d, - 0xaf, 0x87, 0xac, 0xdb, 0x93, 0x4e, 0xbe, 0x6e, 0x35, 0xb3, 0x6e, 0xed, 0x2f, 0x1c, 0x4f, 0xe3, - 0x75, 0xcf, 0xf5, 0x32, 0xf2, 0x29, 0xfc, 0x3f, 0xc5, 0xd6, 0xa1, 0xfd, 0x3e, 0x97, 0x1e, 0x0b, - 0x03, 0x1c, 0x3b, 0x05, 0x1d, 0x45, 0x65, 0xc2, 0xb0, 0xa3, 0x27, 0xf7, 0xd5, 0x1c, 0xd9, 0x83, - 0x7a, 0x0a, 0x76, 0xca, 0x42, 0xda, 0x67, 0x6f, 0x30, 0xf0, 0x94, 0x26, 0x92, 0x08, 0x40, 0x47, - 0xf0, 0xc1, 0x04, 0xbf, 0x97, 0xac, 0x3a, 0x41, 0x49, 0xcd, 0xf6, 0x8d, 0x6f, 0xa0, 0xa4, 0x46, - 0xdb, 0xbe, 0xaf, 0x8a, 0xc2, 0xc2, 0x2e, 0xf1, 0x60, 0x95, 0x76, 0x78, 0x24, 0x13, 0xb2, 0xb8, - 0xda, 0xd6, 0xbf, 0xab, 0xf6, 0x4a, 0xcc, 0xa5, 0x37, 0xd1, 0x4c, 0x8d, 0x9f, 0x73, 0x60, 0x1f, - 0x8c, 0xe4, 0xac, 0xf0, 0xd6, 0x21, 0x1f, 0xa1, 0x8f, 0xec, 0x6c, 0x22, 0xbd, 0xc9, 0x98, 0x3c, - 0x06, 0x3b, 0xb1, 0x8d, 0xfc, 0xf6, 0x13, 0xf5, 0x95, 0x13, 0x7f, 0xa2, 0xbf, 0x19, 0x89, 0x65, - 0x6e, 0x95, 0xd8, 0x54, 0x4c, 0xd9, 0xff, 0x26, 0xa6, 0x4d, 0x58, 0xe3, 0x71, 0x4a, 0xea, 0x3c, - 0xa4, 0x10, 0x5e, 0xc8, 0x43, 0x1f, 0xb5, 0x76, 0xb3, 0x2e, 0xe1, 0x93, 0x7c, 0x8f, 0x84, 0x78, - 0xa5, 0x66, 0xe6, 0x21, 0x5d, 0x2a, 0xbc, 0x3e, 0x1b, 0x30, 0xa3, 0xeb, 0x19, 0xc8, 0x33, 0x2a, - 0x5e, 0xa8, 0x99, 0xeb, 0x20, 0xc3, 0x88, 0xf9, 0x18, 0xeb, 0x75, 0x16, 0x72, 0xa8, 0x66, 0x48, - 0x13, 0xec, 0x34, 0x44, 0xab, 0x3b, 0xaf, 0x57, 0x97, 0xa6, 0xab, 0xb5, 0xac, 0x9f, 0x80, 0x93, - 0x5e, 0x79, 0x8d, 0x12, 0xd7, 0xa6, 0x88, 0xb4, 0x14, 0x5f, 0xc1, 0x47, 0x69, 0xe0, 0x8d, 0x0d, - 0x61, 0xe4, 0x58, 0x9f, 0x92, 0xdc, 0xd0, 0x11, 0x6d, 0xa8, 0xcc, 0x67, 0x39, 0x12, 0x18, 0x38, - 0x15, 0x8d, 0x5f, 0x99, 0x49, 0xf2, 0x58, 0x60, 0x40, 0x24, 0xd4, 0xd2, 0x00, 0x3c, 0x3d, 0x45, - 0x5f, 0xb2, 0x33, 0x4c, 0x15, 0x68, 0x4d, 0x1f, 0x6f, 0x2b, 0x3e, 0xde, 0x87, 0x7f, 0xe3, 0x78, - 0xf7, 0x43, 0xe9, 0xde, 0x9b, 0xee, 0xf5, 0x34, 0x21, 0x9d, 0x54, 0xf6, 0xf3, 0xf7, 0xed, 0x6a, - 0x4e, 0xf2, 0xae, 0x8e, 0xf8, 0x06, 0x16, 0x73, 0xa4, 0xf7, 0x01, 0x94, 0x58, 0x86, 0xa3, 0xce, - 0x6b, 0x3c, 0x77, 0x8a, 0xba, 0xce, 0x05, 0x29, 0xc4, 0xa1, 0x76, 0x34, 0x7e, 0xb4, 0x20, 0xf7, - 0xa5, 0xa4, 0x72, 0x24, 0xc8, 0x36, 0xe4, 0x84, 0xb6, 0x74, 0x7f, 0x94, 0xb6, 0x1e, 0xb7, 0xde, - 0xfb, 0x12, 0xb4, 0x76, 0x7d, 0x39, 0x36, 0x50, 0x37, 0x06, 0x92, 0x07, 0x50, 0x32, 0x96, 0x37, - 0x40, 0x21, 0x68, 0x17, 0x75, 0x1b, 0x15, 0xdc, 0x65, 0xe3, 0x7d, 0x69, 0x9c, 0x64, 0x13, 0x2a, - 0x7d, 0x2a, 0xe4, 0xf1, 0x30, 0xa0, 0x12, 0x3d, 0xc9, 0x06, 0x28, 0x24, 0x1d, 0x0c, 0x75, 0x3f, - 0x65, 0xdc, 0xd5, 0xe9, 0xdc, 0x51, 0x32, 0xd5, 0xf8, 0x25, 0x03, 0x77, 0x76, 0xd5, 0xde, 0xba, - 0x11, 0x8f, 0xc6, 0xc4, 0x81, 0x25, 0x3f, 0x42, 0x2a, 0x79, 0xd2, 0xce, 0xc9, 0x50, 0x5d, 0xeb, - 0x46, 0x54, 0x66, 0x6f, 0x33, 0x20, 0x5f, 0x43, 0x41, 0xdf, 0x36, 0xa7, 0x88, 0xc2, 0x5c, 0xf8, - 0x3b, 0xbb, 0xff, 0xb0, 0x19, 0xff, 0xb8, 0xa8, 0xd9, 0xe7, 0x74, 0xd0, 0xff, 0xac, 0x31, 0x61, - 0x6a, 0xb8, 0x79, 0x65, 0xef, 0x21, 0x0a, 0xf2, 0x08, 0xca, 0x11, 0xf6, 0xe9, 0x39, 0x06, 0x93, - 0xec, 0x73, 0xa6, 0x11, 0x62, 0x77, 0x92, 0xfe, 0x1e, 0x14, 0x7d, 0x5f, 0x8e, 0xbd, 0xb8, 0xda, - 0xaa, 0x5b, 0x8a, 0x5b, 0x0f, 0x6e, 0xa9, 0x76, 0x5c, 0x69, 0xf0, 0x27, 0x55, 0x27, 0x27, 0xb0, - 0x92, 0xba, 0xa2, 0x87, 0xfa, 0x9e, 0xd3, 0x9d, 0x54, 0xdc, 0x6a, 0xdd, 0xc2, 0x36, 0xf7, 0x2c, - 0xbb, 0x65, 0x36, 0xf7, 0x4e, 0x7f, 0x05, 0x24, 0x2d, 0xbe, 0x98, 0x1c, 0xea, 0x99, 0x66, 0x71, - 0xab, 0x7d, 0x0b, 0xf9, 0xfc, 0xdd, 0xeb, 0xda, 0x7c, 0xce, 0xf3, 0xf1, 0xb7, 0x00, 0x53, 0xf9, - 0x10, 0x02, 0xa5, 0x43, 0x0c, 0x03, 0x16, 0x76, 0xe3, 0xb8, 0xec, 0x05, 0xb2, 0x0a, 0xe5, 0xd8, - 0x97, 0xd0, 0xd9, 0x16, 0x59, 0x81, 0xe5, 0x64, 0xf4, 0x92, 0x85, 0x18, 0xd8, 0x19, 0xe5, 0x8a, - 0xd7, 0xb9, 0x78, 0x86, 0x91, 0xb4, 0xb3, 0xe4, 0x0e, 0xe4, 0x8d, 0x8d, 0x81, 0xbd, 0x48, 0x8a, - 0xb0, 0xb4, 0x6d, 0x9e, 0x08, 0x3b, 0xb7, 0x9e, 0xfd, 0xe9, 0x87, 0xaa, 0xb5, 0xf3, 0xc5, 0xdb, - 0xcb, 0xaa, 0xf5, 0xee, 0xb2, 0x6a, 0xfd, 0x7e, 0x59, 0xb5, 0xbe, 0xbf, 0xaa, 0x2e, 0xbc, 0xbb, - 0xaa, 0x2e, 0xfc, 0x7a, 0x55, 0x5d, 0x38, 0xd9, 0x4c, 0x49, 0x41, 0xa5, 0xb6, 0x61, 0x7e, 0x94, - 0x92, 0x2c, 0xdb, 0xe3, 0x76, 0xea, 0xf7, 0x49, 0x2b, 0xa3, 0x93, 0xd3, 0x3f, 0x3b, 0x9f, 0xfc, - 0x19, 0x00, 0x00, 0xff, 0xff, 0xd6, 0x5f, 0xb2, 0x04, 0x59, 0x09, 0x00, 0x00, + // 1100 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcd, 0x6e, 0x1b, 0x37, + 0x10, 0xd6, 0x46, 0x8a, 0x2c, 0x8d, 0x6c, 0x6b, 0x4d, 0xcb, 0xe9, 0xc2, 0x69, 0x24, 0x41, 0x6d, + 0x12, 0x25, 0x80, 0x25, 0xd8, 0x41, 0x11, 0xa0, 0x37, 0xdb, 0xb5, 0x13, 0x23, 0x89, 0x6d, 0x6c, + 0xed, 0x8b, 0x81, 0x62, 0x4b, 0xed, 0xd2, 0x12, 0x11, 0x69, 0xa9, 0x2e, 0x29, 0x43, 0x0e, 0xfa, + 0x10, 0x3d, 0xf4, 0x11, 0x5a, 0xa0, 0x8f, 0x92, 0x43, 0x0f, 0x39, 0x16, 0x3d, 0x18, 0x85, 0x7d, + 0xee, 0xa5, 0x4f, 0x50, 0xf0, 0x67, 0x57, 0x6b, 0xd5, 0x3f, 0xfd, 0x3b, 0xed, 0x70, 0xc8, 0xef, + 0x1b, 0x72, 0xe6, 0x1b, 0x2e, 0xa1, 0xe6, 0x47, 0x8c, 0x73, 0xbf, 0x87, 0x69, 0xd8, 0x56, 0xa6, + 0xa7, 0x6c, 0x4f, 0x8c, 0x5b, 0xc3, 0x88, 0x09, 0x86, 0x1e, 0xbc, 0x23, 0x02, 0x2b, 0x5f, 0x4b, + 0x59, 0x2c, 0x22, 0xad, 0x09, 0x66, 0x79, 0xd1, 0x67, 0x83, 0x01, 0x0b, 0xdb, 0xfa, 0xa3, 0x31, + 0xcb, 0x95, 0x2e, 0xeb, 0x32, 0x65, 0xb6, 0xa5, 0xa5, 0xbd, 0x8d, 0xdf, 0x73, 0x50, 0xde, 0x09, + 0x3b, 0x6c, 0x14, 0x06, 0x07, 0xe3, 0x7d, 0x1c, 0xe1, 0x01, 0x47, 0xf7, 0x20, 0xcf, 0x49, 0x18, + 0x90, 0xc8, 0xb1, 0xea, 0x56, 0xb3, 0xe8, 0x9a, 0x11, 0x7a, 0x04, 0x65, 0x6d, 0x99, 0xed, 0xd0, + 0xc0, 0xb9, 0x53, 0xb7, 0x9a, 0x59, 0x77, 0x4e, 0xbb, 0x37, 0xa5, 0x77, 0x27, 0x40, 0xf7, 0xa1, + 0x28, 0xc6, 0x1e, 0x8b, 0x68, 0x97, 0x86, 0x4e, 0x56, 0x51, 0x14, 0xc4, 0x78, 0x4f, 0x8d, 0xd1, + 0x0a, 0x14, 0x7d, 0x26, 0xcf, 0x72, 0x3a, 0x24, 0x4e, 0xae, 0x6e, 0x35, 0xe7, 0xd7, 0xec, 0x96, + 0xd9, 0xe8, 0x26, 0xa3, 0xe1, 0xc1, 0xe9, 0x90, 0xb8, 0x05, 0xdf, 0x58, 0xa8, 0x02, 0x77, 0x31, + 0xe7, 0x44, 0x38, 0x77, 0x15, 0x8f, 0x1e, 0xa0, 0x17, 0x90, 0xc7, 0x03, 0x36, 0x0a, 0x85, 0x93, + 0x97, 0xee, 0x8d, 0xf6, 0xfb, 0xb3, 0x5a, 0xe6, 0xd7, 0xb3, 0xda, 0xe3, 0x2e, 0x15, 0xbd, 0x51, + 0x47, 0xf2, 0xb5, 0x7d, 0xc6, 0x07, 0x8c, 0x9b, 0xcf, 0x0a, 0x0f, 0xde, 0xb6, 0x65, 0x48, 0xde, + 0x3a, 0xa4, 0xa1, 0x70, 0x0d, 0x1c, 0x3d, 0x07, 0x87, 0xea, 0xd3, 0x7b, 0x72, 0xcb, 0x1d, 0x4e, + 0xa2, 0x13, 0x12, 0x78, 0x3d, 0xcc, 0x7b, 0xce, 0x8c, 0x8a, 0xb8, 0x44, 0xe3, 0xec, 0xec, 0x99, + 0xd9, 0x97, 0x98, 0xf7, 0xd0, 0x6b, 0xf8, 0xe4, 0x2a, 0x20, 0x19, 0x0b, 0x12, 0x85, 0xb8, 0xef, + 0xf5, 0x08, 0xed, 0xf6, 0x84, 0x53, 0xa8, 0x5b, 0xcd, 0x9c, 0x5b, 0xfb, 0x0b, 0xc7, 0x96, 0x59, + 0xf7, 0x52, 0x2d, 0x43, 0x9f, 0xc1, 0x47, 0x29, 0xb6, 0x0e, 0xee, 0xf7, 0x99, 0xf0, 0x68, 0x18, + 0x90, 0xb1, 0x53, 0x54, 0xbb, 0xa8, 0x24, 0x0c, 0x1b, 0x6a, 0x72, 0x47, 0xce, 0xa1, 0x6d, 0xa8, + 0xa7, 0x60, 0xc7, 0x34, 0xc4, 0x7d, 0xfa, 0x8e, 0x04, 0x9e, 0xd4, 0x44, 0xbc, 0x03, 0x50, 0x3b, + 0xf8, 0x38, 0xc1, 0x6f, 0xc7, 0xab, 0x8e, 0x88, 0xc0, 0x26, 0x3c, 0x85, 0x7b, 0x13, 0x3c, 0x16, + 0x94, 0x85, 0x1e, 0x17, 0x58, 0x8c, 0xb8, 0x53, 0x52, 0x05, 0x7a, 0xd6, 0xba, 0x51, 0x6f, 0xad, + 0x84, 0x55, 0x61, 0xbf, 0x54, 0x50, 0xb7, 0x22, 0xae, 0xf0, 0x36, 0xbe, 0x81, 0x79, 0x19, 0x78, + 0xdd, 0xf7, 0x65, 0xfe, 0x69, 0xd8, 0x45, 0x1e, 0x2c, 0xe2, 0x0e, 0x8b, 0x44, 0xbc, 0x6f, 0x53, + 0x58, 0xeb, 0xdf, 0x15, 0x76, 0xc1, 0x70, 0xa9, 0x20, 0x8a, 0xa9, 0xf1, 0xfd, 0x0c, 0xd8, 0x7b, + 0x23, 0x71, 0x59, 0xe3, 0xcb, 0x50, 0x88, 0x88, 0x4f, 0xe8, 0x49, 0xa2, 0xf2, 0x64, 0x8c, 0x9e, + 0x80, 0x1d, 0xdb, 0x5a, 0xe9, 0x3b, 0xb1, 0xd0, 0xcb, 0xb1, 0x3f, 0x96, 0xfa, 0x25, 0x35, 0x67, + 0x6f, 0x55, 0xf3, 0x44, 0xb7, 0xb9, 0xff, 0xa6, 0xdb, 0x55, 0x58, 0x62, 0xe6, 0x48, 0xb2, 0xf4, + 0x82, 0x73, 0x2f, 0x64, 0xa1, 0x4f, 0x54, 0x9b, 0xe4, 0x5c, 0xc4, 0x92, 0xf3, 0x1e, 0x70, 0xbe, + 0x2b, 0x67, 0xa6, 0x21, 0x5d, 0xcc, 0xbd, 0x3e, 0x1d, 0x50, 0xdd, 0x42, 0x97, 0x20, 0x2f, 0x30, + 0x7f, 0x2d, 0x67, 0xae, 0x82, 0x0c, 0x23, 0xea, 0x13, 0xd3, 0x1a, 0x97, 0x21, 0xfb, 0x72, 0x06, + 0x35, 0xc1, 0x4e, 0x43, 0x54, 0x23, 0x15, 0xd4, 0xea, 0xf9, 0xc9, 0x6a, 0xd5, 0x41, 0xcf, 0xc1, + 0x49, 0xaf, 0xbc, 0x42, 0xf4, 0x4b, 0x13, 0x44, 0x5a, 0xf5, 0xbb, 0xf0, 0x69, 0x1a, 0x78, 0x6d, + 0xef, 0x69, 0xe5, 0xd7, 0x27, 0x24, 0xd7, 0x34, 0x5f, 0x1b, 0x2a, 0xd3, 0xa7, 0x1c, 0x71, 0x12, + 0x38, 0x15, 0x85, 0x5f, 0xb8, 0x74, 0xc8, 0x43, 0x4e, 0x02, 0x24, 0xa0, 0x96, 0x06, 0x90, 0xe3, + 0x63, 0xe2, 0x0b, 0x7a, 0x42, 0x52, 0x09, 0x5a, 0x52, 0xe5, 0x6d, 0x99, 0xf2, 0x3e, 0xfa, 0x1b, + 0xe5, 0xdd, 0x09, 0x85, 0x7b, 0x7f, 0x12, 0x6b, 0x2b, 0x26, 0x4d, 0x32, 0xfb, 0xc5, 0x4d, 0x51, + 0x75, 0x25, 0xef, 0xa9, 0x1d, 0x5f, 0xc3, 0xa2, 0x4b, 0xfa, 0x00, 0x40, 0x8a, 0x65, 0x38, 0xea, + 0xbc, 0x25, 0xa7, 0xaa, 0xbd, 0x8b, 0x6e, 0x51, 0x70, 0xbe, 0xaf, 0x1c, 0x37, 0xdc, 0x04, 0xb3, + 0xff, 0xf7, 0x4d, 0xf0, 0xa3, 0x05, 0x79, 0x6d, 0xa2, 0x75, 0xc8, 0x9b, 0x28, 0x96, 0x8a, 0xf2, + 0xe4, 0x96, 0x28, 0x9b, 0xbe, 0x18, 0x1b, 0x6e, 0x03, 0x44, 0x0f, 0x61, 0x5e, 0x5b, 0xde, 0x80, + 0x70, 0x8e, 0xbb, 0x44, 0x75, 0x6c, 0xd1, 0x9d, 0xd3, 0xde, 0x37, 0xda, 0x89, 0x56, 0xa1, 0xd2, + 0xc7, 0x5c, 0x1c, 0x0e, 0x03, 0x2c, 0x88, 0x27, 0xe8, 0x80, 0x70, 0x81, 0x07, 0x43, 0xd5, 0xba, + 0x59, 0x77, 0x71, 0x32, 0x77, 0x10, 0x4f, 0x35, 0x7e, 0xce, 0xc2, 0xec, 0xa6, 0x8c, 0xad, 0x7a, + 0xfe, 0x60, 0x8c, 0x1c, 0x98, 0xf1, 0x23, 0x82, 0x05, 0x8b, 0x6f, 0x8e, 0x78, 0x28, 0x7f, 0x56, + 0x5a, 0xbf, 0x3a, 0xb6, 0x1e, 0xa0, 0xaf, 0xa1, 0xa8, 0x2e, 0xb6, 0x63, 0x42, 0xb8, 0xfe, 0x8d, + 0x6d, 0x6c, 0xfe, 0xc3, 0xbe, 0xff, 0xe3, 0xac, 0x66, 0x9f, 0xe2, 0x41, 0xff, 0xf3, 0x46, 0xc2, + 0xd4, 0x70, 0x0b, 0xd2, 0xde, 0x26, 0x84, 0xa3, 0xc7, 0x50, 0x8e, 0x48, 0x1f, 0x9f, 0x92, 0x20, + 0x39, 0x7d, 0x5e, 0xf7, 0x9c, 0x71, 0xc7, 0xc7, 0xdf, 0x86, 0x92, 0xef, 0x8b, 0x71, 0x5c, 0x53, + 0xd9, 0x98, 0xa5, 0xb5, 0x87, 0xb7, 0x64, 0xdb, 0x64, 0x1a, 0xfc, 0x24, 0xeb, 0xe8, 0x08, 0x16, + 0x52, 0x3f, 0x9e, 0xa1, 0xba, 0x52, 0x55, 0xd3, 0x96, 0xd6, 0x5a, 0xb7, 0xb0, 0x4d, 0x3d, 0x36, + 0xdc, 0x32, 0x9d, 0x7a, 0x7d, 0x7c, 0x05, 0x28, 0xad, 0x73, 0x43, 0x0e, 0xf5, 0x6c, 0xb3, 0xb4, + 0xd6, 0xbe, 0x85, 0x7c, 0xfa, 0x9a, 0x77, 0x6d, 0x36, 0xe5, 0x79, 0xfa, 0x2d, 0xc0, 0x44, 0x3e, + 0x08, 0xc1, 0xfc, 0x3e, 0x09, 0x03, 0x1a, 0x76, 0xcd, 0xbe, 0xec, 0x0c, 0x5a, 0x84, 0xb2, 0xf1, + 0xc5, 0x74, 0xb6, 0x85, 0x16, 0x60, 0x2e, 0x1e, 0xbd, 0xa1, 0x21, 0x09, 0xec, 0xac, 0x74, 0x99, + 0x75, 0x2e, 0x39, 0x21, 0x91, 0xb0, 0x73, 0x68, 0x16, 0x0a, 0xda, 0x26, 0x81, 0x7d, 0x17, 0x95, + 0x60, 0x66, 0x5d, 0xff, 0x8d, 0xec, 0xfc, 0x72, 0xee, 0xa7, 0x1f, 0xaa, 0xd6, 0xd3, 0x57, 0x50, + 0xb9, 0xaa, 0x45, 0x90, 0x0d, 0xb3, 0xbb, 0x4c, 0x24, 0xff, 0x66, 0x3b, 0x83, 0xe6, 0xa0, 0x38, + 0x19, 0x5a, 0x92, 0x79, 0x6b, 0x4c, 0xfc, 0x91, 0x24, 0xbb, 0xa3, 0xc9, 0x36, 0x5e, 0xbd, 0x3f, + 0xaf, 0x5a, 0x1f, 0xce, 0xab, 0xd6, 0x6f, 0xe7, 0x55, 0xeb, 0xbb, 0x8b, 0x6a, 0xe6, 0xc3, 0x45, + 0x35, 0xf3, 0xcb, 0x45, 0x35, 0x73, 0xb4, 0x9a, 0xd2, 0x95, 0xcc, 0xd3, 0x8a, 0x7e, 0x4b, 0xc6, + 0x29, 0x6b, 0x8f, 0xdb, 0xa9, 0x17, 0xa6, 0x92, 0x59, 0x27, 0xaf, 0xde, 0x83, 0xcf, 0xfe, 0x0c, + 0x00, 0x00, 0xff, 0xff, 0xd3, 0x52, 0xba, 0xe1, 0x7c, 0x0a, 0x00, 0x00, } func (m *InboundTxParams) Marshal() (dAtA []byte, err error) { @@ -591,6 +640,11 @@ func (m *InboundTxParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.TxFinalizationStatus != 0 { + i = encodeVarintCrossChainTx(dAtA, i, uint64(m.TxFinalizationStatus)) + i-- + dAtA[i] = 0x58 + } if m.InboundTxFinalizedZetaHeight != 0 { i = encodeVarintCrossChainTx(dAtA, i, uint64(m.InboundTxFinalizedZetaHeight)) i-- @@ -738,6 +792,11 @@ func (m *OutboundTxParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0xa0 } + if m.TxFinalizationStatus != 0 { + i = encodeVarintCrossChainTx(dAtA, i, uint64(m.TxFinalizationStatus)) + i-- + dAtA[i] = 0x60 + } if len(m.TssPubkey) > 0 { i -= len(m.TssPubkey) copy(dAtA[i:], m.TssPubkey) @@ -994,6 +1053,9 @@ func (m *InboundTxParams) Size() (n int) { if m.InboundTxFinalizedZetaHeight != 0 { n += 1 + sovCrossChainTx(uint64(m.InboundTxFinalizedZetaHeight)) } + if m.TxFinalizationStatus != 0 { + n += 1 + sovCrossChainTx(uint64(m.TxFinalizationStatus)) + } return n } @@ -1051,6 +1113,9 @@ func (m *OutboundTxParams) Size() (n int) { if l > 0 { n += 1 + l + sovCrossChainTx(uint64(l)) } + if m.TxFinalizationStatus != 0 { + n += 1 + sovCrossChainTx(uint64(m.TxFinalizationStatus)) + } if m.OutboundTxGasUsed != 0 { n += 2 + sovCrossChainTx(uint64(m.OutboundTxGasUsed)) } @@ -1423,6 +1488,25 @@ func (m *InboundTxParams) Unmarshal(dAtA []byte) error { break } } + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TxFinalizationStatus", wireType) + } + m.TxFinalizationStatus = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TxFinalizationStatus |= TxFinalizationStatus(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipCrossChainTx(dAtA[iNdEx:]) @@ -1846,6 +1930,25 @@ func (m *OutboundTxParams) Unmarshal(dAtA []byte) error { } m.TssPubkey = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 12: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TxFinalizationStatus", wireType) + } + m.TxFinalizationStatus = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCrossChainTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TxFinalizationStatus |= TxFinalizationStatus(b&0x7F) << shift + if b < 0x80 { + break + } + } case 20: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field OutboundTxGasUsed", wireType) diff --git a/x/crosschain/types/errors.go b/x/crosschain/types/errors.go index 42274e4698..8dc589e878 100644 --- a/x/crosschain/types/errors.go +++ b/x/crosschain/types/errors.go @@ -34,12 +34,13 @@ var ( ErrCannotFindCctx = errorsmod.Register(ModuleName, 1134, "cannot find cctx") ErrStatusNotPending = errorsmod.Register(ModuleName, 1135, "Status not pending") - ErrCannotFindGasParams = errorsmod.Register(ModuleName, 1136, "cannot find gas params") - ErrInvalidGasAmount = errorsmod.Register(ModuleName, 1137, "invalid gas amount") - ErrNoLiquidityPool = errorsmod.Register(ModuleName, 1138, "no liquidity pool") - ErrInvalidCoinType = errorsmod.Register(ModuleName, 1139, "invalid coin type") - ErrCannotMigrateTssFunds = errorsmod.Register(ModuleName, 1140, "cannot migrate TSS funds") - ErrTxBodyVerificationFail = errorsmod.Register(ModuleName, 1141, "transaction body verification fail") - ErrReceiverIsEmpty = errorsmod.Register(ModuleName, 1142, "receiver is empty") - ErrUnsupportedStatus = errorsmod.Register(ModuleName, 1143, "unsupported status") + ErrCannotFindGasParams = errorsmod.Register(ModuleName, 1136, "cannot find gas params") + ErrInvalidGasAmount = errorsmod.Register(ModuleName, 1137, "invalid gas amount") + ErrNoLiquidityPool = errorsmod.Register(ModuleName, 1138, "no liquidity pool") + ErrInvalidCoinType = errorsmod.Register(ModuleName, 1139, "invalid coin type") + ErrCannotMigrateTssFunds = errorsmod.Register(ModuleName, 1140, "cannot migrate TSS funds") + ErrTxBodyVerificationFail = errorsmod.Register(ModuleName, 1141, "transaction body verification fail") + ErrReceiverIsEmpty = errorsmod.Register(ModuleName, 1142, "receiver is empty") + ErrUnsupportedStatus = errorsmod.Register(ModuleName, 1143, "unsupported status") + ErrObservedTxAlreadyFinalized = errorsmod.Register(ModuleName, 1144, "observed tx already finalized") ) diff --git a/x/crosschain/types/genesis.pb.go b/x/crosschain/types/genesis.pb.go index 250dc7128d..43a21227fb 100644 --- a/x/crosschain/types/genesis.pb.go +++ b/x/crosschain/types/genesis.pb.go @@ -34,6 +34,7 @@ type GenesisState struct { InTxHashToCctxList []InTxHashToCctx `protobuf:"bytes,9,rep,name=inTxHashToCctxList,proto3" json:"inTxHashToCctxList"` InTxTrackerList []InTxTracker `protobuf:"bytes,11,rep,name=in_tx_tracker_list,json=inTxTrackerList,proto3" json:"in_tx_tracker_list"` ZetaAccounting ZetaAccounting `protobuf:"bytes,12,opt,name=zeta_accounting,json=zetaAccounting,proto3" json:"zeta_accounting"` + FinalizedInbounds []string `protobuf:"bytes,16,rep,name=FinalizedInbounds,proto3" json:"FinalizedInbounds,omitempty"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -125,6 +126,13 @@ func (m *GenesisState) GetZetaAccounting() ZetaAccounting { return ZetaAccounting{} } +func (m *GenesisState) GetFinalizedInbounds() []string { + if m != nil { + return m.FinalizedInbounds + } + return nil +} + func init() { proto.RegisterType((*GenesisState)(nil), "zetachain.zetacore.crosschain.GenesisState") } @@ -132,37 +140,39 @@ func init() { func init() { proto.RegisterFile("crosschain/genesis.proto", fileDescriptor_dd51403692d571f4) } var fileDescriptor_dd51403692d571f4 = []byte{ - // 468 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0x51, 0x6b, 0x14, 0x31, - 0x10, 0xc7, 0x6f, 0xd5, 0x56, 0xcd, 0x9d, 0x56, 0xa2, 0xe0, 0x72, 0xe0, 0xb6, 0x54, 0xc4, 0xa2, - 0x74, 0x17, 0xeb, 0x27, 0xb0, 0xf7, 0xd0, 0x4a, 0x0b, 0xd6, 0xf3, 0x9e, 0x8a, 0x25, 0xe6, 0x42, - 0xd8, 0x0d, 0xbd, 0x6e, 0x96, 0xcd, 0x2c, 0xac, 0xfd, 0x14, 0x7e, 0xac, 0x3e, 0xf6, 0x49, 0x7c, - 0x12, 0xb9, 0xfb, 0x22, 0x92, 0xd9, 0x58, 0xb3, 0x5c, 0xe9, 0xf6, 0x6d, 0xc8, 0xcc, 0xff, 0xf7, - 0x9f, 0xcc, 0x24, 0x24, 0x14, 0xa5, 0x36, 0x46, 0x64, 0x5c, 0xe5, 0x49, 0x2a, 0x73, 0x69, 0x94, - 0x89, 0x8b, 0x52, 0x83, 0xa6, 0x2f, 0xce, 0x25, 0x70, 0x4c, 0xc4, 0x18, 0xe9, 0x52, 0xc6, 0xff, - 0x8b, 0x87, 0xeb, 0x9e, 0x10, 0x43, 0x86, 0x31, 0x83, 0xba, 0xd1, 0x0f, 0x87, 0x3e, 0x99, 0x1b, - 0x56, 0x94, 0x4a, 0x48, 0x97, 0x7b, 0xe9, 0xe5, 0x50, 0xc3, 0x32, 0x6e, 0x32, 0x06, 0x9a, 0x09, - 0x71, 0x05, 0x88, 0x96, 0x8a, 0xa0, 0xe4, 0xe2, 0x54, 0x96, 0x2e, 0xbf, 0xe9, 0xe5, 0x67, 0xdc, - 0x00, 0x9b, 0xce, 0xb4, 0x38, 0x65, 0x99, 0x54, 0x69, 0x06, 0xae, 0xc6, 0xef, 0x52, 0x57, 0xb0, - 0x0c, 0x79, 0xee, 0x15, 0x14, 0xbc, 0xe4, 0x67, 0xee, 0xfa, 0xc3, 0x67, 0xa9, 0x4e, 0x35, 0x86, - 0x89, 0x8d, 0x9a, 0xd3, 0xcd, 0x9f, 0x2b, 0x64, 0xb0, 0xd7, 0x8c, 0xe9, 0x0b, 0x70, 0x90, 0x74, - 0x44, 0x56, 0x1b, 0x59, 0x18, 0x6c, 0x04, 0x5b, 0xfd, 0x9d, 0x57, 0xf1, 0x8d, 0x63, 0x8b, 0x8f, - 0xb0, 0x78, 0xf7, 0xde, 0xc5, 0xef, 0xf5, 0xde, 0xd8, 0x49, 0xe9, 0x09, 0x79, 0xa2, 0x2b, 0x98, - 0xd4, 0x93, 0xa6, 0xb5, 0x43, 0x65, 0x20, 0xbc, 0xb3, 0x71, 0x77, 0xab, 0xbf, 0xf3, 0xb6, 0x03, - 0xf7, 0xc9, 0x93, 0x39, 0xe8, 0x12, 0x8a, 0x1e, 0x90, 0x41, 0xca, 0xcd, 0x91, 0x9d, 0x3f, 0xa2, - 0x57, 0x10, 0xfd, 0xba, 0x03, 0xbd, 0xe7, 0x24, 0xe3, 0x96, 0x98, 0x7e, 0x26, 0x8f, 0x46, 0xb6, - 0x68, 0x64, 0x8b, 0x26, 0xb5, 0x09, 0xef, 0xdf, 0xaa, 0x51, 0x5f, 0x33, 0x6e, 0x13, 0xe8, 0x37, - 0xf2, 0xd4, 0xee, 0x6f, 0xd7, 0xae, 0x6f, 0x1f, 0xb7, 0x87, 0x6d, 0x3e, 0x40, 0x70, 0xdc, 0x01, - 0x3e, 0x6c, 0x2b, 0xc7, 0xd7, 0xa1, 0xa8, 0x20, 0xd4, 0x5a, 0xed, 0x73, 0x93, 0x4d, 0xf4, 0x48, - 0x40, 0x8d, 0x06, 0x0f, 0xd1, 0x60, 0xbb, 0xc3, 0xe0, 0x63, 0x4b, 0xe8, 0x86, 0x7c, 0x0d, 0x8e, - 0x9e, 0x58, 0x13, 0xef, 0x85, 0xb1, 0x99, 0x35, 0xe9, 0xa3, 0xc9, 0x9b, 0x5b, 0x98, 0xb4, 0xd7, - 0xb8, 0xa6, 0xf2, 0xf6, 0x16, 0xbf, 0x92, 0x35, 0xab, 0x64, 0x5c, 0x08, 0x5d, 0xe5, 0xa0, 0xf2, - 0x34, 0x1c, 0xe0, 0x93, 0xeb, 0xba, 0xc0, 0xb1, 0x04, 0xfe, 0xe1, 0x4a, 0xe4, 0xf0, 0x8f, 0xcf, - 0xdb, 0xa7, 0x07, 0x17, 0xf3, 0x28, 0xb8, 0x9c, 0x47, 0xc1, 0x9f, 0x79, 0x14, 0xfc, 0x58, 0x44, - 0xbd, 0xcb, 0x45, 0xd4, 0xfb, 0xb5, 0x88, 0x7a, 0xc7, 0xef, 0x52, 0x05, 0x59, 0x35, 0x8d, 0x85, - 0x3e, 0x4b, 0xac, 0x68, 0xbb, 0xf9, 0x2c, 0xff, 0x9c, 0x92, 0x3a, 0xf1, 0xbe, 0x10, 0x7c, 0x2f, - 0xa4, 0x99, 0xae, 0xe2, 0x67, 0x79, 0xff, 0x37, 0x00, 0x00, 0xff, 0xff, 0x06, 0xe1, 0xb6, 0x7c, - 0x5d, 0x04, 0x00, 0x00, + // 498 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0xd1, 0x6e, 0xd3, 0x3c, + 0x14, 0xc7, 0x9b, 0x6f, 0x1f, 0x85, 0xb9, 0x85, 0x0d, 0x83, 0x44, 0x54, 0x89, 0xac, 0x1a, 0x42, + 0x54, 0xc0, 0x12, 0x31, 0x9e, 0x80, 0x56, 0x62, 0x9b, 0x36, 0x89, 0x11, 0x7a, 0x35, 0x31, 0x19, + 0xd7, 0xb3, 0x12, 0x6b, 0x5d, 0x5c, 0xc5, 0x8e, 0x14, 0x7a, 0xcd, 0x03, 0xf0, 0x58, 0xbb, 0xdc, + 0x25, 0x57, 0x08, 0xb5, 0x2f, 0x82, 0x7c, 0x62, 0x86, 0xa3, 0x4e, 0x64, 0x77, 0x47, 0x3e, 0xe7, + 0xff, 0xfb, 0x1f, 0x9f, 0x63, 0x23, 0x9f, 0xe5, 0x52, 0x29, 0x96, 0x52, 0x91, 0x45, 0x09, 0xcf, + 0xb8, 0x12, 0x2a, 0x9c, 0xe5, 0x52, 0x4b, 0xfc, 0x74, 0xce, 0x35, 0x85, 0x44, 0x08, 0x91, 0xcc, + 0x79, 0xf8, 0xb7, 0xb8, 0xb7, 0xe5, 0x08, 0x21, 0x24, 0x10, 0x13, 0x5d, 0x56, 0xfa, 0x5e, 0xcf, + 0x25, 0x53, 0x45, 0x66, 0xb9, 0x60, 0xdc, 0xe6, 0x9e, 0x39, 0x39, 0xd0, 0x90, 0x94, 0xaa, 0x94, + 0x68, 0x49, 0x18, 0xbb, 0x06, 0x04, 0x2b, 0x45, 0x3a, 0xa7, 0xec, 0x9c, 0xe7, 0x36, 0xbf, 0xed, + 0xe4, 0xa7, 0x54, 0x69, 0x32, 0x99, 0x4a, 0x76, 0x4e, 0x52, 0x2e, 0x92, 0x54, 0xdb, 0x1a, 0xb7, + 0x4b, 0x59, 0xe8, 0x55, 0xc8, 0x13, 0xa7, 0x60, 0x46, 0x73, 0x7a, 0x61, 0xaf, 0xdf, 0x7b, 0x9c, + 0xc8, 0x44, 0x42, 0x18, 0x99, 0xa8, 0x3a, 0xdd, 0xfe, 0xd6, 0x46, 0xdd, 0xbd, 0x6a, 0x4c, 0x9f, + 0x34, 0xd5, 0x1c, 0x8f, 0x50, 0xbb, 0x92, 0xf9, 0x5e, 0xdf, 0x1b, 0x74, 0x76, 0x9f, 0x87, 0xff, + 0x1c, 0x5b, 0x78, 0x0c, 0xc5, 0xc3, 0xff, 0x2f, 0x7f, 0x6e, 0xb5, 0x62, 0x2b, 0xc5, 0xa7, 0x68, + 0x53, 0x16, 0x7a, 0x5c, 0x8e, 0xab, 0xd6, 0x8e, 0x84, 0xd2, 0xfe, 0x7f, 0xfd, 0xb5, 0x41, 0x67, + 0xf7, 0x55, 0x03, 0xee, 0x83, 0x23, 0xb3, 0xd0, 0x15, 0x14, 0x3e, 0x44, 0xdd, 0x84, 0xaa, 0x63, + 0x33, 0x7f, 0x40, 0xdf, 0x01, 0xf4, 0x8b, 0x06, 0xf4, 0x9e, 0x95, 0xc4, 0x35, 0x31, 0xfe, 0x88, + 0xee, 0x8f, 0x4c, 0xd1, 0xc8, 0x14, 0x8d, 0x4b, 0xe5, 0xdf, 0xbd, 0x55, 0xa3, 0xae, 0x26, 0xae, + 0x13, 0xf0, 0x17, 0xf4, 0xc8, 0xec, 0x6f, 0x68, 0xd6, 0xb7, 0x0f, 0xdb, 0x83, 0x36, 0xef, 0x01, + 0x38, 0x6c, 0x00, 0x1f, 0xd5, 0x95, 0xf1, 0x4d, 0x28, 0xcc, 0x10, 0x36, 0x56, 0xfb, 0x54, 0xa5, + 0x63, 0x39, 0x62, 0xba, 0x04, 0x83, 0x75, 0x30, 0xd8, 0x69, 0x30, 0x38, 0xa8, 0x09, 0xed, 0x90, + 0x6f, 0xc0, 0xe1, 0x53, 0x63, 0xe2, 0xbc, 0x30, 0x32, 0x35, 0x26, 0x1d, 0x30, 0x79, 0x79, 0x0b, + 0x93, 0xfa, 0x1a, 0x37, 0x44, 0x56, 0xdf, 0xe2, 0x67, 0xb4, 0x61, 0x94, 0x84, 0x32, 0x26, 0x8b, + 0x4c, 0x8b, 0x2c, 0xf1, 0xbb, 0xf0, 0xe4, 0x9a, 0x2e, 0x70, 0xc2, 0x35, 0x7d, 0x77, 0x2d, 0xb2, + 0xf8, 0x07, 0xf3, 0xda, 0x29, 0x7e, 0x8d, 0x1e, 0xbe, 0x17, 0x19, 0x9d, 0x8a, 0x39, 0x3f, 0x3b, + 0xc8, 0x26, 0xb2, 0xc8, 0xce, 0x94, 0xbf, 0xd9, 0x5f, 0x1b, 0xac, 0xc7, 0xab, 0x89, 0xe1, 0xe1, + 0xe5, 0x22, 0xf0, 0xae, 0x16, 0x81, 0xf7, 0x6b, 0x11, 0x78, 0xdf, 0x97, 0x41, 0xeb, 0x6a, 0x19, + 0xb4, 0x7e, 0x2c, 0x83, 0xd6, 0xc9, 0x9b, 0x44, 0xe8, 0xb4, 0x98, 0x84, 0x4c, 0x5e, 0x44, 0xc6, + 0x62, 0xa7, 0xfa, 0x5a, 0x7f, 0xfa, 0x8a, 0xca, 0xc8, 0xf9, 0x70, 0xfa, 0xeb, 0x8c, 0xab, 0x49, + 0x1b, 0xbe, 0xd6, 0xdb, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x69, 0x4a, 0x62, 0x7d, 0x8b, 0x04, + 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -185,6 +195,17 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.FinalizedInbounds) > 0 { + for iNdEx := len(m.FinalizedInbounds) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.FinalizedInbounds[iNdEx]) + copy(dAtA[i:], m.FinalizedInbounds[iNdEx]) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.FinalizedInbounds[iNdEx]))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x82 + } + } { size, err := m.ZetaAccounting.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -349,6 +370,12 @@ func (m *GenesisState) Size() (n int) { } l = m.ZetaAccounting.Size() n += 1 + l + sovGenesis(uint64(l)) + if len(m.FinalizedInbounds) > 0 { + for _, s := range m.FinalizedInbounds { + l = len(s) + n += 2 + l + sovGenesis(uint64(l)) + } + } return n } @@ -657,6 +684,38 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 16: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FinalizedInbounds", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FinalizedInbounds = append(m.FinalizedInbounds, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/crosschain/types/keys.go b/x/crosschain/types/keys.go index 7e710562a4..8777d8df0c 100644 --- a/x/crosschain/types/keys.go +++ b/x/crosschain/types/keys.go @@ -36,8 +36,9 @@ func KeyPrefix(p string) []byte { } const ( - SendKey = "Send-value-" - LastBlockHeightKey = "LastBlockHeight-value-" + SendKey = "Send-value-" + LastBlockHeightKey = "LastBlockHeight-value-" + FinalizedInboundsKey = "FinalizedInbounds-value-" GasPriceKey = "GasPrice-value-" @@ -75,6 +76,10 @@ func (m CrossChainTx) LogIdentifierForCCTX() string { } +func FinalizedInboundKey(intxHash string, chainID int64, eventIndex uint64) string { + return fmt.Sprintf("%d-%s-%d", chainID, intxHash, eventIndex) +} + var ( ModuleAddress = authtypes.NewModuleAddress(ModuleName) //ModuleAddressEVM common.EVMAddress diff --git a/x/observer/keeper/chain_nonces.go b/x/observer/keeper/chain_nonces.go index cf386545d0..7a9a6ab53c 100644 --- a/x/observer/keeper/chain_nonces.go +++ b/x/observer/keeper/chain_nonces.go @@ -39,9 +39,7 @@ func (k Keeper) RemoveChainNonces(ctx sdk.Context, index string) { func (k Keeper) GetAllChainNonces(ctx sdk.Context) (list []types.ChainNonces) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.ChainNoncesKey)) iterator := sdk.KVStorePrefixIterator(store, []byte{}) - defer iterator.Close() - for ; iterator.Valid(); iterator.Next() { var val types.ChainNonces k.cdc.MustUnmarshal(iterator.Value(), &val)