From 8db24cced7700042808c0b3402bbd0f068cc5ff3 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Wed, 17 Apr 2024 21:02:18 -0500 Subject: [PATCH 01/33] initial commit of grpc pending cctx query with rate limiter --- proto/crosschain/query.proto | 10 + proto/crosschain/rate_limiter_flags.proto | 26 + typescript/crosschain/index.d.ts | 1 + typescript/crosschain/query_pb.d.ts | 58 ++ .../crosschain/rate_limiter_flags_pb.d.ts | 91 +++ x/crosschain/keeper/foreign_coins.go | 4 +- x/crosschain/keeper/foreign_coins_test.go | 3 +- x/crosschain/keeper/grpc_query_cctx.go | 219 +++++- x/crosschain/keeper/rate_limiter_flags.go | 87 ++ x/crosschain/types/keys.go | 3 + x/crosschain/types/query.pb.go | 652 ++++++++++++--- x/crosschain/types/rate_limiter_flags.pb.go | 741 ++++++++++++++++++ 12 files changed, 1768 insertions(+), 127 deletions(-) create mode 100644 proto/crosschain/rate_limiter_flags.proto create mode 100644 typescript/crosschain/rate_limiter_flags_pb.d.ts create mode 100644 x/crosschain/keeper/rate_limiter_flags.go create mode 100644 x/crosschain/types/rate_limiter_flags.pb.go diff --git a/proto/crosschain/query.proto b/proto/crosschain/query.proto index 99ad6b4b72..5372c9b0c9 100644 --- a/proto/crosschain/query.proto +++ b/proto/crosschain/query.proto @@ -252,6 +252,16 @@ message QueryListCctxPendingResponse { uint64 totalPending = 2; } +message QueryListCctxPendingWithRateLimitRequest { + uint32 limit = 2; +} + +message QueryListCctxPendingWithRateLimitResponse { + repeated CrossChainTx cross_chain_tx = 1; + uint64 total_pending = 2; + bool rate_limit_exceeded = 3; +} + message QueryLastZetaHeightRequest {} message QueryLastZetaHeightResponse { diff --git a/proto/crosschain/rate_limiter_flags.proto b/proto/crosschain/rate_limiter_flags.proto new file mode 100644 index 0000000000..af9edabcbb --- /dev/null +++ b/proto/crosschain/rate_limiter_flags.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; +package zetachain.zetacore.crosschain; + +import "gogoproto/gogo.proto"; +import "pkg/coin/coin.proto"; + +option go_package = "github.com/zeta-chain/zetacore/x/crosschain/types"; + +// ZRC20Rate defines the conversion rate of ZRC20 to ZETA +message ZRC20Rate { + int64 chain_id = 1; + coin.CoinType coin_type = 2; + string asset = 3; + double conversion_rate = 4; +} + +// RateLimiterFlags defines the outbound rate limiter flags +message RateLimiterFlags { + bool is_enabled = 1; + int64 rate_limit_window = 2; + string rate_limit_in_zeta = 3 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Uint", + (gogoproto.nullable) = false + ]; + repeated ZRC20Rate zrc20_rates = 4; +} diff --git a/typescript/crosschain/index.d.ts b/typescript/crosschain/index.d.ts index e357b4b8b3..0f542908cb 100644 --- a/typescript/crosschain/index.d.ts +++ b/typescript/crosschain/index.d.ts @@ -7,4 +7,5 @@ export * from "./in_tx_tracker_pb"; export * from "./last_block_height_pb"; export * from "./out_tx_tracker_pb"; export * from "./query_pb"; +export * from "./rate_limiter_flags_pb"; export * from "./tx_pb"; diff --git a/typescript/crosschain/query_pb.d.ts b/typescript/crosschain/query_pb.d.ts index 370926427e..3f66935a9f 100644 --- a/typescript/crosschain/query_pb.d.ts +++ b/typescript/crosschain/query_pb.d.ts @@ -870,6 +870,64 @@ export declare class QueryListCctxPendingResponse extends Message | undefined, b: QueryListCctxPendingResponse | PlainMessage | undefined): boolean; } +/** + * @generated from message zetachain.zetacore.crosschain.QueryListCctxPendingWithRateLimitRequest + */ +export declare class QueryListCctxPendingWithRateLimitRequest extends Message { + /** + * @generated from field: uint32 limit = 2; + */ + limit: number; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "zetachain.zetacore.crosschain.QueryListCctxPendingWithRateLimitRequest"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): QueryListCctxPendingWithRateLimitRequest; + + static fromJson(jsonValue: JsonValue, options?: Partial): QueryListCctxPendingWithRateLimitRequest; + + static fromJsonString(jsonString: string, options?: Partial): QueryListCctxPendingWithRateLimitRequest; + + static equals(a: QueryListCctxPendingWithRateLimitRequest | PlainMessage | undefined, b: QueryListCctxPendingWithRateLimitRequest | PlainMessage | undefined): boolean; +} + +/** + * @generated from message zetachain.zetacore.crosschain.QueryListCctxPendingWithRateLimitResponse + */ +export declare class QueryListCctxPendingWithRateLimitResponse extends Message { + /** + * @generated from field: repeated zetachain.zetacore.crosschain.CrossChainTx cross_chain_tx = 1; + */ + crossChainTx: CrossChainTx[]; + + /** + * @generated from field: uint64 total_pending = 2; + */ + totalPending: bigint; + + /** + * @generated from field: bool rate_limit_exceeded = 3; + */ + rateLimitExceeded: boolean; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "zetachain.zetacore.crosschain.QueryListCctxPendingWithRateLimitResponse"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): QueryListCctxPendingWithRateLimitResponse; + + static fromJson(jsonValue: JsonValue, options?: Partial): QueryListCctxPendingWithRateLimitResponse; + + static fromJsonString(jsonString: string, options?: Partial): QueryListCctxPendingWithRateLimitResponse; + + static equals(a: QueryListCctxPendingWithRateLimitResponse | PlainMessage | undefined, b: QueryListCctxPendingWithRateLimitResponse | PlainMessage | undefined): boolean; +} + /** * @generated from message zetachain.zetacore.crosschain.QueryLastZetaHeightRequest */ diff --git a/typescript/crosschain/rate_limiter_flags_pb.d.ts b/typescript/crosschain/rate_limiter_flags_pb.d.ts new file mode 100644 index 0000000000..b95e353e94 --- /dev/null +++ b/typescript/crosschain/rate_limiter_flags_pb.d.ts @@ -0,0 +1,91 @@ +// @generated by protoc-gen-es v1.3.0 with parameter "target=dts" +// @generated from file crosschain/rate_limiter_flags.proto (package zetachain.zetacore.crosschain, syntax proto3) +/* eslint-disable */ +// @ts-nocheck + +import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf"; +import { Message, proto3 } from "@bufbuild/protobuf"; +import type { CoinType } from "../pkg/coin/coin_pb.js"; + +/** + * ZRC20Rate defines the conversion rate of ZRC20 to ZETA + * + * @generated from message zetachain.zetacore.crosschain.ZRC20Rate + */ +export declare class ZRC20Rate extends Message { + /** + * @generated from field: int64 chain_id = 1; + */ + chainId: bigint; + + /** + * @generated from field: coin.CoinType coin_type = 2; + */ + coinType: CoinType; + + /** + * @generated from field: string asset = 3; + */ + asset: string; + + /** + * @generated from field: double conversion_rate = 4; + */ + conversionRate: number; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "zetachain.zetacore.crosschain.ZRC20Rate"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): ZRC20Rate; + + static fromJson(jsonValue: JsonValue, options?: Partial): ZRC20Rate; + + static fromJsonString(jsonString: string, options?: Partial): ZRC20Rate; + + static equals(a: ZRC20Rate | PlainMessage | undefined, b: ZRC20Rate | PlainMessage | undefined): boolean; +} + +/** + * RateLimiterFlags defines the outbound rate limiter flags + * + * @generated from message zetachain.zetacore.crosschain.RateLimiterFlags + */ +export declare class RateLimiterFlags extends Message { + /** + * @generated from field: bool is_enabled = 1; + */ + isEnabled: boolean; + + /** + * @generated from field: int64 rate_limit_window = 2; + */ + rateLimitWindow: bigint; + + /** + * @generated from field: string rate_limit_in_zeta = 3; + */ + rateLimitInZeta: string; + + /** + * @generated from field: repeated zetachain.zetacore.crosschain.ZRC20Rate zrc20_rates = 4; + */ + zrc20Rates: ZRC20Rate[]; + + constructor(data?: PartialMessage); + + static readonly runtime: typeof proto3; + static readonly typeName = "zetachain.zetacore.crosschain.RateLimiterFlags"; + static readonly fields: FieldList; + + static fromBinary(bytes: Uint8Array, options?: Partial): RateLimiterFlags; + + static fromJson(jsonValue: JsonValue, options?: Partial): RateLimiterFlags; + + static fromJsonString(jsonString: string, options?: Partial): RateLimiterFlags; + + static equals(a: RateLimiterFlags | PlainMessage | undefined, b: RateLimiterFlags | PlainMessage | undefined): boolean; +} + diff --git a/x/crosschain/keeper/foreign_coins.go b/x/crosschain/keeper/foreign_coins.go index 1ceeb39bf7..15ecd54260 100644 --- a/x/crosschain/keeper/foreign_coins.go +++ b/x/crosschain/keeper/foreign_coins.go @@ -5,11 +5,11 @@ import ( fungibleModuleTypes "github.com/zeta-chain/zetacore/x/fungible/types" ) -func (k Keeper) GetAllForeignCoins(ctx sdk.Context) ([]fungibleModuleTypes.ForeignCoins, error) { +func (k Keeper) GetAllForeignCoins(ctx sdk.Context) []fungibleModuleTypes.ForeignCoins { chains := k.zetaObserverKeeper.GetSupportedChains(ctx) var fCoins []fungibleModuleTypes.ForeignCoins for _, chain := range chains { fCoins = append(fCoins, k.fungibleKeeper.GetAllForeignCoinsForChain(ctx, chain.ChainId)...) } - return fCoins, nil + return fCoins } diff --git a/x/crosschain/keeper/foreign_coins_test.go b/x/crosschain/keeper/foreign_coins_test.go index 5d145b08f1..aaa359cd72 100644 --- a/x/crosschain/keeper/foreign_coins_test.go +++ b/x/crosschain/keeper/foreign_coins_test.go @@ -14,7 +14,6 @@ func TestKeeper_GetAllForeignCoins(t *testing.T) { fc.ForeignChainId = 101 k.GetFungibleKeeper().SetForeignCoins(ctx, fc) - res, err := k.GetAllForeignCoins(ctx) - require.NoError(t, err) + res := k.GetAllForeignCoins(ctx) require.Equal(t, 1, len(res)) } diff --git a/x/crosschain/keeper/grpc_query_cctx.go b/x/crosschain/keeper/grpc_query_cctx.go index 74bdc49293..1fe7d04e24 100644 --- a/x/crosschain/keeper/grpc_query_cctx.go +++ b/x/crosschain/keeper/grpc_query_cctx.go @@ -3,10 +3,13 @@ package keeper import ( "context" "fmt" + "math/big" + "strings" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" + "github.com/zeta-chain/zetacore/pkg/coin" "github.com/zeta-chain/zetacore/x/crosschain/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -91,15 +94,13 @@ func (k Keeper) CctxByNonce(c context.Context, req *types.QueryGetCctxByNonceReq } // CctxListPending returns a list of pending cctxs and the total number of pending cctxs -// a limit for the number of cctxs to return can be specified -// if no limit is specified, the default is MaxPendingCctxs +// a limit for the number of cctxs to return can be specified or the default is MaxPendingCctxs func (k Keeper) CctxListPending(c context.Context, req *types.QueryListCctxPendingRequest) (*types.QueryListCctxPendingResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } - // check limit - // if no limit specified, default to MaxPendingCctxs + // check limit and use default MaxPendingCctxs if not specified if req.Limit > MaxPendingCctxs { return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("limit exceeds max limit of %d", MaxPendingCctxs)) } @@ -144,11 +145,10 @@ func (k Keeper) CctxListPending(c context.Context, req *types.QueryListCctxPendi if !found { return nil, status.Error(codes.Internal, fmt.Sprintf("cctx not found: index %s", nonceToCctx.CctxIndex)) } - if cctx.CctxStatus.Status == types.CctxStatus_PendingOutbound || cctx.CctxStatus.Status == types.CctxStatus_PendingRevert { - totalPending++ - // we check here if max cctxs is reached because we want to return the total pending cctxs - // even if we have reached the limit + // only take a `limit` number of pending cctxs as result but still count the total pending cctxs + if IsPending(cctx) { + totalPending++ if !maxCCTXsReached() { cctxs = append(cctxs, &cctx) } @@ -177,3 +177,206 @@ func (k Keeper) CctxListPending(c context.Context, req *types.QueryListCctxPendi TotalPending: totalPending, }, nil } + +// CctxListPendingWithinRateLimit returns a list of pending cctxs that do not exceed the outbound rate limit +// a limit for the number of cctxs to return can be specified or the default is MaxPendingCctxs +func (k Keeper) CctxListPendingWithinRateLimit(c context.Context, req *types.QueryListCctxPendingWithRateLimitRequest) (*types.QueryListCctxPendingWithRateLimitResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + + // check limit and use default MaxPendingCctxs if not specified + if req.Limit > MaxPendingCctxs { + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("limit exceeds max limit of %d", MaxPendingCctxs)) + } + limit := req.Limit + if limit == 0 { + limit = MaxPendingCctxs + } + + // get current height and tss + ctx := sdk.UnwrapSDKContext(c) + height := ctx.BlockHeight() + if height <= 0 { + return nil, status.Error(codes.OutOfRange, "height out of range") + } + tss, found := k.zetaObserverKeeper.GetTSS(ctx) + if !found { + return nil, status.Error(codes.Internal, "tss not found") + } + + // check rate limit flags to decide if we should apply rate limit + applyLimit := true + rateLimitFlags, found := k.GetRatelimiterFlags(ctx) + if !found || !rateLimitFlags.IsEnabled { + applyLimit = false + } + + // calculate the rate limiter sliding window left boundary (inclusive) + leftWindowBoundary := height - rateLimitFlags.RateLimitWindow + if leftWindowBoundary < 0 { + leftWindowBoundary = 0 + } + + // get the conversion rates for all foreign coins + var gasCoinRates map[int64]*big.Float + var erc20CoinRates map[string]*big.Float + var rateLimitInZeta *big.Float + if applyLimit { + gasCoinRates, erc20CoinRates = k.GetRatelimiterRates(ctx) + rateLimitInZeta = new(big.Float).SetInt(rateLimitFlags.RateLimitInZeta.BigInt()) + } + + // define a few variables to be used in the below loops + limitExceeded := false + totalPending := uint64(0) + totalCctxValueInZeta := big.NewFloat(0) + cctxs := make([]*types.CrossChainTx, 0) + + // the criteria to stop adding cctxs to the result + maxCCTXsReached := func() bool { + // #nosec G701 len always positive + return uint32(len(cctxs)) >= limit + } + + // query pending cctxs for each supported chain + chains := k.zetaObserverKeeper.GetSupportedChains(ctx) +ChainLoop: + for _, chain := range chains { + // get pending nonces for this chain + pendingNonces, found := k.GetObserverKeeper().GetPendingNonces(ctx, tss.TssPubkey, chain.ChainId) + if !found { + return nil, status.Error(codes.Internal, "pending nonces not found") + } + + // we should at least query 1000 prior to find any pending cctx that we might have missed + // this logic is needed because a confirmation of higher nonce will automatically update the p.NonceLow + // therefore might mask some lower nonce cctx that is still pending. + startNonce := pendingNonces.NonceLow - 1 + endNonce := pendingNonces.NonceLow - 1000 + if endNonce < 0 { + endNonce = 0 + } + + // query cctx by nonce backwards to the left boundary of the rate limit sliding window + for nonce := startNonce; nonce >= 0; nonce-- { + nonceToCctx, found := k.GetObserverKeeper().GetNonceToCctx(ctx, tss.TssPubkey, chain.ChainId, nonce) + if !found { + return nil, status.Error(codes.Internal, fmt.Sprintf("nonceToCctx not found: chainid %d, nonce %d", chain.ChainId, nonce)) + } + cctx, found := k.GetCrossChainTx(ctx, nonceToCctx.CctxIndex) + if !found { + return nil, status.Error(codes.Internal, fmt.Sprintf("cctx not found: index %s", nonceToCctx.CctxIndex)) + } + + // We should at least go backwards by 1000 nonces to pick up missed pending cctxs + // We might go even further back if rate limiter is enabled and the endNonce hasn't hit the left window boundary yet + // There are three criteria to stop scanning backwards: + // criteria #1: if rate limiter is disabled, we should stop exactly on the `endNonce` + if !applyLimit && nonce < endNonce { + break + } + if applyLimit { + // criteria #2: if rate limiter is enabled, we'll stop at the left window boundary if the `endNonce` hasn't hit it yet + // #nosec G701 always positive + if nonce < endNonce && cctx.InboundTxParams.InboundTxObservedExternalHeight < uint64(leftWindowBoundary) { + break + } + // criteria #3: if rate limiter is enabled, we should finish the RPC call if the rate limit is exceeded + if rateLimitExceeded(chain.ChainId, &cctx, gasCoinRates, erc20CoinRates, totalCctxValueInZeta, rateLimitInZeta) { + limitExceeded = true + break ChainLoop + } + } + + // only take a `limit` number of pending cctxs as result but still count the total pending cctxs + if IsPending(cctx) { + totalPending++ + if !maxCCTXsReached() { + cctxs = append(cctxs, &cctx) + } + } + } + + // add the pending nonces to the total pending + // #nosec G701 always in range + totalPending += uint64(pendingNonces.NonceHigh - pendingNonces.NonceLow) + + // now query the pending nonces that we know are pending + for i := pendingNonces.NonceLow; i < pendingNonces.NonceHigh; i++ { + nonceToCctx, found := k.GetObserverKeeper().GetNonceToCctx(ctx, tss.TssPubkey, chain.ChainId, i) + if !found { + return nil, status.Error(codes.Internal, "nonceToCctx not found") + } + cctx, found := k.GetCrossChainTx(ctx, nonceToCctx.CctxIndex) + if !found { + return nil, status.Error(codes.Internal, "cctxIndex not found") + } + + // only take a `limit` number of pending cctxs as result + if maxCCTXsReached() { + break + } + // criteria #3: if rate limiter is enabled, we should finish the RPC call if the rate limit is exceeded + if applyLimit && rateLimitExceeded(chain.ChainId, &cctx, gasCoinRates, erc20CoinRates, totalCctxValueInZeta, rateLimitInZeta) { + limitExceeded = true + break ChainLoop + } + cctxs = append(cctxs, &cctx) + } + } + + return &types.QueryListCctxPendingWithRateLimitResponse{ + CrossChainTx: cctxs, + TotalPending: totalPending, + RateLimitExceeded: limitExceeded, + }, nil +} + +// convertCctxValue converts the value of the cctx in ZETA using given conversion rates +func convertCctxValue( + chainID int64, + cctx *types.CrossChainTx, + gasCoinRates map[int64]*big.Float, + erc20CoinRates map[string]*big.Float, +) *big.Float { + var rate *big.Float + switch cctx.InboundTxParams.CoinType { + case coin.CoinType_Zeta: + // no conversion needed for ZETA + rate = big.NewFloat(1.0) + case coin.CoinType_Gas: + // convert gas coin amount into ZETA + rate = gasCoinRates[chainID] + case coin.CoinType_ERC20: + // convert erc20 coin amount into ZETA + rate = erc20CoinRates[strings.ToLower(cctx.InboundTxParams.Asset)] + default: + // skip CoinType_Cmd + return big.NewFloat(0) + } + if rate == nil || rate.Cmp(big.NewFloat(0)) == 0 { + // should not happen, return 0 to skip this cctx + return big.NewFloat(0) + } + + // convert asset amount into ZETA + amountCctx := new(big.Float).SetInt(cctx.InboundTxParams.Amount.BigInt()) + amountZeta := new(big.Float).Mul(amountCctx, rate) + return amountZeta +} + +// rateLimitExceeded accumulates the cctx value and then checks if the rate limit is exceeded +// returns true if the rate limit is exceeded +func rateLimitExceeded( + chainID int64, + cctx *types.CrossChainTx, + gasCoinRates map[int64]*big.Float, + erc20CoinRates map[string]*big.Float, + currentCctxValue *big.Float, + rateLimitValue *big.Float, +) bool { + amountZeta := convertCctxValue(chainID, cctx, gasCoinRates, erc20CoinRates) + currentCctxValue.Add(currentCctxValue, amountZeta) + return currentCctxValue.Cmp(rateLimitValue) > 0 +} diff --git a/x/crosschain/keeper/rate_limiter_flags.go b/x/crosschain/keeper/rate_limiter_flags.go new file mode 100644 index 0000000000..f5cd88cb99 --- /dev/null +++ b/x/crosschain/keeper/rate_limiter_flags.go @@ -0,0 +1,87 @@ +package keeper + +import ( + "math/big" + "strings" + + "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/zeta-chain/zetacore/pkg/chains" + "github.com/zeta-chain/zetacore/pkg/coin" + "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +// hardcoded rate limiter flags +var rateLimitFlags = types.RateLimiterFlags{ + IsEnabled: true, + RateLimitWindow: 1200, // 1200 zeta blocks, 2 hours + RateLimitInZeta: math.NewUint(2000000), // 2,000,000 ZETA + Zrc20Rates: []*types.ZRC20Rate{ + // ETH + { + ChainId: chains.GoerliLocalnetChain().ChainId, + CoinType: coin.CoinType_Gas, + Asset: "", + ConversionRate: 2500, + }, + // USDT + { + ChainId: chains.GoerliLocalnetChain().ChainId, + CoinType: coin.CoinType_ERC20, + Asset: "0xbD1e64A22B9F92D9Ce81aA9B4b0fFacd80215564", + ConversionRate: 0.8, + }, + // BTC + { + ChainId: chains.BtcRegtestChain().ChainId, + CoinType: coin.CoinType_ERC20, + Asset: "0x8f56682c2b8b2e3d4f6f7f7d6f3c01b3f6f6a7d6", + ConversionRate: 50000, + }, + }, +} + +// SetRatelimiterFlags set the rate limiter flags in the store +func (k Keeper) SetRatelimiterFlags(ctx sdk.Context, crosschainFlags types.RateLimiterFlags) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.RateLimiterFlagsKey)) + b := k.cdc.MustMarshal(&crosschainFlags) + store.Set([]byte{0}, b) +} + +// GetRatelimiterFlags read the rate limiter flags from the store +func (k Keeper) GetRatelimiterFlags(_ sdk.Context) (val types.RateLimiterFlags, found bool) { + return rateLimitFlags, true + // store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.RateLimiterFlagsKey)) + + // b := store.Get([]byte{0}) + // if b == nil { + // return val, false + // } + + // k.cdc.MustUnmarshal(b, &val) + // return val, true +} + +// GetRatelimiterRates returns two maps of foreign coins and their rates +// The 1st map: foreign chain id -> gas coin rate +// The 2nd map: foreign erc20 asset -> erc20 coin rate +func (k Keeper) GetRatelimiterRates(ctx sdk.Context) (map[int64]*big.Float, map[string]*big.Float) { + rateLimitFlags, _ := k.GetRatelimiterFlags(ctx) + + // the result maps + gasCoinRates := make(map[int64]*big.Float) + erc20CoinRates := make(map[string]*big.Float) + + // loop through the rate limiter flags to get the rate + for _, zrc20Rate := range rateLimitFlags.Zrc20Rates { + rate := big.NewFloat(zrc20Rate.ConversionRate) + switch zrc20Rate.CoinType { + case coin.CoinType_Gas: + gasCoinRates[zrc20Rate.ChainId] = rate + case coin.CoinType_ERC20: + erc20CoinRates[strings.ToLower(zrc20Rate.Asset)] = rate + } + } + return gasCoinRates, erc20CoinRates +} diff --git a/x/crosschain/types/keys.go b/x/crosschain/types/keys.go index 719f54687f..9d1c38c882 100644 --- a/x/crosschain/types/keys.go +++ b/x/crosschain/types/keys.go @@ -53,6 +53,9 @@ const ( // #nosec G101: Potential hardcoded credentials (gosec) // ZetaAccountingKey value is used as prefix for storing ZetaAccountingKey ZetaAccountingKey = "ZetaAccounting-value-" + + // RateLimiterFlagsKey is the key for the rate limiter flags + RateLimiterFlagsKey = "RateLimiterFlags-value-" ) // OutTxTrackerKey returns the store key to retrieve a OutTxTracker from the index fields diff --git a/x/crosschain/types/query.pb.go b/x/crosschain/types/query.pb.go index af554543a3..0a8a73f0e4 100644 --- a/x/crosschain/types/query.pb.go +++ b/x/crosschain/types/query.pb.go @@ -1587,6 +1587,116 @@ func (m *QueryListCctxPendingResponse) GetTotalPending() uint64 { return 0 } +type QueryListCctxPendingWithRateLimitRequest struct { + Limit uint32 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` +} + +func (m *QueryListCctxPendingWithRateLimitRequest) Reset() { + *m = QueryListCctxPendingWithRateLimitRequest{} +} +func (m *QueryListCctxPendingWithRateLimitRequest) String() string { return proto.CompactTextString(m) } +func (*QueryListCctxPendingWithRateLimitRequest) ProtoMessage() {} +func (*QueryListCctxPendingWithRateLimitRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_65a992045e92a606, []int{33} +} +func (m *QueryListCctxPendingWithRateLimitRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryListCctxPendingWithRateLimitRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryListCctxPendingWithRateLimitRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryListCctxPendingWithRateLimitRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryListCctxPendingWithRateLimitRequest.Merge(m, src) +} +func (m *QueryListCctxPendingWithRateLimitRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryListCctxPendingWithRateLimitRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryListCctxPendingWithRateLimitRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryListCctxPendingWithRateLimitRequest proto.InternalMessageInfo + +func (m *QueryListCctxPendingWithRateLimitRequest) GetLimit() uint32 { + if m != nil { + return m.Limit + } + return 0 +} + +type QueryListCctxPendingWithRateLimitResponse struct { + CrossChainTx []*CrossChainTx `protobuf:"bytes,1,rep,name=cross_chain_tx,json=crossChainTx,proto3" json:"cross_chain_tx,omitempty"` + TotalPending uint64 `protobuf:"varint,2,opt,name=total_pending,json=totalPending,proto3" json:"total_pending,omitempty"` + RateLimitExceeded bool `protobuf:"varint,3,opt,name=rate_limit_exceeded,json=rateLimitExceeded,proto3" json:"rate_limit_exceeded,omitempty"` +} + +func (m *QueryListCctxPendingWithRateLimitResponse) Reset() { + *m = QueryListCctxPendingWithRateLimitResponse{} +} +func (m *QueryListCctxPendingWithRateLimitResponse) String() string { + return proto.CompactTextString(m) +} +func (*QueryListCctxPendingWithRateLimitResponse) ProtoMessage() {} +func (*QueryListCctxPendingWithRateLimitResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_65a992045e92a606, []int{34} +} +func (m *QueryListCctxPendingWithRateLimitResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryListCctxPendingWithRateLimitResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryListCctxPendingWithRateLimitResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryListCctxPendingWithRateLimitResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryListCctxPendingWithRateLimitResponse.Merge(m, src) +} +func (m *QueryListCctxPendingWithRateLimitResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryListCctxPendingWithRateLimitResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryListCctxPendingWithRateLimitResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryListCctxPendingWithRateLimitResponse proto.InternalMessageInfo + +func (m *QueryListCctxPendingWithRateLimitResponse) GetCrossChainTx() []*CrossChainTx { + if m != nil { + return m.CrossChainTx + } + return nil +} + +func (m *QueryListCctxPendingWithRateLimitResponse) GetTotalPending() uint64 { + if m != nil { + return m.TotalPending + } + return 0 +} + +func (m *QueryListCctxPendingWithRateLimitResponse) GetRateLimitExceeded() bool { + if m != nil { + return m.RateLimitExceeded + } + return false +} + type QueryLastZetaHeightRequest struct { } @@ -1594,7 +1704,7 @@ func (m *QueryLastZetaHeightRequest) Reset() { *m = QueryLastZetaHeightR func (m *QueryLastZetaHeightRequest) String() string { return proto.CompactTextString(m) } func (*QueryLastZetaHeightRequest) ProtoMessage() {} func (*QueryLastZetaHeightRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{33} + return fileDescriptor_65a992045e92a606, []int{35} } func (m *QueryLastZetaHeightRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1631,7 +1741,7 @@ func (m *QueryLastZetaHeightResponse) Reset() { *m = QueryLastZetaHeight func (m *QueryLastZetaHeightResponse) String() string { return proto.CompactTextString(m) } func (*QueryLastZetaHeightResponse) ProtoMessage() {} func (*QueryLastZetaHeightResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{34} + return fileDescriptor_65a992045e92a606, []int{36} } func (m *QueryLastZetaHeightResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1676,7 +1786,7 @@ func (m *QueryConvertGasToZetaRequest) Reset() { *m = QueryConvertGasToZ func (m *QueryConvertGasToZetaRequest) String() string { return proto.CompactTextString(m) } func (*QueryConvertGasToZetaRequest) ProtoMessage() {} func (*QueryConvertGasToZetaRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{35} + return fileDescriptor_65a992045e92a606, []int{37} } func (m *QueryConvertGasToZetaRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1729,7 +1839,7 @@ func (m *QueryConvertGasToZetaResponse) Reset() { *m = QueryConvertGasTo func (m *QueryConvertGasToZetaResponse) String() string { return proto.CompactTextString(m) } func (*QueryConvertGasToZetaResponse) ProtoMessage() {} func (*QueryConvertGasToZetaResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{36} + return fileDescriptor_65a992045e92a606, []int{38} } func (m *QueryConvertGasToZetaResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1786,7 +1896,7 @@ func (m *QueryMessagePassingProtocolFeeRequest) Reset() { *m = QueryMess func (m *QueryMessagePassingProtocolFeeRequest) String() string { return proto.CompactTextString(m) } func (*QueryMessagePassingProtocolFeeRequest) ProtoMessage() {} func (*QueryMessagePassingProtocolFeeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{37} + return fileDescriptor_65a992045e92a606, []int{39} } func (m *QueryMessagePassingProtocolFeeRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1825,7 +1935,7 @@ func (m *QueryMessagePassingProtocolFeeResponse) Reset() { func (m *QueryMessagePassingProtocolFeeResponse) String() string { return proto.CompactTextString(m) } func (*QueryMessagePassingProtocolFeeResponse) ProtoMessage() {} func (*QueryMessagePassingProtocolFeeResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65a992045e92a606, []int{38} + return fileDescriptor_65a992045e92a606, []int{40} } func (m *QueryMessagePassingProtocolFeeResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1895,6 +2005,8 @@ func init() { proto.RegisterType((*QueryAllCctxResponse)(nil), "zetachain.zetacore.crosschain.QueryAllCctxResponse") proto.RegisterType((*QueryListCctxPendingRequest)(nil), "zetachain.zetacore.crosschain.QueryListCctxPendingRequest") proto.RegisterType((*QueryListCctxPendingResponse)(nil), "zetachain.zetacore.crosschain.QueryListCctxPendingResponse") + proto.RegisterType((*QueryListCctxPendingWithRateLimitRequest)(nil), "zetachain.zetacore.crosschain.QueryListCctxPendingWithRateLimitRequest") + proto.RegisterType((*QueryListCctxPendingWithRateLimitResponse)(nil), "zetachain.zetacore.crosschain.QueryListCctxPendingWithRateLimitResponse") proto.RegisterType((*QueryLastZetaHeightRequest)(nil), "zetachain.zetacore.crosschain.QueryLastZetaHeightRequest") proto.RegisterType((*QueryLastZetaHeightResponse)(nil), "zetachain.zetacore.crosschain.QueryLastZetaHeightResponse") proto.RegisterType((*QueryConvertGasToZetaRequest)(nil), "zetachain.zetacore.crosschain.QueryConvertGasToZetaRequest") @@ -1906,115 +2018,120 @@ func init() { func init() { proto.RegisterFile("crosschain/query.proto", fileDescriptor_65a992045e92a606) } var fileDescriptor_65a992045e92a606 = []byte{ - // 1715 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x59, 0xd1, 0x6f, 0x14, 0x45, - 0x18, 0xef, 0xf4, 0x28, 0x94, 0x69, 0xa1, 0x32, 0x54, 0xac, 0x4b, 0x7b, 0x85, 0xad, 0xd0, 0x0a, - 0xf6, 0x16, 0x0a, 0x14, 0x81, 0x62, 0xbc, 0x16, 0x29, 0xc4, 0x02, 0xf5, 0x52, 0xa3, 0xc1, 0x98, - 0xcb, 0x74, 0x6f, 0xdd, 0xdb, 0xb0, 0xdd, 0x29, 0xb7, 0x7b, 0xa4, 0xa5, 0xe9, 0x0b, 0x0f, 0x3e, - 0x9b, 0xf0, 0xe0, 0x8b, 0xaf, 0x46, 0x1f, 0x7c, 0xf0, 0xc1, 0xe8, 0x83, 0x09, 0xc6, 0xa8, 0xc8, - 0x23, 0x89, 0x89, 0x31, 0x9a, 0x18, 0x03, 0xfe, 0x05, 0xfe, 0x05, 0x66, 0x67, 0xbf, 0xbd, 0x9b, - 0xdd, 0xdb, 0xbd, 0x9b, 0x5e, 0x8f, 0x07, 0x9e, 0x7a, 0xbb, 0x33, 0xdf, 0x37, 0xbf, 0xdf, 0x6f, - 0xbe, 0xf9, 0xf6, 0xfb, 0xa6, 0xf8, 0x80, 0x5e, 0x61, 0xae, 0xab, 0x97, 0xa9, 0xe5, 0x68, 0xb7, - 0xab, 0x46, 0x65, 0x3d, 0xb7, 0x5a, 0x61, 0x1e, 0x23, 0x23, 0x77, 0x0d, 0x8f, 0xf2, 0xd7, 0x39, - 0xfe, 0x8b, 0x55, 0x8c, 0x5c, 0x7d, 0xaa, 0x72, 0x4c, 0x67, 0xee, 0x0a, 0x73, 0xb5, 0x65, 0xea, - 0x1a, 0x81, 0x9d, 0x76, 0xe7, 0xe4, 0xb2, 0xe1, 0xd1, 0x93, 0xda, 0x2a, 0x35, 0x2d, 0x87, 0x7a, - 0x16, 0x73, 0x02, 0x57, 0xca, 0xa8, 0xb0, 0x04, 0xff, 0x59, 0xe4, 0xbf, 0x8b, 0xde, 0x1a, 0x4c, - 0x50, 0x84, 0x09, 0x26, 0x75, 0x8b, 0xab, 0x15, 0x4b, 0x37, 0x60, 0x6c, 0x4c, 0x18, 0xe3, 0x36, - 0xc5, 0x32, 0x75, 0xcb, 0x45, 0x8f, 0x15, 0x75, 0xbd, 0xe6, 0x20, 0xdb, 0x30, 0xc9, 0xab, 0x50, - 0xfd, 0x96, 0x51, 0x81, 0x71, 0x55, 0x18, 0xb7, 0xa9, 0xeb, 0x15, 0x97, 0x6d, 0xa6, 0xdf, 0x2a, - 0x96, 0x0d, 0xcb, 0x2c, 0x7b, 0x09, 0x28, 0x59, 0xd5, 0x6b, 0x74, 0x32, 0x68, 0x32, 0x93, 0xf1, - 0x9f, 0x9a, 0xff, 0x0b, 0xde, 0x0e, 0x9b, 0x8c, 0x99, 0xb6, 0xa1, 0xd1, 0x55, 0x4b, 0xa3, 0x8e, - 0xc3, 0x3c, 0xce, 0xdc, 0x0d, 0x46, 0xd5, 0x61, 0xac, 0xbc, 0xe3, 0x8b, 0x73, 0xd3, 0xf0, 0x68, - 0x5e, 0xd7, 0x59, 0xd5, 0xf1, 0x2c, 0xc7, 0x2c, 0x18, 0xb7, 0xab, 0x86, 0xeb, 0xa9, 0xd7, 0xf0, - 0xc1, 0xc4, 0x51, 0x77, 0x95, 0x39, 0xae, 0x41, 0x72, 0x78, 0x3f, 0x5d, 0x66, 0x15, 0xcf, 0x28, - 0x15, 0xfd, 0x2d, 0x28, 0xd2, 0x15, 0x7f, 0xc6, 0x10, 0x3a, 0x84, 0x26, 0x76, 0x17, 0xf6, 0xc1, - 0x10, 0xb7, 0xe5, 0x03, 0x35, 0x77, 0xf3, 0x86, 0x77, 0xa3, 0xea, 0x2d, 0xad, 0x2d, 0x05, 0xf0, - 0x61, 0x35, 0x32, 0x84, 0x77, 0x71, 0x76, 0x57, 0x2f, 0x71, 0x17, 0x99, 0x42, 0xf8, 0x48, 0x06, - 0x71, 0x8f, 0xc3, 0x1c, 0xdd, 0x18, 0xea, 0x3e, 0x84, 0x26, 0x76, 0x14, 0x82, 0x07, 0xb5, 0x8a, - 0x87, 0x93, 0xdd, 0x01, 0xbc, 0x77, 0x71, 0x3f, 0x13, 0xde, 0x73, 0xa7, 0x7d, 0x53, 0xc7, 0x73, - 0x4d, 0x03, 0x27, 0x27, 0xba, 0x9a, 0xdd, 0xf1, 0xe8, 0xef, 0xd1, 0xae, 0x42, 0xc4, 0x8d, 0x6a, - 0x00, 0x8b, 0xbc, 0x6d, 0x27, 0xb1, 0xb8, 0x8c, 0x71, 0x3d, 0xc0, 0x60, 0xcd, 0xa3, 0xb9, 0x20, - 0x1a, 0x73, 0x7e, 0x34, 0xe6, 0x82, 0x28, 0x86, 0x68, 0xcc, 0x2d, 0x52, 0xd3, 0x00, 0xdb, 0x82, - 0x60, 0xa9, 0x3e, 0x40, 0x40, 0xaf, 0x61, 0x9d, 0x54, 0x7a, 0x99, 0x0e, 0xd0, 0x23, 0xf3, 0x11, - 0xfc, 0xdd, 0x1c, 0xff, 0x78, 0x4b, 0xfc, 0x01, 0xa6, 0x08, 0x81, 0x7b, 0x08, 0xab, 0x49, 0x04, - 0x66, 0xd7, 0xe7, 0x7c, 0x24, 0xa1, 0x5e, 0x83, 0xb8, 0x87, 0x23, 0x83, 0x3d, 0x0f, 0x1e, 0x62, - 0x2a, 0x76, 0xb7, 0xad, 0xe2, 0x2f, 0x08, 0x8f, 0x35, 0x05, 0xf1, 0x9c, 0x88, 0xf9, 0x31, 0xc2, - 0x87, 0x43, 0x1e, 0x57, 0x9d, 0x34, 0x2d, 0x5f, 0xc6, 0xbd, 0x41, 0xe6, 0xb2, 0x4a, 0xd1, 0x23, - 0x54, 0xea, 0x98, 0xa0, 0x3f, 0x0a, 0xbb, 0x9a, 0x04, 0x04, 0xf4, 0x2c, 0xe0, 0x3e, 0xcb, 0x89, - 0xcb, 0x79, 0xac, 0x85, 0x9c, 0xa2, 0xbf, 0x40, 0x4d, 0xd1, 0x49, 0xe7, 0xc4, 0x14, 0x4e, 0xb0, - 0xb0, 0xa4, 0xdb, 0xe9, 0x13, 0xfc, 0xbd, 0x70, 0x82, 0xa3, 0xeb, 0x3c, 0x0f, 0x22, 0x5d, 0xc0, - 0x23, 0x61, 0x76, 0xf5, 0x97, 0xbc, 0x42, 0xdd, 0xf2, 0x12, 0x9b, 0xd3, 0xbd, 0xb5, 0x50, 0x26, - 0x05, 0xf7, 0x5a, 0x30, 0x00, 0x29, 0xbf, 0xf6, 0xac, 0x6e, 0xe2, 0x6c, 0x9a, 0x31, 0x70, 0xff, - 0x00, 0xef, 0xb5, 0x22, 0x23, 0x20, 0xf4, 0xa4, 0x04, 0xfd, 0xba, 0x11, 0x28, 0x10, 0x73, 0xa5, - 0xce, 0xc0, 0xf2, 0xd1, 0xc9, 0x97, 0xa8, 0x47, 0x65, 0xc0, 0xdf, 0xc5, 0xa3, 0xa9, 0xd6, 0x80, - 0xfe, 0x3d, 0xbc, 0x67, 0xce, 0xc7, 0xc4, 0x83, 0x7e, 0x69, 0xcd, 0x95, 0xcc, 0x17, 0xa2, 0x0d, - 0x40, 0x8f, 0xfa, 0x51, 0x4d, 0x50, 0x1d, 0x42, 0xa6, 0x51, 0xf5, 0x4e, 0x05, 0xe7, 0x43, 0x04, - 0x1a, 0x25, 0xac, 0xd4, 0x64, 0x8b, 0x32, 0x1d, 0xda, 0xa2, 0xce, 0xc5, 0xa9, 0x86, 0x5f, 0x0a, - 0x43, 0x6d, 0x9e, 0xba, 0x8b, 0x7e, 0x65, 0x26, 0x7c, 0x5a, 0x2c, 0xa7, 0x64, 0xac, 0xc1, 0x0e, - 0x07, 0x0f, 0x6a, 0x11, 0x0f, 0x35, 0x1a, 0x00, 0xe5, 0x39, 0xdc, 0x1b, 0xbe, 0x03, 0x6d, 0xc7, - 0x5b, 0x90, 0xad, 0xb9, 0xa8, 0x19, 0xaa, 0x14, 0x10, 0xe5, 0x6d, 0x3b, 0x8e, 0xa8, 0x53, 0xbb, - 0xf7, 0x25, 0x02, 0x12, 0x91, 0x35, 0x12, 0x49, 0x64, 0xda, 0x22, 0xd1, 0xb9, 0xfd, 0x99, 0xae, - 0xa7, 0x82, 0x05, 0xea, 0x7a, 0xb3, 0x7e, 0x61, 0x7b, 0x85, 0xd7, 0xb5, 0xcd, 0xb7, 0x69, 0x03, - 0x4e, 0x61, 0x92, 0x1d, 0x10, 0x7d, 0x1f, 0x0f, 0xc4, 0x86, 0x40, 0xd2, 0x5c, 0x0b, 0xbe, 0x71, - 0x87, 0x71, 0x37, 0x6a, 0xb9, 0x7e, 0x38, 0x52, 0x40, 0x77, 0x6a, 0x27, 0x7f, 0x46, 0xc0, 0x33, - 0x69, 0xa9, 0x66, 0x3c, 0x33, 0x1d, 0xe0, 0xd9, 0xb9, 0x5d, 0x3e, 0x8e, 0xf7, 0x87, 0xbb, 0x25, - 0x66, 0xab, 0xe4, 0xad, 0x5d, 0x80, 0xa6, 0x03, 0x26, 0xcf, 0xae, 0x5f, 0xf7, 0xeb, 0xf9, 0x76, - 0xdb, 0x00, 0x13, 0x0f, 0x46, 0x97, 0x06, 0xd5, 0x6e, 0xe0, 0x7e, 0x31, 0xb7, 0x4a, 0x96, 0xff, - 0xa2, 0x49, 0x21, 0xe2, 0x40, 0xfd, 0x10, 0x38, 0xe6, 0x6d, 0xfb, 0x59, 0x64, 0xe4, 0xaf, 0x11, - 0x10, 0xa9, 0xf9, 0x4f, 0x25, 0x92, 0xd9, 0x16, 0x91, 0xce, 0xed, 0xfa, 0x75, 0x28, 0xa4, 0x16, - 0x2c, 0x97, 0x6b, 0xbf, 0x68, 0x38, 0xa5, 0x7a, 0xfb, 0xd8, 0xac, 0x1c, 0x1d, 0xc4, 0x3d, 0xb6, - 0xb5, 0x62, 0x79, 0x7c, 0xf5, 0x3d, 0x85, 0xe0, 0x41, 0xbd, 0x1f, 0x56, 0x4c, 0x0d, 0x0e, 0x9f, - 0x95, 0x14, 0x2a, 0xee, 0xf7, 0x98, 0x47, 0x6d, 0x58, 0x08, 0x22, 0x2b, 0xf2, 0xae, 0xd6, 0x23, - 0xfb, 0x87, 0xc7, 0xef, 0x66, 0x23, 0x89, 0x40, 0x3d, 0x13, 0x6a, 0x10, 0x1b, 0x05, 0xc4, 0x07, - 0xf0, 0x4e, 0x21, 0x35, 0x65, 0x0a, 0xf0, 0xa4, 0x2e, 0x01, 0xd3, 0x39, 0xe6, 0xdc, 0x31, 0x2a, - 0xfe, 0x97, 0x68, 0x89, 0xf9, 0xe6, 0x0d, 0xa7, 0xa0, 0x41, 0x3a, 0x05, 0xf7, 0x9a, 0xd4, 0x5d, - 0xa8, 0xa9, 0xb7, 0xbb, 0x50, 0x7b, 0x56, 0x3f, 0x47, 0x50, 0x3f, 0x34, 0xba, 0x05, 0x3c, 0xaf, - 0xe1, 0x7d, 0xac, 0xea, 0x2d, 0xb3, 0xaa, 0x53, 0x9a, 0xa7, 0xee, 0x55, 0xc7, 0x1f, 0x0c, 0x3b, - 0xf6, 0x86, 0x01, 0x7f, 0x36, 0xbf, 0x27, 0xd0, 0x99, 0x7d, 0xd9, 0x30, 0x60, 0x76, 0xb0, 0x68, - 0xe3, 0x00, 0x99, 0xc0, 0x03, 0xfe, 0x5f, 0x31, 0x4f, 0x65, 0xb8, 0x9e, 0xf1, 0xd7, 0xea, 0x38, - 0x3e, 0xc2, 0x61, 0x5e, 0x33, 0x5c, 0x97, 0x9a, 0xc6, 0x22, 0x75, 0x5d, 0xcb, 0x31, 0x17, 0xeb, - 0x1e, 0x43, 0x75, 0x2f, 0xe3, 0xa3, 0xad, 0x26, 0x02, 0xb1, 0x61, 0xbc, 0xfb, 0xa3, 0x1a, 0xc4, - 0x80, 0x50, 0xfd, 0xc5, 0xd4, 0x7f, 0x23, 0xb8, 0x87, 0x3b, 0x22, 0x0f, 0x11, 0xee, 0x17, 0xfb, - 0x36, 0x72, 0xbe, 0x45, 0xf4, 0x34, 0xb9, 0xb2, 0x50, 0x2e, 0xb4, 0x65, 0x1b, 0x20, 0x56, 0x2f, - 0xde, 0xfb, 0xed, 0xdf, 0xfb, 0xdd, 0x67, 0xc9, 0x19, 0xcd, 0x37, 0x9d, 0x14, 0xee, 0x9f, 0x6a, - 0x97, 0x3c, 0x35, 0x23, 0x6d, 0x03, 0x92, 0xe0, 0xa6, 0xb6, 0xc1, 0xd3, 0xde, 0x26, 0xf9, 0x0e, - 0xe1, 0x01, 0xd1, 0x6f, 0xde, 0xb6, 0xe5, 0xb8, 0x24, 0x5f, 0x5c, 0xc8, 0x71, 0x49, 0xb9, 0x8c, - 0x50, 0x8f, 0x73, 0x2e, 0x47, 0xc8, 0x98, 0x04, 0x17, 0xf2, 0x17, 0xc2, 0x07, 0x62, 0xc8, 0xa1, - 0x7f, 0x24, 0xf9, 0x36, 0x40, 0x44, 0x9b, 0x60, 0x65, 0x76, 0x3b, 0x2e, 0x80, 0xce, 0x79, 0x4e, - 0xe7, 0x34, 0x99, 0x92, 0xa0, 0x03, 0xb6, 0xb0, 0x43, 0x9b, 0xe4, 0x4f, 0x84, 0x5f, 0x14, 0x9a, - 0x34, 0x81, 0xdc, 0x9b, 0x92, 0xc8, 0x52, 0x1b, 0x7c, 0x25, 0xbf, 0x0d, 0x0f, 0x40, 0x6d, 0x86, - 0x53, 0x9b, 0x26, 0xa7, 0x53, 0xa8, 0x59, 0x4e, 0x0a, 0xb3, 0xa2, 0x55, 0xda, 0x24, 0xdf, 0x22, - 0xbc, 0x37, 0x4a, 0x4e, 0x3a, 0xe6, 0x12, 0x5a, 0x6d, 0xe9, 0x98, 0x4b, 0x6a, 0x9f, 0x5b, 0xc6, - 0x9c, 0xc0, 0xc4, 0x25, 0xbf, 0x02, 0x70, 0xa1, 0x05, 0x99, 0x91, 0x3c, 0xbc, 0x89, 0x8d, 0x98, - 0x72, 0xb1, 0x4d, 0x6b, 0x00, 0xff, 0x3a, 0x07, 0x3f, 0x45, 0x4e, 0x34, 0x01, 0x5f, 0x37, 0xd3, - 0x36, 0xc2, 0xe7, 0x4d, 0xf2, 0x3b, 0xc2, 0xa4, 0xb1, 0x35, 0x25, 0x52, 0x78, 0x52, 0x1b, 0x62, - 0xe5, 0x8d, 0x76, 0xcd, 0x81, 0x4f, 0x9e, 0xf3, 0xb9, 0x40, 0xce, 0xa5, 0xf2, 0x89, 0x5f, 0x8d, - 0x17, 0x4b, 0xd4, 0xa3, 0x22, 0xb1, 0x1f, 0x10, 0xde, 0x17, 0x5d, 0xc1, 0x0f, 0xaf, 0x99, 0x2d, - 0x84, 0x48, 0x9b, 0xbb, 0x94, 0xda, 0x02, 0xab, 0x93, 0x9c, 0xd5, 0x38, 0x39, 0x22, 0xb5, 0x4b, - 0xe4, 0x2b, 0x54, 0x6f, 0xbd, 0xc8, 0xb4, 0x64, 0x80, 0xc4, 0x7a, 0x44, 0xe5, 0xec, 0x96, 0xed, - 0x00, 0xac, 0xc6, 0xc1, 0xbe, 0x4a, 0xc6, 0x53, 0xc0, 0x9a, 0x60, 0xe0, 0x6b, 0x5e, 0x32, 0xd6, - 0x36, 0xc9, 0x17, 0x08, 0xf7, 0x85, 0x5e, 0x7c, 0xa9, 0xa7, 0x25, 0xc5, 0x6a, 0x0b, 0x71, 0x42, - 0xa7, 0xaa, 0x8e, 0x73, 0xc4, 0x87, 0xc9, 0x68, 0x0b, 0xc4, 0xe4, 0x01, 0xc2, 0x2f, 0xc4, 0x4b, - 0x1a, 0x22, 0x95, 0x3c, 0x52, 0xea, 0x2b, 0x65, 0xa6, 0x3d, 0x63, 0x49, 0xa9, 0xf5, 0x38, 0xd6, - 0x87, 0x08, 0xf7, 0x09, 0x55, 0x0b, 0xb9, 0x24, 0xb3, 0x7c, 0xab, 0xea, 0x48, 0x79, 0x6b, 0x9b, - 0x5e, 0x80, 0xcd, 0x31, 0xce, 0xe6, 0x15, 0xa2, 0xa6, 0xb0, 0x11, 0x2a, 0x3d, 0xf2, 0x08, 0x35, - 0x34, 0xa3, 0x44, 0x36, 0x15, 0x26, 0xb7, 0xd2, 0x72, 0xa9, 0x27, 0xfd, 0x1a, 0x40, 0x9d, 0xe6, - 0xf0, 0x4f, 0x90, 0x5c, 0x0a, 0x7c, 0x3b, 0x6a, 0x57, 0x0b, 0xff, 0x9f, 0x10, 0x26, 0x31, 0x9f, - 0xfe, 0x29, 0x90, 0x4d, 0x19, 0xdb, 0x61, 0x93, 0xde, 0xec, 0xab, 0x39, 0xce, 0x66, 0x82, 0x1c, - 0x95, 0x63, 0x43, 0x3e, 0x43, 0x78, 0x07, 0x4f, 0x3e, 0x53, 0x92, 0x32, 0x8a, 0xe9, 0xf1, 0xd4, - 0x96, 0x6c, 0x24, 0xbf, 0xbb, 0x3a, 0x7c, 0xb0, 0xb8, 0xc8, 0xdf, 0x20, 0xdc, 0x27, 0x34, 0xf9, - 0xe4, 0xdc, 0x16, 0x56, 0x8c, 0x5e, 0x0c, 0xb4, 0x07, 0xf6, 0x0c, 0x07, 0xab, 0x91, 0xc9, 0xa6, - 0x60, 0x1b, 0x8a, 0xeb, 0x4f, 0x11, 0xde, 0x15, 0x7e, 0x81, 0xa6, 0x24, 0x77, 0x74, 0xcb, 0xc2, - 0xc6, 0x1a, 0x7d, 0x75, 0x8c, 0x63, 0x1d, 0x21, 0x07, 0x9b, 0x60, 0xf5, 0x2b, 0xb0, 0x01, 0xdf, - 0xca, 0x6f, 0x91, 0xa1, 0x43, 0x95, 0x2b, 0xc1, 0x92, 0x9b, 0x74, 0xb9, 0x12, 0x2c, 0xa5, 0x1f, - 0x6f, 0x99, 0x39, 0xf4, 0xba, 0x0d, 0x2f, 0x1d, 0xa3, 0xff, 0x48, 0x96, 0x0b, 0x86, 0xc4, 0x7f, - 0x4d, 0x2b, 0xe7, 0xdb, 0x31, 0x95, 0xfc, 0xaa, 0xdf, 0x8d, 0xa2, 0xf4, 0x81, 0x47, 0xbb, 0x7b, - 0x39, 0xe0, 0x89, 0xf7, 0x05, 0x72, 0xc0, 0x93, 0x2f, 0x13, 0x5a, 0x02, 0xb7, 0x23, 0x66, 0xb3, - 0x6f, 0x3f, 0x7a, 0x92, 0x45, 0x8f, 0x9f, 0x64, 0xd1, 0x3f, 0x4f, 0xb2, 0xe8, 0x93, 0xa7, 0xd9, - 0xae, 0xc7, 0x4f, 0xb3, 0x5d, 0x7f, 0x3c, 0xcd, 0x76, 0xdd, 0x3c, 0x69, 0x5a, 0x5e, 0xb9, 0xba, - 0x9c, 0xd3, 0xd9, 0x8a, 0xe8, 0x2a, 0xc4, 0xa3, 0xad, 0x89, 0x5e, 0xbd, 0xf5, 0x55, 0xc3, 0x5d, - 0xde, 0xc9, 0xbf, 0x02, 0xa7, 0xfe, 0x0f, 0x00, 0x00, 0xff, 0xff, 0xda, 0xf6, 0xfb, 0xb3, 0x90, - 0x21, 0x00, 0x00, + // 1797 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x59, 0x41, 0x6f, 0x14, 0xc7, + 0x12, 0x76, 0x7b, 0x31, 0x98, 0xb6, 0xc1, 0xcf, 0x8d, 0x1f, 0xcf, 0x6f, 0xb1, 0xd7, 0x30, 0x7e, + 0x60, 0x03, 0xcf, 0xbb, 0x60, 0xc0, 0x3c, 0xc0, 0x3c, 0xb1, 0x36, 0x60, 0x50, 0x0c, 0x98, 0x95, + 0x23, 0x22, 0xa2, 0x68, 0xd4, 0x9e, 0xed, 0xcc, 0x8e, 0x18, 0xcf, 0x98, 0x9d, 0x59, 0xb4, 0xc6, + 0xf2, 0x85, 0x43, 0xce, 0x91, 0x38, 0xe4, 0x92, 0x6b, 0x94, 0x1c, 0x72, 0xc8, 0x21, 0x4a, 0x0e, + 0x91, 0x88, 0xa2, 0x24, 0x84, 0x23, 0x12, 0x52, 0x14, 0x25, 0x52, 0x14, 0x41, 0x7e, 0x41, 0x7e, + 0x41, 0x34, 0x3d, 0x35, 0xbb, 0x3d, 0xb3, 0x33, 0xbb, 0xed, 0xf5, 0x72, 0xe0, 0xe4, 0x9d, 0xe9, + 0xae, 0xea, 0xef, 0xab, 0xaa, 0xa9, 0xae, 0x2a, 0xe3, 0xfd, 0x5a, 0xd9, 0x76, 0x1c, 0xad, 0x44, + 0x0d, 0x2b, 0x77, 0xbf, 0xc2, 0xca, 0xeb, 0xd9, 0xb5, 0xb2, 0xed, 0xda, 0x64, 0xf4, 0x21, 0x73, + 0x29, 0x7f, 0x9d, 0xe5, 0xbf, 0xec, 0x32, 0xcb, 0xd6, 0xb7, 0xa6, 0x8f, 0x69, 0xb6, 0xb3, 0x6a, + 0x3b, 0xb9, 0x15, 0xea, 0x30, 0x5f, 0x2e, 0xf7, 0xe0, 0xe4, 0x0a, 0x73, 0xe9, 0xc9, 0xdc, 0x1a, + 0xd5, 0x0d, 0x8b, 0xba, 0x86, 0x6d, 0xf9, 0xaa, 0xd2, 0x63, 0xc2, 0x11, 0xfc, 0xa7, 0xca, 0x7f, + 0xab, 0x6e, 0x15, 0x36, 0xa4, 0x85, 0x0d, 0x3a, 0x75, 0xd4, 0xb5, 0xb2, 0xa1, 0x31, 0x58, 0x1b, + 0x17, 0xd6, 0xb8, 0x8c, 0x5a, 0xa2, 0x4e, 0x49, 0x75, 0x6d, 0x55, 0xd3, 0x6a, 0x0a, 0x32, 0x0d, + 0x9b, 0xdc, 0x32, 0xd5, 0xee, 0xb1, 0x32, 0xac, 0x2b, 0xc2, 0xba, 0x49, 0x1d, 0x57, 0x5d, 0x31, + 0x6d, 0xed, 0x9e, 0x5a, 0x62, 0x86, 0x5e, 0x72, 0x63, 0x50, 0xda, 0x15, 0xb7, 0x51, 0xc9, 0x90, + 0x6e, 0xeb, 0x36, 0xff, 0x99, 0xf3, 0x7e, 0xc1, 0xdb, 0x11, 0xdd, 0xb6, 0x75, 0x93, 0xe5, 0xe8, + 0x9a, 0x91, 0xa3, 0x96, 0x65, 0xbb, 0x9c, 0xb9, 0xe3, 0xaf, 0x2a, 0x23, 0x38, 0x7d, 0xdb, 0x33, + 0xce, 0x5d, 0xe6, 0xd2, 0xbc, 0xa6, 0xd9, 0x15, 0xcb, 0x35, 0x2c, 0xbd, 0xc0, 0xee, 0x57, 0x98, + 0xe3, 0x2a, 0x37, 0xf0, 0x81, 0xd8, 0x55, 0x67, 0xcd, 0xb6, 0x1c, 0x46, 0xb2, 0x78, 0x1f, 0x5d, + 0xb1, 0xcb, 0x2e, 0x2b, 0xaa, 0x9e, 0x0b, 0x54, 0xba, 0xea, 0xed, 0x18, 0x46, 0x07, 0xd1, 0xe4, + 0xee, 0xc2, 0x20, 0x2c, 0x71, 0x59, 0xbe, 0x50, 0x53, 0xb7, 0xc0, 0xdc, 0x5b, 0x15, 0x77, 0xb9, + 0xba, 0xec, 0xc3, 0x87, 0xd3, 0xc8, 0x30, 0xde, 0xc5, 0xd9, 0x5d, 0xbf, 0xcc, 0x55, 0xa4, 0x0a, + 0xc1, 0x23, 0x19, 0xc2, 0x3d, 0x96, 0x6d, 0x69, 0x6c, 0xb8, 0xfb, 0x20, 0x9a, 0xdc, 0x51, 0xf0, + 0x1f, 0x94, 0x0a, 0x1e, 0x89, 0x57, 0x07, 0xf0, 0xde, 0xc6, 0xfd, 0xb6, 0xf0, 0x9e, 0x2b, 0xed, + 0x9b, 0x3e, 0x9e, 0x6d, 0x1a, 0x38, 0x59, 0x51, 0xd5, 0xdc, 0x8e, 0x67, 0xbf, 0x8f, 0x75, 0x15, + 0x42, 0x6a, 0x14, 0x06, 0x2c, 0xf2, 0xa6, 0x19, 0xc7, 0xe2, 0x2a, 0xc6, 0xf5, 0x00, 0x83, 0x33, + 0x8f, 0x64, 0xfd, 0x68, 0xcc, 0x7a, 0xd1, 0x98, 0xf5, 0xa3, 0x18, 0xa2, 0x31, 0xbb, 0x44, 0x75, + 0x06, 0xb2, 0x05, 0x41, 0x52, 0x79, 0x82, 0x80, 0x5e, 0xc3, 0x39, 0x89, 0xf4, 0x52, 0x1d, 0xa0, + 0x47, 0x16, 0x42, 0xf8, 0xbb, 0x39, 0xfe, 0x89, 0x96, 0xf8, 0x7d, 0x4c, 0x21, 0x02, 0x8f, 0x10, + 0x56, 0xe2, 0x08, 0xcc, 0xad, 0xcf, 0x7b, 0x48, 0x02, 0x7b, 0x0d, 0xe1, 0x1e, 0x8e, 0x0c, 0x7c, + 0xee, 0x3f, 0x44, 0xac, 0xd8, 0xdd, 0xb6, 0x15, 0x7f, 0x44, 0x78, 0xbc, 0x29, 0x88, 0x37, 0xc4, + 0x98, 0x1f, 0x20, 0x7c, 0x28, 0xe0, 0x71, 0xdd, 0x4a, 0xb2, 0xe5, 0xbf, 0x71, 0xaf, 0x9f, 0xb9, + 0x8c, 0x62, 0xf8, 0x13, 0x2a, 0x76, 0xcc, 0xa0, 0xdf, 0x09, 0x5e, 0x8d, 0x03, 0x02, 0xf6, 0x2c, + 0xe0, 0x3e, 0xc3, 0x8a, 0x9a, 0xf3, 0x58, 0x0b, 0x73, 0x8a, 0xfa, 0x7c, 0x6b, 0x8a, 0x4a, 0x3a, + 0x67, 0x4c, 0xe1, 0x0b, 0x16, 0x8e, 0x74, 0x3a, 0xfd, 0x05, 0x7f, 0x23, 0x7c, 0xc1, 0xe1, 0x73, + 0xde, 0x04, 0x23, 0x5d, 0xc0, 0xa3, 0x41, 0x76, 0xf5, 0x8e, 0xbc, 0x46, 0x9d, 0xd2, 0xb2, 0x3d, + 0xaf, 0xb9, 0xd5, 0xc0, 0x4c, 0x69, 0xdc, 0x6b, 0xc0, 0x02, 0xa4, 0xfc, 0xda, 0xb3, 0xb2, 0x89, + 0x33, 0x49, 0xc2, 0xc0, 0xfd, 0x5d, 0xbc, 0xd7, 0x08, 0xad, 0x80, 0xa1, 0xa7, 0x24, 0xe8, 0xd7, + 0x85, 0xc0, 0x02, 0x11, 0x55, 0xca, 0x2c, 0x1c, 0x1f, 0xde, 0x7c, 0x99, 0xba, 0x54, 0x06, 0xfc, + 0x43, 0x3c, 0x96, 0x28, 0x0d, 0xe8, 0xef, 0xe0, 0x3d, 0xf3, 0x1e, 0x26, 0x1e, 0xf4, 0xcb, 0x55, + 0x47, 0x32, 0x5f, 0x88, 0x32, 0x00, 0x3d, 0xac, 0x47, 0xd1, 0xc1, 0xea, 0x10, 0x32, 0x8d, 0x56, + 0xef, 0x54, 0x70, 0x3e, 0x45, 0x60, 0xa3, 0x98, 0x93, 0x9a, 0xb8, 0x28, 0xd5, 0x21, 0x17, 0x75, + 0x2e, 0x4e, 0x73, 0xf8, 0x5f, 0x41, 0xa8, 0x2d, 0x50, 0x67, 0xc9, 0xab, 0xcc, 0x84, 0xab, 0xc5, + 0xb0, 0x8a, 0xac, 0x0a, 0x1e, 0xf6, 0x1f, 0x14, 0x15, 0x0f, 0x37, 0x0a, 0x00, 0xe5, 0x79, 0xdc, + 0x1b, 0xbc, 0x03, 0xdb, 0x4e, 0xb4, 0x20, 0x5b, 0x53, 0x51, 0x13, 0x54, 0x28, 0x20, 0xca, 0x9b, + 0x66, 0x14, 0x51, 0xa7, 0xbc, 0xf7, 0x19, 0x02, 0x12, 0xa1, 0x33, 0x62, 0x49, 0xa4, 0xda, 0x22, + 0xd1, 0x39, 0xff, 0xcc, 0xd4, 0x53, 0xc1, 0x22, 0x75, 0xdc, 0x39, 0xaf, 0xb0, 0xbd, 0xc6, 0xeb, + 0xda, 0xe6, 0x6e, 0xda, 0x80, 0xaf, 0x30, 0x4e, 0x0e, 0x88, 0xbe, 0x83, 0x07, 0x22, 0x4b, 0x60, + 0xd2, 0x6c, 0x0b, 0xbe, 0x51, 0x85, 0x51, 0x35, 0x4a, 0xa9, 0xfe, 0x71, 0x24, 0x80, 0xee, 0x94, + 0x27, 0x7f, 0x40, 0xc0, 0x33, 0xee, 0xa8, 0x66, 0x3c, 0x53, 0x1d, 0xe0, 0xd9, 0x39, 0x2f, 0x1f, + 0xc7, 0xfb, 0x02, 0x6f, 0x89, 0xd9, 0x2a, 0xde, 0xb5, 0x8b, 0xd0, 0x74, 0xc0, 0xe6, 0xb9, 0xf5, + 0x9b, 0x5e, 0x3d, 0xdf, 0x6e, 0x1b, 0xa0, 0xe3, 0xa1, 0xf0, 0xd1, 0x60, 0xb5, 0x5b, 0xb8, 0x5f, + 0xcc, 0xad, 0x92, 0xe5, 0xbf, 0x28, 0x52, 0x08, 0x29, 0x50, 0xde, 0x03, 0x8e, 0x79, 0xd3, 0x7c, + 0x1d, 0x19, 0xf9, 0x0b, 0x04, 0x44, 0x6a, 0xfa, 0x13, 0x89, 0xa4, 0xb6, 0x45, 0xa4, 0x73, 0x5e, + 0xbf, 0x09, 0x85, 0xd4, 0xa2, 0xe1, 0x70, 0xdb, 0x2f, 0x31, 0xab, 0x58, 0x6f, 0x1f, 0x9b, 0x95, + 0xa3, 0x43, 0xb8, 0xc7, 0x34, 0x56, 0x0d, 0x97, 0x9f, 0xbe, 0xa7, 0xe0, 0x3f, 0x28, 0x8f, 0x83, + 0x8a, 0xa9, 0x41, 0xe1, 0xeb, 0x32, 0x85, 0x82, 0xfb, 0x5d, 0xdb, 0xa5, 0x26, 0x1c, 0x04, 0x91, + 0x15, 0x7a, 0xa7, 0x5c, 0xc2, 0x93, 0x71, 0xa0, 0xee, 0x18, 0x6e, 0xa9, 0x40, 0x5d, 0xb6, 0xe8, + 0x41, 0x17, 0x02, 0x3e, 0x86, 0xd7, 0x0b, 0x84, 0x8f, 0x4a, 0xa8, 0x00, 0x92, 0xb7, 0xf1, 0xde, + 0xf0, 0x14, 0xa2, 0x2d, 0x9a, 0x9a, 0x48, 0x73, 0x1c, 0xef, 0xe1, 0x94, 0xd4, 0xb5, 0x64, 0x9e, + 0x5e, 0x3b, 0x5f, 0xa6, 0x2e, 0x53, 0x39, 0x66, 0x95, 0x55, 0x35, 0xc6, 0x8a, 0xac, 0x38, 0x9c, + 0x3a, 0x88, 0x26, 0x7b, 0x0b, 0x83, 0xe5, 0x00, 0xe7, 0x15, 0x58, 0xa8, 0xcd, 0x0e, 0xbc, 0xa4, + 0xe2, 0x75, 0xf9, 0xa1, 0x04, 0xa9, 0x9c, 0x09, 0x62, 0x23, 0xb2, 0x0a, 0x24, 0xf7, 0xe3, 0x9d, + 0x42, 0xca, 0x4e, 0x15, 0xe0, 0x49, 0x59, 0x86, 0x08, 0x98, 0xb7, 0xad, 0x07, 0xac, 0xec, 0xdd, + 0xd0, 0xcb, 0xb6, 0x27, 0xde, 0x90, 0x1d, 0x1a, 0x42, 0x2a, 0x8d, 0x7b, 0x75, 0xea, 0x2c, 0xd6, + 0xac, 0xbf, 0xbb, 0x50, 0x7b, 0x56, 0x3e, 0x41, 0x50, 0x57, 0x35, 0xaa, 0x05, 0x3c, 0xff, 0xc5, + 0x83, 0x76, 0xc5, 0x5d, 0xb1, 0x2b, 0x56, 0x71, 0x81, 0x3a, 0xd7, 0x2d, 0x6f, 0x31, 0x98, 0x64, + 0x34, 0x2c, 0x78, 0xbb, 0xf9, 0xfc, 0x44, 0xb3, 0xcd, 0xab, 0x8c, 0xc1, 0x6e, 0xff, 0xd0, 0xc6, + 0x05, 0x32, 0x89, 0x07, 0xbc, 0xbf, 0x62, 0xfe, 0x4e, 0x71, 0xfb, 0x47, 0x5f, 0x2b, 0x13, 0xf8, + 0x30, 0x87, 0x79, 0x83, 0x39, 0x0e, 0xd5, 0xd9, 0x12, 0x75, 0x1c, 0xc3, 0xd2, 0x97, 0xea, 0x1a, + 0x03, 0xeb, 0x5e, 0xc5, 0x47, 0x5a, 0x6d, 0x04, 0x62, 0x23, 0x78, 0xf7, 0xfb, 0x35, 0x88, 0x3e, + 0xa1, 0xfa, 0x8b, 0xe9, 0xbf, 0x46, 0x71, 0x0f, 0x57, 0x44, 0x9e, 0x22, 0xdc, 0x2f, 0xf6, 0xb3, + 0xe4, 0x7c, 0x8b, 0x70, 0x6b, 0x32, 0xca, 0x49, 0x5f, 0x68, 0x4b, 0xd6, 0x47, 0xac, 0x5c, 0x7c, + 0xf4, 0xe2, 0xcf, 0xc7, 0xdd, 0x67, 0xc9, 0x99, 0x9c, 0x27, 0x3a, 0x25, 0xcc, 0xe5, 0x6a, 0xc3, + 0xaf, 0x9a, 0x50, 0x6e, 0x03, 0x2e, 0x87, 0xcd, 0xdc, 0x06, 0xbf, 0x0e, 0x36, 0xc9, 0xd7, 0x08, + 0x0f, 0x88, 0x7a, 0xf3, 0xa6, 0x29, 0xc7, 0x25, 0x7e, 0xa0, 0x23, 0xc7, 0x25, 0x61, 0x48, 0xa3, + 0x1c, 0xe7, 0x5c, 0x0e, 0x93, 0x71, 0x09, 0x2e, 0xe4, 0x37, 0x84, 0xf7, 0x47, 0x90, 0x43, 0x5f, + 0x4d, 0xf2, 0x6d, 0x80, 0x08, 0x0f, 0x07, 0xd2, 0x73, 0xdb, 0x51, 0x01, 0x74, 0xce, 0x73, 0x3a, + 0xa7, 0xc9, 0xb4, 0x04, 0x1d, 0x90, 0x05, 0x0f, 0x6d, 0x92, 0x5f, 0x11, 0xfe, 0xa7, 0xd0, 0xbc, + 0x0a, 0xe4, 0x2e, 0x49, 0x22, 0x4b, 0x1c, 0x7c, 0xa4, 0xf3, 0xdb, 0xd0, 0x00, 0xd4, 0x66, 0x39, + 0xb5, 0x19, 0x72, 0x3a, 0x81, 0x9a, 0x61, 0x25, 0x30, 0x53, 0x8d, 0xe2, 0x26, 0xf9, 0x0a, 0xe1, + 0xbd, 0x61, 0x72, 0xd2, 0x31, 0x17, 0x33, 0x82, 0x90, 0x8e, 0xb9, 0xb8, 0xb1, 0x42, 0xcb, 0x98, + 0x13, 0x98, 0x38, 0xe4, 0x27, 0x00, 0x2e, 0xb4, 0x66, 0xb3, 0x92, 0x1f, 0x6f, 0x6c, 0x83, 0x9a, + 0xbe, 0xd8, 0xa6, 0x34, 0x80, 0xff, 0x1f, 0x07, 0x3f, 0x4d, 0x4e, 0x34, 0x01, 0x5f, 0x17, 0xcb, + 0x6d, 0x04, 0xcf, 0x9b, 0xe4, 0x67, 0x84, 0x49, 0x63, 0xcb, 0x4e, 0xa4, 0xf0, 0x24, 0x0e, 0x0a, + 0xd2, 0xff, 0x6f, 0x57, 0x1c, 0xf8, 0xe4, 0x39, 0x9f, 0x0b, 0xe4, 0x5c, 0x22, 0x9f, 0xe8, 0xbf, + 0x0c, 0xd4, 0x22, 0x75, 0xa9, 0x48, 0xec, 0x5b, 0x84, 0x07, 0xc3, 0x27, 0x78, 0xe1, 0x35, 0xbb, + 0x85, 0x10, 0x69, 0xd3, 0x4b, 0x89, 0xa3, 0x01, 0x65, 0x8a, 0xb3, 0x9a, 0x20, 0x87, 0xa5, 0xbc, + 0x44, 0x3e, 0x47, 0xf5, 0x96, 0x94, 0xcc, 0x48, 0x06, 0x48, 0xa4, 0x77, 0x4e, 0x9f, 0xdd, 0xb2, + 0x1c, 0x80, 0xcd, 0x71, 0xb0, 0x47, 0xc9, 0x44, 0x02, 0x58, 0x1d, 0x04, 0x3c, 0x9b, 0x17, 0x59, + 0x75, 0x93, 0x7c, 0x8a, 0x70, 0x5f, 0xa0, 0xc5, 0x33, 0xf5, 0x8c, 0xa4, 0xb1, 0xda, 0x42, 0x1c, + 0xd3, 0xc1, 0x2b, 0x13, 0x1c, 0xf1, 0x21, 0x32, 0xd6, 0x02, 0x31, 0x79, 0x82, 0xf0, 0x3f, 0xa2, + 0x25, 0x0d, 0x91, 0x4a, 0x1e, 0x09, 0xf5, 0x55, 0x7a, 0xb6, 0x3d, 0x61, 0x49, 0x53, 0x6b, 0x51, + 0xac, 0x4f, 0x11, 0xee, 0x13, 0xaa, 0x16, 0x72, 0x59, 0xe6, 0xf8, 0x56, 0xd5, 0x51, 0xfa, 0xca, + 0x36, 0xb5, 0x00, 0x9b, 0x63, 0x9c, 0xcd, 0x7f, 0x88, 0x92, 0xc0, 0x46, 0xa8, 0xf4, 0xc8, 0x33, + 0xd4, 0xd0, 0xa4, 0x13, 0xd9, 0x54, 0x18, 0x3f, 0x62, 0x90, 0x4b, 0x3d, 0xc9, 0xe3, 0x11, 0x65, + 0x86, 0xc3, 0x3f, 0x41, 0xb2, 0x09, 0xf0, 0xcd, 0xb0, 0x5c, 0x2d, 0xfc, 0xbf, 0x47, 0x98, 0x44, + 0x74, 0x7a, 0x5f, 0x81, 0x6c, 0xca, 0xd8, 0x0e, 0x9b, 0xe4, 0x21, 0x88, 0x92, 0xe5, 0x6c, 0x26, + 0xc9, 0x11, 0x39, 0x36, 0xe4, 0x63, 0x84, 0x77, 0xf0, 0xe4, 0x33, 0x2d, 0x69, 0x46, 0x31, 0x3d, + 0x9e, 0xda, 0x92, 0x8c, 0xe4, 0xbd, 0xab, 0xc1, 0x85, 0xc5, 0x8d, 0xfc, 0x25, 0xc2, 0x7d, 0xc2, + 0xf0, 0x83, 0x9c, 0xdb, 0xc2, 0x89, 0xe1, 0x81, 0x49, 0x7b, 0x60, 0xcf, 0x70, 0xb0, 0x39, 0x32, + 0xd5, 0x14, 0x6c, 0x43, 0x71, 0xfd, 0x11, 0xc2, 0xbb, 0x82, 0x1b, 0x68, 0x5a, 0xd2, 0xa3, 0x5b, + 0x36, 0x6c, 0x64, 0x00, 0xa2, 0x8c, 0x73, 0xac, 0xa3, 0xe4, 0x40, 0x13, 0xac, 0x5e, 0x05, 0x36, + 0xe0, 0x49, 0x79, 0x2d, 0x76, 0xd0, 0xd1, 0x4a, 0x95, 0x60, 0xf1, 0xc3, 0x0b, 0xb9, 0x12, 0x2c, + 0x61, 0x4e, 0xd1, 0x32, 0x73, 0x68, 0x75, 0x19, 0x5e, 0x3a, 0x86, 0xff, 0xc1, 0x2e, 0x17, 0x0c, + 0xb1, 0xff, 0xb2, 0x4f, 0x9f, 0x6f, 0x47, 0x54, 0xf2, 0x56, 0x7f, 0x18, 0x46, 0xe9, 0x01, 0x0f, + 0x77, 0xf7, 0x72, 0xc0, 0x63, 0xe7, 0x05, 0x72, 0xc0, 0xe3, 0x87, 0x09, 0x2d, 0x81, 0x9b, 0x21, + 0xb1, 0xb9, 0xb7, 0x9e, 0xbd, 0xcc, 0xa0, 0xe7, 0x2f, 0x33, 0xe8, 0x8f, 0x97, 0x19, 0xf4, 0xe1, + 0xab, 0x4c, 0xd7, 0xf3, 0x57, 0x99, 0xae, 0x5f, 0x5e, 0x65, 0xba, 0xee, 0x9e, 0xd4, 0x0d, 0xb7, + 0x54, 0x59, 0xc9, 0x6a, 0xf6, 0xaa, 0xa8, 0x2a, 0xc0, 0x93, 0xab, 0x8a, 0x5a, 0xdd, 0xf5, 0x35, + 0xe6, 0xac, 0xec, 0xe4, 0xb7, 0xc0, 0xa9, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0x68, 0x29, 0xb5, + 0x4c, 0xa8, 0x22, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -4043,6 +4160,86 @@ func (m *QueryListCctxPendingResponse) MarshalToSizedBuffer(dAtA []byte) (int, e return len(dAtA) - i, nil } +func (m *QueryListCctxPendingWithRateLimitRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryListCctxPendingWithRateLimitRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryListCctxPendingWithRateLimitRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Limit != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.Limit)) + i-- + dAtA[i] = 0x10 + } + return len(dAtA) - i, nil +} + +func (m *QueryListCctxPendingWithRateLimitResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryListCctxPendingWithRateLimitResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryListCctxPendingWithRateLimitResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.RateLimitExceeded { + i-- + if m.RateLimitExceeded { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x18 + } + if m.TotalPending != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.TotalPending)) + i-- + dAtA[i] = 0x10 + } + if len(m.CrossChainTx) > 0 { + for iNdEx := len(m.CrossChainTx) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.CrossChainTx[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func (m *QueryLastZetaHeightRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -4723,6 +4920,39 @@ func (m *QueryListCctxPendingResponse) Size() (n int) { return n } +func (m *QueryListCctxPendingWithRateLimitRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Limit != 0 { + n += 1 + sovQuery(uint64(m.Limit)) + } + return n +} + +func (m *QueryListCctxPendingWithRateLimitResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.CrossChainTx) > 0 { + for _, e := range m.CrossChainTx { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + if m.TotalPending != 0 { + n += 1 + sovQuery(uint64(m.TotalPending)) + } + if m.RateLimitExceeded { + n += 2 + } + return n +} + func (m *QueryLastZetaHeightRequest) Size() (n int) { if m == nil { return 0 @@ -7911,6 +8141,198 @@ func (m *QueryListCctxPendingResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryListCctxPendingWithRateLimitRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryListCctxPendingWithRateLimitRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryListCctxPendingWithRateLimitRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + } + m.Limit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Limit |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryListCctxPendingWithRateLimitResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryListCctxPendingWithRateLimitResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryListCctxPendingWithRateLimitResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CrossChainTx", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CrossChainTx = append(m.CrossChainTx, &CrossChainTx{}) + if err := m.CrossChainTx[len(m.CrossChainTx)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalPending", wireType) + } + m.TotalPending = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalPending |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RateLimitExceeded", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.RateLimitExceeded = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *QueryLastZetaHeightRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/crosschain/types/rate_limiter_flags.pb.go b/x/crosschain/types/rate_limiter_flags.pb.go new file mode 100644 index 0000000000..ce24f8baf3 --- /dev/null +++ b/x/crosschain/types/rate_limiter_flags.pb.go @@ -0,0 +1,741 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: crosschain/rate_limiter_flags.proto + +package types + +import ( + encoding_binary "encoding/binary" + fmt "fmt" + io "io" + math "math" + math_bits "math/bits" + + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/gogo/protobuf/proto" + coin "github.com/zeta-chain/zetacore/pkg/coin" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// ZRC20Rate defines the conversion rate of ZRC20 to ZETA +type ZRC20Rate struct { + ChainId int64 `protobuf:"varint,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + CoinType coin.CoinType `protobuf:"varint,2,opt,name=coin_type,json=coinType,proto3,enum=coin.CoinType" json:"coin_type,omitempty"` + Asset string `protobuf:"bytes,3,opt,name=asset,proto3" json:"asset,omitempty"` + ConversionRate float64 `protobuf:"fixed64,4,opt,name=conversion_rate,json=conversionRate,proto3" json:"conversion_rate,omitempty"` +} + +func (m *ZRC20Rate) Reset() { *m = ZRC20Rate{} } +func (m *ZRC20Rate) String() string { return proto.CompactTextString(m) } +func (*ZRC20Rate) ProtoMessage() {} +func (*ZRC20Rate) Descriptor() ([]byte, []int) { + return fileDescriptor_b17ae80d5af4e97e, []int{0} +} +func (m *ZRC20Rate) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ZRC20Rate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ZRC20Rate.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ZRC20Rate) XXX_Merge(src proto.Message) { + xxx_messageInfo_ZRC20Rate.Merge(m, src) +} +func (m *ZRC20Rate) XXX_Size() int { + return m.Size() +} +func (m *ZRC20Rate) XXX_DiscardUnknown() { + xxx_messageInfo_ZRC20Rate.DiscardUnknown(m) +} + +var xxx_messageInfo_ZRC20Rate proto.InternalMessageInfo + +func (m *ZRC20Rate) GetChainId() int64 { + if m != nil { + return m.ChainId + } + return 0 +} + +func (m *ZRC20Rate) GetCoinType() coin.CoinType { + if m != nil { + return m.CoinType + } + return coin.CoinType_Zeta +} + +func (m *ZRC20Rate) GetAsset() string { + if m != nil { + return m.Asset + } + return "" +} + +func (m *ZRC20Rate) GetConversionRate() float64 { + if m != nil { + return m.ConversionRate + } + return 0 +} + +// RateLimiterFlags defines the outbound rate limiter flags +type RateLimiterFlags struct { + IsEnabled bool `protobuf:"varint,1,opt,name=is_enabled,json=isEnabled,proto3" json:"is_enabled,omitempty"` + RateLimitWindow int64 `protobuf:"varint,2,opt,name=rate_limit_window,json=rateLimitWindow,proto3" json:"rate_limit_window,omitempty"` + RateLimitInZeta github_com_cosmos_cosmos_sdk_types.Uint `protobuf:"bytes,3,opt,name=rate_limit_in_zeta,json=rateLimitInZeta,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint" json:"rate_limit_in_zeta"` + Zrc20Rates []*ZRC20Rate `protobuf:"bytes,4,rep,name=zrc20_rates,json=zrc20Rates,proto3" json:"zrc20_rates,omitempty"` +} + +func (m *RateLimiterFlags) Reset() { *m = RateLimiterFlags{} } +func (m *RateLimiterFlags) String() string { return proto.CompactTextString(m) } +func (*RateLimiterFlags) ProtoMessage() {} +func (*RateLimiterFlags) Descriptor() ([]byte, []int) { + return fileDescriptor_b17ae80d5af4e97e, []int{1} +} +func (m *RateLimiterFlags) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RateLimiterFlags) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RateLimiterFlags.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RateLimiterFlags) XXX_Merge(src proto.Message) { + xxx_messageInfo_RateLimiterFlags.Merge(m, src) +} +func (m *RateLimiterFlags) XXX_Size() int { + return m.Size() +} +func (m *RateLimiterFlags) XXX_DiscardUnknown() { + xxx_messageInfo_RateLimiterFlags.DiscardUnknown(m) +} + +var xxx_messageInfo_RateLimiterFlags proto.InternalMessageInfo + +func (m *RateLimiterFlags) GetIsEnabled() bool { + if m != nil { + return m.IsEnabled + } + return false +} + +func (m *RateLimiterFlags) GetRateLimitWindow() int64 { + if m != nil { + return m.RateLimitWindow + } + return 0 +} + +func (m *RateLimiterFlags) GetZrc20Rates() []*ZRC20Rate { + if m != nil { + return m.Zrc20Rates + } + return nil +} + +func init() { + proto.RegisterType((*ZRC20Rate)(nil), "zetachain.zetacore.crosschain.ZRC20Rate") + proto.RegisterType((*RateLimiterFlags)(nil), "zetachain.zetacore.crosschain.RateLimiterFlags") +} + +func init() { + proto.RegisterFile("crosschain/rate_limiter_flags.proto", fileDescriptor_b17ae80d5af4e97e) +} + +var fileDescriptor_b17ae80d5af4e97e = []byte{ + // 416 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x52, 0x41, 0x6b, 0x14, 0x31, + 0x14, 0xde, 0x74, 0xab, 0xee, 0xa6, 0xb0, 0xd5, 0xd8, 0xc3, 0x58, 0xe8, 0x74, 0xa8, 0x87, 0x0e, + 0x4a, 0x93, 0x3a, 0xfe, 0x83, 0x16, 0x85, 0x45, 0x4f, 0x41, 0x11, 0x16, 0x21, 0x64, 0x33, 0x71, + 0x1a, 0xba, 0x9b, 0x0c, 0x49, 0xb4, 0xb6, 0x3f, 0xc0, 0xb3, 0xf8, 0xab, 0x7a, 0xec, 0x51, 0x3c, + 0x14, 0xd9, 0xfd, 0x23, 0x92, 0xa4, 0xeb, 0xce, 0xa9, 0x97, 0x99, 0x2f, 0x8f, 0xf7, 0x7d, 0x7c, + 0xdf, 0x7b, 0x0f, 0x3e, 0x17, 0xd6, 0x38, 0x27, 0xce, 0xb8, 0xd2, 0xc4, 0x72, 0x2f, 0xd9, 0x4c, + 0xcd, 0x95, 0x97, 0x96, 0x7d, 0x99, 0xf1, 0xc6, 0xe1, 0xd6, 0x1a, 0x6f, 0xd0, 0xde, 0x95, 0xf4, + 0x3c, 0xf6, 0xe0, 0x88, 0x8c, 0x95, 0x78, 0xcd, 0xdb, 0xdd, 0x69, 0x4c, 0x63, 0x62, 0x27, 0x09, + 0x28, 0x91, 0x76, 0x9f, 0xb6, 0xe7, 0x0d, 0x11, 0x46, 0xe9, 0xf8, 0x49, 0xc5, 0x83, 0x5f, 0x00, + 0x0e, 0x27, 0xf4, 0xb4, 0x3a, 0xa6, 0xdc, 0x4b, 0xf4, 0x0c, 0x0e, 0xa2, 0x02, 0x53, 0x75, 0x06, + 0x0a, 0x50, 0xf6, 0xe9, 0xa3, 0xf8, 0x1e, 0xd7, 0xe8, 0x25, 0x1c, 0x06, 0x1a, 0xf3, 0x97, 0xad, + 0xcc, 0x36, 0x0a, 0x50, 0x8e, 0xaa, 0x11, 0x8e, 0x42, 0xa7, 0x46, 0xe9, 0x0f, 0x97, 0xad, 0xa4, + 0x03, 0x71, 0x87, 0xd0, 0x0e, 0x7c, 0xc0, 0x9d, 0x93, 0x3e, 0xeb, 0x17, 0xa0, 0x1c, 0xd2, 0xf4, + 0x40, 0x87, 0x70, 0x5b, 0x18, 0xfd, 0x4d, 0x5a, 0xa7, 0x8c, 0x66, 0x21, 0x5c, 0xb6, 0x59, 0x80, + 0x12, 0xd0, 0xd1, 0xba, 0x1c, 0x6c, 0x1c, 0xfc, 0xd8, 0x80, 0x8f, 0x03, 0x78, 0x9f, 0xa2, 0xbf, + 0x0d, 0xc9, 0xd1, 0x1e, 0x84, 0xca, 0x31, 0xa9, 0xf9, 0x74, 0x26, 0x93, 0xbb, 0x01, 0x1d, 0x2a, + 0xf7, 0x26, 0x15, 0xd0, 0x0b, 0xf8, 0x64, 0x3d, 0x2e, 0x76, 0xa1, 0x74, 0x6d, 0x2e, 0xa2, 0xcf, + 0x3e, 0xdd, 0xb6, 0x2b, 0xad, 0x4f, 0xb1, 0x8c, 0x3e, 0x43, 0xd4, 0xe9, 0x55, 0x9a, 0x85, 0x21, + 0x26, 0xaf, 0x27, 0xe4, 0xfa, 0x76, 0xbf, 0xf7, 0xe7, 0x76, 0xff, 0xb0, 0x51, 0xfe, 0xec, 0xeb, + 0x14, 0x0b, 0x33, 0x27, 0xc2, 0xb8, 0xb9, 0x71, 0x77, 0xbf, 0x23, 0x57, 0x9f, 0x93, 0x30, 0x05, + 0x87, 0x3f, 0x2a, 0xed, 0x3b, 0xea, 0x63, 0x3d, 0x91, 0x9e, 0xa3, 0x31, 0xdc, 0xba, 0xb2, 0xa2, + 0x3a, 0x8e, 0x09, 0x5d, 0xb6, 0x59, 0xf4, 0xcb, 0xad, 0xaa, 0xc4, 0xf7, 0xae, 0x0c, 0xff, 0xdf, + 0x01, 0x85, 0x91, 0x1c, 0xa0, 0x3b, 0x79, 0x77, 0xbd, 0xc8, 0xc1, 0xcd, 0x22, 0x07, 0x7f, 0x17, + 0x39, 0xf8, 0xb9, 0xcc, 0x7b, 0x37, 0xcb, 0xbc, 0xf7, 0x7b, 0x99, 0xf7, 0x26, 0xaf, 0x3a, 0xf6, + 0x82, 0xde, 0x51, 0xba, 0x98, 0x95, 0x34, 0xf9, 0x4e, 0x3a, 0x77, 0x14, 0xdd, 0x4e, 0x1f, 0xc6, + 0x8d, 0xbf, 0xfe, 0x17, 0x00, 0x00, 0xff, 0xff, 0xba, 0xde, 0xfb, 0xd3, 0x62, 0x02, 0x00, 0x00, +} + +func (m *ZRC20Rate) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ZRC20Rate) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ZRC20Rate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.ConversionRate != 0 { + i -= 8 + encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.ConversionRate)))) + i-- + dAtA[i] = 0x21 + } + if len(m.Asset) > 0 { + i -= len(m.Asset) + copy(dAtA[i:], m.Asset) + i = encodeVarintRateLimiterFlags(dAtA, i, uint64(len(m.Asset))) + i-- + dAtA[i] = 0x1a + } + if m.CoinType != 0 { + i = encodeVarintRateLimiterFlags(dAtA, i, uint64(m.CoinType)) + i-- + dAtA[i] = 0x10 + } + if m.ChainId != 0 { + i = encodeVarintRateLimiterFlags(dAtA, i, uint64(m.ChainId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *RateLimiterFlags) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RateLimiterFlags) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RateLimiterFlags) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Zrc20Rates) > 0 { + for iNdEx := len(m.Zrc20Rates) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Zrc20Rates[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRateLimiterFlags(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + { + size := m.RateLimitInZeta.Size() + i -= size + if _, err := m.RateLimitInZeta.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintRateLimiterFlags(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if m.RateLimitWindow != 0 { + i = encodeVarintRateLimiterFlags(dAtA, i, uint64(m.RateLimitWindow)) + i-- + dAtA[i] = 0x10 + } + if m.IsEnabled { + i-- + if m.IsEnabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintRateLimiterFlags(dAtA []byte, offset int, v uint64) int { + offset -= sovRateLimiterFlags(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ZRC20Rate) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ChainId != 0 { + n += 1 + sovRateLimiterFlags(uint64(m.ChainId)) + } + if m.CoinType != 0 { + n += 1 + sovRateLimiterFlags(uint64(m.CoinType)) + } + l = len(m.Asset) + if l > 0 { + n += 1 + l + sovRateLimiterFlags(uint64(l)) + } + if m.ConversionRate != 0 { + n += 9 + } + return n +} + +func (m *RateLimiterFlags) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.IsEnabled { + n += 2 + } + if m.RateLimitWindow != 0 { + n += 1 + sovRateLimiterFlags(uint64(m.RateLimitWindow)) + } + l = m.RateLimitInZeta.Size() + n += 1 + l + sovRateLimiterFlags(uint64(l)) + if len(m.Zrc20Rates) > 0 { + for _, e := range m.Zrc20Rates { + l = e.Size() + n += 1 + l + sovRateLimiterFlags(uint64(l)) + } + } + return n +} + +func sovRateLimiterFlags(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozRateLimiterFlags(x uint64) (n int) { + return sovRateLimiterFlags(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ZRC20Rate) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRateLimiterFlags + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ZRC20Rate: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ZRC20Rate: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + m.ChainId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRateLimiterFlags + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ChainId |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CoinType", wireType) + } + m.CoinType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRateLimiterFlags + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CoinType |= coin.CoinType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Asset", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRateLimiterFlags + } + 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 ErrInvalidLengthRateLimiterFlags + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRateLimiterFlags + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Asset = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 1 { + return fmt.Errorf("proto: wrong wireType = %d for field ConversionRate", wireType) + } + var v uint64 + if (iNdEx + 8) > l { + return io.ErrUnexpectedEOF + } + v = uint64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:])) + iNdEx += 8 + m.ConversionRate = float64(math.Float64frombits(v)) + default: + iNdEx = preIndex + skippy, err := skipRateLimiterFlags(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRateLimiterFlags + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RateLimiterFlags) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRateLimiterFlags + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RateLimiterFlags: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RateLimiterFlags: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IsEnabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRateLimiterFlags + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IsEnabled = bool(v != 0) + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RateLimitWindow", wireType) + } + m.RateLimitWindow = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRateLimiterFlags + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RateLimitWindow |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RateLimitInZeta", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRateLimiterFlags + } + 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 ErrInvalidLengthRateLimiterFlags + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRateLimiterFlags + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.RateLimitInZeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Zrc20Rates", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRateLimiterFlags + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRateLimiterFlags + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRateLimiterFlags + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Zrc20Rates = append(m.Zrc20Rates, &ZRC20Rate{}) + if err := m.Zrc20Rates[len(m.Zrc20Rates)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRateLimiterFlags(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRateLimiterFlags + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipRateLimiterFlags(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowRateLimiterFlags + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowRateLimiterFlags + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowRateLimiterFlags + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthRateLimiterFlags + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupRateLimiterFlags + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthRateLimiterFlags + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthRateLimiterFlags = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowRateLimiterFlags = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupRateLimiterFlags = fmt.Errorf("proto: unexpected end of group") +) From a873173ecdc96f6e839c515f55593bdb8b33cc65 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Thu, 18 Apr 2024 13:03:52 -0500 Subject: [PATCH 02/33] replace big.Float with sdk.Dec and update mock rate limiter flags --- docs/openapi/openapi.swagger.yaml | 34 ++ proto/crosschain/query.proto | 5 + proto/crosschain/rate_limiter_flags.proto | 32 +- testutil/keeper/mocks/crosschain/fungible.go | 20 + .../crosschain/rate_limiter_flags_pb.d.ts | 77 ++- x/crosschain/keeper/grpc_query_cctx.go | 101 ++-- x/crosschain/keeper/grpc_query_cctx_test.go | 30 ++ x/crosschain/keeper/rate_limiter_flags.go | 55 +-- x/crosschain/types/expected_keepers.go | 1 + x/crosschain/types/query.pb.go | 268 ++++++----- x/crosschain/types/query.pb.gw.go | 83 ++++ x/crosschain/types/rate_limiter_flags.pb.go | 439 ++++++++---------- x/fungible/keeper/foreign_coins.go | 18 + 13 files changed, 685 insertions(+), 478 deletions(-) diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index 1d1042551f..c39cbb7644 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -26608,6 +26608,27 @@ paths: format: int64 tags: - Query + /zeta-chain/crosschain/cctxPendingWithRateLimit: + get: + summary: Queries a list of pending cctxs with rate limit. + operationId: Query_CctxListPendingWithinRateLimit + responses: + "200": + description: A successful response. + schema: + $ref: '#/definitions/crosschainQueryListCctxPendingWithRateLimitResponse' + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/googlerpcStatus' + parameters: + - name: limit + in: query + required: false + type: integer + format: int64 + tags: + - Query /zeta-chain/crosschain/convertGasToZeta: get: operationId: Query_ConvertGasToZeta @@ -53901,6 +53922,19 @@ definitions: totalPending: type: string format: uint64 + crosschainQueryListCctxPendingWithRateLimitResponse: + type: object + properties: + cross_chain_tx: + type: array + items: + type: object + $ref: '#/definitions/crosschainCrossChainTx' + total_pending: + type: string + format: uint64 + rate_limit_exceeded: + type: boolean crosschainQueryMessagePassingProtocolFeeResponse: type: object properties: diff --git a/proto/crosschain/query.proto b/proto/crosschain/query.proto index 5372c9b0c9..89f80247da 100644 --- a/proto/crosschain/query.proto +++ b/proto/crosschain/query.proto @@ -98,6 +98,11 @@ service Query { option (google.api.http).get = "/zeta-chain/crosschain/cctxPending"; } + // Queries a list of pending cctxs with rate limit. + rpc CctxListPendingWithinRateLimit(QueryListCctxPendingWithRateLimitRequest) returns (QueryListCctxPendingWithRateLimitResponse) { + option (google.api.http).get = "/zeta-chain/crosschain/cctxPendingWithRateLimit"; + } + rpc ZetaAccounting(QueryZetaAccountingRequest) returns (QueryZetaAccountingResponse) { option (google.api.http).get = "/zeta-chain/crosschain/zetaAccounting"; } diff --git a/proto/crosschain/rate_limiter_flags.proto b/proto/crosschain/rate_limiter_flags.proto index af9edabcbb..0e8185713b 100644 --- a/proto/crosschain/rate_limiter_flags.proto +++ b/proto/crosschain/rate_limiter_flags.proto @@ -2,25 +2,29 @@ syntax = "proto3"; package zetachain.zetacore.crosschain; import "gogoproto/gogo.proto"; -import "pkg/coin/coin.proto"; option go_package = "github.com/zeta-chain/zetacore/x/crosschain/types"; -// ZRC20Rate defines the conversion rate of ZRC20 to ZETA -message ZRC20Rate { - int64 chain_id = 1; - coin.CoinType coin_type = 2; - string asset = 3; - double conversion_rate = 4; -} - -// RateLimiterFlags defines the outbound rate limiter flags message RateLimiterFlags { - bool is_enabled = 1; - int64 rate_limit_window = 2; - string rate_limit_in_zeta = 3 [ + bool enabled = 1; + + // window in blocks + int64 window = 2; + + // rate in azeta per block + string rate = 3 [ (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Uint", (gogoproto.nullable) = false ]; - repeated ZRC20Rate zrc20_rates = 4; + + // conversion in azeta per token + repeated Conversion conversions = 4 [(gogoproto.nullable) = false]; +} + +message Conversion { + string zrc20 = 1; + string rate = 2 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; } diff --git a/testutil/keeper/mocks/crosschain/fungible.go b/testutil/keeper/mocks/crosschain/fungible.go index 54b7e54a03..f1e624ca9b 100644 --- a/testutil/keeper/mocks/crosschain/fungible.go +++ b/testutil/keeper/mocks/crosschain/fungible.go @@ -254,6 +254,26 @@ func (_m *CrosschainFungibleKeeper) GetAllForeignCoinsForChain(ctx types.Context return r0 } +// GetAllForeignERC20CoinMap provides a mock function with given fields: ctx +func (_m *CrosschainFungibleKeeper) GetAllForeignERC20CoinMap(ctx types.Context) map[int64]map[string]fungibletypes.ForeignCoins { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetAllForeignERC20CoinMap") + } + + var r0 map[int64]map[string]fungibletypes.ForeignCoins + if rf, ok := ret.Get(0).(func(types.Context) map[int64]map[string]fungibletypes.ForeignCoins); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[int64]map[string]fungibletypes.ForeignCoins) + } + } + + return r0 +} + // GetForeignCoinFromAsset provides a mock function with given fields: ctx, asset, chainID func (_m *CrosschainFungibleKeeper) GetForeignCoinFromAsset(ctx types.Context, asset string, chainID int64) (fungibletypes.ForeignCoins, bool) { ret := _m.Called(ctx, asset, chainID) diff --git a/typescript/crosschain/rate_limiter_flags_pb.d.ts b/typescript/crosschain/rate_limiter_flags_pb.d.ts index b95e353e94..02997cd099 100644 --- a/typescript/crosschain/rate_limiter_flags_pb.d.ts +++ b/typescript/crosschain/rate_limiter_flags_pb.d.ts @@ -5,87 +5,78 @@ import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf"; import { Message, proto3 } from "@bufbuild/protobuf"; -import type { CoinType } from "../pkg/coin/coin_pb.js"; /** - * ZRC20Rate defines the conversion rate of ZRC20 to ZETA - * - * @generated from message zetachain.zetacore.crosschain.ZRC20Rate + * @generated from message zetachain.zetacore.crosschain.RateLimiterFlags */ -export declare class ZRC20Rate extends Message { +export declare class RateLimiterFlags extends Message { /** - * @generated from field: int64 chain_id = 1; + * @generated from field: bool enabled = 1; */ - chainId: bigint; + enabled: boolean; /** - * @generated from field: coin.CoinType coin_type = 2; + * window in blocks + * + * @generated from field: int64 window = 2; */ - coinType: CoinType; + window: bigint; /** - * @generated from field: string asset = 3; + * rate in azeta per block + * + * @generated from field: string rate = 3; */ - asset: string; + rate: string; /** - * @generated from field: double conversion_rate = 4; + * conversion in azeta per token + * + * @generated from field: repeated zetachain.zetacore.crosschain.Conversion conversions = 4; */ - conversionRate: number; + conversions: Conversion[]; - constructor(data?: PartialMessage); + constructor(data?: PartialMessage); static readonly runtime: typeof proto3; - static readonly typeName = "zetachain.zetacore.crosschain.ZRC20Rate"; + static readonly typeName = "zetachain.zetacore.crosschain.RateLimiterFlags"; static readonly fields: FieldList; - static fromBinary(bytes: Uint8Array, options?: Partial): ZRC20Rate; + static fromBinary(bytes: Uint8Array, options?: Partial): RateLimiterFlags; - static fromJson(jsonValue: JsonValue, options?: Partial): ZRC20Rate; + static fromJson(jsonValue: JsonValue, options?: Partial): RateLimiterFlags; - static fromJsonString(jsonString: string, options?: Partial): ZRC20Rate; + static fromJsonString(jsonString: string, options?: Partial): RateLimiterFlags; - static equals(a: ZRC20Rate | PlainMessage | undefined, b: ZRC20Rate | PlainMessage | undefined): boolean; + static equals(a: RateLimiterFlags | PlainMessage | undefined, b: RateLimiterFlags | PlainMessage | undefined): boolean; } /** - * RateLimiterFlags defines the outbound rate limiter flags - * - * @generated from message zetachain.zetacore.crosschain.RateLimiterFlags + * @generated from message zetachain.zetacore.crosschain.Conversion */ -export declare class RateLimiterFlags extends Message { - /** - * @generated from field: bool is_enabled = 1; - */ - isEnabled: boolean; - - /** - * @generated from field: int64 rate_limit_window = 2; - */ - rateLimitWindow: bigint; - +export declare class Conversion extends Message { /** - * @generated from field: string rate_limit_in_zeta = 3; + * @generated from field: string zrc20 = 1; */ - rateLimitInZeta: string; + zrc20: string; /** - * @generated from field: repeated zetachain.zetacore.crosschain.ZRC20Rate zrc20_rates = 4; + * @generated from field: string rate = 2; */ - zrc20Rates: ZRC20Rate[]; + rate: string; - constructor(data?: PartialMessage); + constructor(data?: PartialMessage); static readonly runtime: typeof proto3; - static readonly typeName = "zetachain.zetacore.crosschain.RateLimiterFlags"; + static readonly typeName = "zetachain.zetacore.crosschain.Conversion"; static readonly fields: FieldList; - static fromBinary(bytes: Uint8Array, options?: Partial): RateLimiterFlags; + static fromBinary(bytes: Uint8Array, options?: Partial): Conversion; - static fromJson(jsonValue: JsonValue, options?: Partial): RateLimiterFlags; + static fromJson(jsonValue: JsonValue, options?: Partial): Conversion; - static fromJsonString(jsonString: string, options?: Partial): RateLimiterFlags; + static fromJsonString(jsonString: string, options?: Partial): Conversion; - static equals(a: RateLimiterFlags | PlainMessage | undefined, b: RateLimiterFlags | PlainMessage | undefined): boolean; + static equals(a: Conversion | PlainMessage | undefined, b: Conversion | PlainMessage | undefined): boolean; } diff --git a/x/crosschain/keeper/grpc_query_cctx.go b/x/crosschain/keeper/grpc_query_cctx.go index 1fe7d04e24..ac3d2da63a 100644 --- a/x/crosschain/keeper/grpc_query_cctx.go +++ b/x/crosschain/keeper/grpc_query_cctx.go @@ -3,7 +3,6 @@ package keeper import ( "context" "fmt" - "math/big" "strings" "github.com/cosmos/cosmos-sdk/store/prefix" @@ -11,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/query" "github.com/zeta-chain/zetacore/pkg/coin" "github.com/zeta-chain/zetacore/x/crosschain/types" + fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -208,29 +208,32 @@ func (k Keeper) CctxListPendingWithinRateLimit(c context.Context, req *types.Que // check rate limit flags to decide if we should apply rate limit applyLimit := true rateLimitFlags, found := k.GetRatelimiterFlags(ctx) - if !found || !rateLimitFlags.IsEnabled { + if !found || !rateLimitFlags.Enabled { applyLimit = false } // calculate the rate limiter sliding window left boundary (inclusive) - leftWindowBoundary := height - rateLimitFlags.RateLimitWindow + leftWindowBoundary := height - rateLimitFlags.Window if leftWindowBoundary < 0 { leftWindowBoundary = 0 } // get the conversion rates for all foreign coins - var gasCoinRates map[int64]*big.Float - var erc20CoinRates map[string]*big.Float - var rateLimitInZeta *big.Float + var gasCoinRates map[int64]sdk.Dec + var erc20CoinRates map[int64]map[string]sdk.Dec + var erc20Coins map[int64]map[string]fungibletypes.ForeignCoins + var rateLimitInZeta sdk.Dec if applyLimit { gasCoinRates, erc20CoinRates = k.GetRatelimiterRates(ctx) - rateLimitInZeta = new(big.Float).SetInt(rateLimitFlags.RateLimitInZeta.BigInt()) + erc20Coins = k.fungibleKeeper.GetAllForeignERC20CoinMap(ctx) + //rateLimitInZeta = new(big.Float).SetInt(rateLimitFlags.RateLimitInZeta.BigInt()) + rateLimitInZeta = sdk.NewDecFromBigInt(rateLimitFlags.Rate.BigInt()) } // define a few variables to be used in the below loops limitExceeded := false totalPending := uint64(0) - totalCctxValueInZeta := big.NewFloat(0) + totalCctxValueInZeta := sdk.NewDec(0) cctxs := make([]*types.CrossChainTx, 0) // the criteria to stop adding cctxs to the result @@ -243,6 +246,11 @@ func (k Keeper) CctxListPendingWithinRateLimit(c context.Context, req *types.Que chains := k.zetaObserverKeeper.GetSupportedChains(ctx) ChainLoop: for _, chain := range chains { + // skip zeta chain + if chain.IsZetaChain() { + continue + } + // get pending nonces for this chain pendingNonces, found := k.GetObserverKeeper().GetPendingNonces(ctx, tss.TssPubkey, chain.ChainId) if !found { @@ -283,7 +291,7 @@ ChainLoop: break } // criteria #3: if rate limiter is enabled, we should finish the RPC call if the rate limit is exceeded - if rateLimitExceeded(chain.ChainId, &cctx, gasCoinRates, erc20CoinRates, totalCctxValueInZeta, rateLimitInZeta) { + if rateLimitExceeded(chain.ChainId, &cctx, gasCoinRates, erc20CoinRates, erc20Coins, &totalCctxValueInZeta, rateLimitInZeta) { limitExceeded = true break ChainLoop } @@ -315,10 +323,10 @@ ChainLoop: // only take a `limit` number of pending cctxs as result if maxCCTXsReached() { - break + break ChainLoop } // criteria #3: if rate limiter is enabled, we should finish the RPC call if the rate limit is exceeded - if applyLimit && rateLimitExceeded(chain.ChainId, &cctx, gasCoinRates, erc20CoinRates, totalCctxValueInZeta, rateLimitInZeta) { + if applyLimit && rateLimitExceeded(chain.ChainId, &cctx, gasCoinRates, erc20CoinRates, erc20Coins, &totalCctxValueInZeta, rateLimitInZeta) { limitExceeded = true break ChainLoop } @@ -337,32 +345,60 @@ ChainLoop: func convertCctxValue( chainID int64, cctx *types.CrossChainTx, - gasCoinRates map[int64]*big.Float, - erc20CoinRates map[string]*big.Float, -) *big.Float { - var rate *big.Float + gasCoinRates map[int64]sdk.Dec, + erc20CoinRates map[int64]map[string]sdk.Dec, + erc20Coins map[int64]map[string]fungibletypes.ForeignCoins, +) sdk.Dec { + var rate sdk.Dec + var decimals uint64 switch cctx.InboundTxParams.CoinType { case coin.CoinType_Zeta: // no conversion needed for ZETA - rate = big.NewFloat(1.0) + rate = sdk.NewDec(1) case coin.CoinType_Gas: - // convert gas coin amount into ZETA rate = gasCoinRates[chainID] case coin.CoinType_ERC20: - // convert erc20 coin amount into ZETA - rate = erc20CoinRates[strings.ToLower(cctx.InboundTxParams.Asset)] + // get the ERC20 coin decimals + _, found := erc20Coins[chainID] + if !found { + // skip if no coin found for this chainID + return sdk.NewDec(0) + } + fCoin, found := erc20Coins[chainID][strings.ToLower(cctx.InboundTxParams.Asset)] + if !found { + // skip if no coin found for this Asset + return sdk.NewDec(0) + } + // #nosec G701 always in range + decimals = uint64(fCoin.Decimals) + + // get the ERC20 coin rate + _, found = erc20CoinRates[chainID] + if !found { + // skip if no rate found for this chainID + return sdk.NewDec(0) + } + rate = erc20CoinRates[chainID][strings.ToLower(cctx.InboundTxParams.Asset)] default: // skip CoinType_Cmd - return big.NewFloat(0) + return sdk.NewDec(0) } - if rate == nil || rate.Cmp(big.NewFloat(0)) == 0 { - // should not happen, return 0 to skip this cctx - return big.NewFloat(0) + + // should not happen, return 0 to skip if it happens + if rate.LTE(sdk.NewDec(0)) { + return sdk.NewDec(0) } + // calculate the reciprocal of `rate` as the amount of zrc20 needed to buy 1 ZETA + // for example, given rate = 0.8, the reciprocal is 1.25, which means 1.25 ZRC20 can buy 1 ZETA + // given decimals = 6, below calculation is equivalent to 1,000,000 / 1.25 = 800,000 + // which means 800,000 ZRC20 can buy 1 ZETA + oneZrc20 := sdk.NewDec(1).Power(decimals) + oneZeta := oneZrc20.Quo(rate) + // convert asset amount into ZETA - amountCctx := new(big.Float).SetInt(cctx.InboundTxParams.Amount.BigInt()) - amountZeta := new(big.Float).Mul(amountCctx, rate) + amountCctx := sdk.NewDecFromBigInt(cctx.InboundTxParams.Amount.BigInt()) + amountZeta := amountCctx.Quo(oneZeta) return amountZeta } @@ -371,12 +407,13 @@ func convertCctxValue( func rateLimitExceeded( chainID int64, cctx *types.CrossChainTx, - gasCoinRates map[int64]*big.Float, - erc20CoinRates map[string]*big.Float, - currentCctxValue *big.Float, - rateLimitValue *big.Float, + gasCoinRates map[int64]sdk.Dec, + erc20CoinRates map[int64]map[string]sdk.Dec, + erc20Coins map[int64]map[string]fungibletypes.ForeignCoins, + currentCctxValue *sdk.Dec, + rateLimitValue sdk.Dec, ) bool { - amountZeta := convertCctxValue(chainID, cctx, gasCoinRates, erc20CoinRates) - currentCctxValue.Add(currentCctxValue, amountZeta) - return currentCctxValue.Cmp(rateLimitValue) > 0 + amountZeta := convertCctxValue(chainID, cctx, gasCoinRates, erc20CoinRates, erc20Coins) + *currentCctxValue = currentCctxValue.Add(amountZeta) + return currentCctxValue.GT(rateLimitValue) } diff --git a/x/crosschain/keeper/grpc_query_cctx_test.go b/x/crosschain/keeper/grpc_query_cctx_test.go index 59b0b68863..883315c0a0 100644 --- a/x/crosschain/keeper/grpc_query_cctx_test.go +++ b/x/crosschain/keeper/grpc_query_cctx_test.go @@ -185,6 +185,36 @@ func TestKeeper_CctxListPending(t *testing.T) { }) } +func TestKeeper_CctxListPendingWithRateLimit(t *testing.T) { + t.Run("should fail for empty req", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + _, err := k.CctxListPendingWithinRateLimit(ctx, nil) + require.ErrorContains(t, err, "invalid request") + }) + + t.Run("should fail if limit is too high", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + _, err := k.CctxListPendingWithinRateLimit(ctx, &types.QueryListCctxPendingWithRateLimitRequest{Limit: keeper.MaxPendingCctxs + 1}) + require.ErrorContains(t, err, "limit exceeds max limit of") + }) + + t.Run("should fail if no TSS", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + _, err := k.CctxListPendingWithinRateLimit(ctx, &types.QueryListCctxPendingWithRateLimitRequest{Limit: 1}) + require.ErrorContains(t, err, "tss not found") + }) + + t.Run("should return empty list if no nonces", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + + // set TSS + zk.ObserverKeeper.SetTSS(ctx, sample.Tss()) + + _, err := k.CctxListPendingWithinRateLimit(ctx, &types.QueryListCctxPendingWithRateLimitRequest{Limit: 1}) + require.ErrorContains(t, err, "pending nonces not found") + }) +} + func TestKeeper_ZetaAccounting(t *testing.T) { t.Run("should error if zeta accounting not found", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) diff --git a/x/crosschain/keeper/rate_limiter_flags.go b/x/crosschain/keeper/rate_limiter_flags.go index f5cd88cb99..6af2908d6f 100644 --- a/x/crosschain/keeper/rate_limiter_flags.go +++ b/x/crosschain/keeper/rate_limiter_flags.go @@ -1,43 +1,36 @@ package keeper import ( - "math/big" "strings" "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/pkg/coin" "github.com/zeta-chain/zetacore/x/crosschain/types" ) // hardcoded rate limiter flags var rateLimitFlags = types.RateLimiterFlags{ - IsEnabled: true, - RateLimitWindow: 1200, // 1200 zeta blocks, 2 hours - RateLimitInZeta: math.NewUint(2000000), // 2,000,000 ZETA - Zrc20Rates: []*types.ZRC20Rate{ + Enabled: true, + Window: 100, // 100 zeta blocks, 10 minutes + Rate: math.NewUint(2000000), // 2000 ZETA + Conversions: []types.Conversion{ // ETH { - ChainId: chains.GoerliLocalnetChain().ChainId, - CoinType: coin.CoinType_Gas, - Asset: "", - ConversionRate: 2500, + Zrc20: "0x13A0c5930C028511Dc02665E7285134B6d11A5f4", + Rate: sdk.NewDec(2500), }, // USDT { - ChainId: chains.GoerliLocalnetChain().ChainId, - CoinType: coin.CoinType_ERC20, - Asset: "0xbD1e64A22B9F92D9Ce81aA9B4b0fFacd80215564", - ConversionRate: 0.8, + Zrc20: "0xbD1e64A22B9F92D9Ce81aA9B4b0fFacd80215564", + Rate: sdk.MustNewDecFromStr("0.8"), + //sdk.NewDec(0.8), }, // BTC { - ChainId: chains.BtcRegtestChain().ChainId, - CoinType: coin.CoinType_ERC20, - Asset: "0x8f56682c2b8b2e3d4f6f7f7d6f3c01b3f6f6a7d6", - ConversionRate: 50000, + Zrc20: "0x8f56682c2b8b2e3d4f6f7f7d6f3c01b3f6f6a7d6", + Rate: sdk.NewDec(50000), }, }, } @@ -65,22 +58,30 @@ func (k Keeper) GetRatelimiterFlags(_ sdk.Context) (val types.RateLimiterFlags, // GetRatelimiterRates returns two maps of foreign coins and their rates // The 1st map: foreign chain id -> gas coin rate -// The 2nd map: foreign erc20 asset -> erc20 coin rate -func (k Keeper) GetRatelimiterRates(ctx sdk.Context) (map[int64]*big.Float, map[string]*big.Float) { +// The 2nd map: foreign chain id -> erc20 asset -> erc20 coin rate +func (k Keeper) GetRatelimiterRates(ctx sdk.Context) (map[int64]sdk.Dec, map[int64]map[string]sdk.Dec) { rateLimitFlags, _ := k.GetRatelimiterFlags(ctx) // the result maps - gasCoinRates := make(map[int64]*big.Float) - erc20CoinRates := make(map[string]*big.Float) + gasCoinRates := make(map[int64]sdk.Dec) + erc20CoinRates := make(map[int64]map[string]sdk.Dec) // loop through the rate limiter flags to get the rate - for _, zrc20Rate := range rateLimitFlags.Zrc20Rates { - rate := big.NewFloat(zrc20Rate.ConversionRate) - switch zrc20Rate.CoinType { + for _, conversion := range rateLimitFlags.Conversions { + fCoin, found := k.fungibleKeeper.GetForeignCoins(ctx, conversion.Zrc20) + if !found { + continue + } + + chainID := fCoin.ForeignChainId + switch fCoin.CoinType { case coin.CoinType_Gas: - gasCoinRates[zrc20Rate.ChainId] = rate + gasCoinRates[chainID] = conversion.Rate case coin.CoinType_ERC20: - erc20CoinRates[strings.ToLower(zrc20Rate.Asset)] = rate + if _, found := erc20CoinRates[chainID]; !found { + erc20CoinRates[chainID] = make(map[string]sdk.Dec) + } + erc20CoinRates[chainID][strings.ToLower(fCoin.Asset)] = conversion.Rate } } return gasCoinRates, erc20CoinRates diff --git a/x/crosschain/types/expected_keepers.go b/x/crosschain/types/expected_keepers.go index c985a01915..2e02f3bb32 100644 --- a/x/crosschain/types/expected_keepers.go +++ b/x/crosschain/types/expected_keepers.go @@ -96,6 +96,7 @@ type ObserverKeeper interface { type FungibleKeeper interface { GetForeignCoins(ctx sdk.Context, zrc20Addr string) (val fungibletypes.ForeignCoins, found bool) GetAllForeignCoins(ctx sdk.Context) (list []fungibletypes.ForeignCoins) + GetAllForeignERC20CoinMap(ctx sdk.Context) map[int64]map[string]fungibletypes.ForeignCoins SetForeignCoins(ctx sdk.Context, foreignCoins fungibletypes.ForeignCoins) GetAllForeignCoinsForChain(ctx sdk.Context, foreignChainID int64) (list []fungibletypes.ForeignCoins) GetForeignCoinFromAsset(ctx sdk.Context, asset string, chainID int64) (fungibletypes.ForeignCoins, bool) diff --git a/x/crosschain/types/query.pb.go b/x/crosschain/types/query.pb.go index 0a8a73f0e4..a5c1d6db31 100644 --- a/x/crosschain/types/query.pb.go +++ b/x/crosschain/types/query.pb.go @@ -2018,120 +2018,122 @@ func init() { func init() { proto.RegisterFile("crosschain/query.proto", fileDescriptor_65a992045e92a606) } var fileDescriptor_65a992045e92a606 = []byte{ - // 1797 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x59, 0x41, 0x6f, 0x14, 0xc7, - 0x12, 0x76, 0x7b, 0x31, 0x98, 0xb6, 0xc1, 0xcf, 0x8d, 0x1f, 0xcf, 0x6f, 0xb1, 0xd7, 0x30, 0x7e, - 0x60, 0x03, 0xcf, 0xbb, 0x60, 0xc0, 0x3c, 0xc0, 0x3c, 0xb1, 0x36, 0x60, 0x50, 0x0c, 0x98, 0x95, - 0x23, 0x22, 0xa2, 0x68, 0xd4, 0x9e, 0xed, 0xcc, 0x8e, 0x18, 0xcf, 0x98, 0x9d, 0x59, 0xb4, 0xc6, - 0xf2, 0x85, 0x43, 0xce, 0x91, 0x38, 0xe4, 0x92, 0x6b, 0x94, 0x1c, 0x72, 0xc8, 0x21, 0x4a, 0x0e, - 0x91, 0x88, 0xa2, 0x24, 0x84, 0x23, 0x12, 0x52, 0x14, 0x25, 0x52, 0x14, 0x41, 0x7e, 0x41, 0x7e, - 0x41, 0x34, 0x3d, 0x35, 0xbb, 0x3d, 0xb3, 0x33, 0xbb, 0xed, 0xf5, 0x72, 0xe0, 0xe4, 0x9d, 0xe9, - 0xae, 0xea, 0xef, 0xab, 0xaa, 0xa9, 0xae, 0x2a, 0xe3, 0xfd, 0x5a, 0xd9, 0x76, 0x1c, 0xad, 0x44, - 0x0d, 0x2b, 0x77, 0xbf, 0xc2, 0xca, 0xeb, 0xd9, 0xb5, 0xb2, 0xed, 0xda, 0x64, 0xf4, 0x21, 0x73, - 0x29, 0x7f, 0x9d, 0xe5, 0xbf, 0xec, 0x32, 0xcb, 0xd6, 0xb7, 0xa6, 0x8f, 0x69, 0xb6, 0xb3, 0x6a, - 0x3b, 0xb9, 0x15, 0xea, 0x30, 0x5f, 0x2e, 0xf7, 0xe0, 0xe4, 0x0a, 0x73, 0xe9, 0xc9, 0xdc, 0x1a, - 0xd5, 0x0d, 0x8b, 0xba, 0x86, 0x6d, 0xf9, 0xaa, 0xd2, 0x63, 0xc2, 0x11, 0xfc, 0xa7, 0xca, 0x7f, - 0xab, 0x6e, 0x15, 0x36, 0xa4, 0x85, 0x0d, 0x3a, 0x75, 0xd4, 0xb5, 0xb2, 0xa1, 0x31, 0x58, 0x1b, - 0x17, 0xd6, 0xb8, 0x8c, 0x5a, 0xa2, 0x4e, 0x49, 0x75, 0x6d, 0x55, 0xd3, 0x6a, 0x0a, 0x32, 0x0d, - 0x9b, 0xdc, 0x32, 0xd5, 0xee, 0xb1, 0x32, 0xac, 0x2b, 0xc2, 0xba, 0x49, 0x1d, 0x57, 0x5d, 0x31, - 0x6d, 0xed, 0x9e, 0x5a, 0x62, 0x86, 0x5e, 0x72, 0x63, 0x50, 0xda, 0x15, 0xb7, 0x51, 0xc9, 0x90, - 0x6e, 0xeb, 0x36, 0xff, 0x99, 0xf3, 0x7e, 0xc1, 0xdb, 0x11, 0xdd, 0xb6, 0x75, 0x93, 0xe5, 0xe8, - 0x9a, 0x91, 0xa3, 0x96, 0x65, 0xbb, 0x9c, 0xb9, 0xe3, 0xaf, 0x2a, 0x23, 0x38, 0x7d, 0xdb, 0x33, - 0xce, 0x5d, 0xe6, 0xd2, 0xbc, 0xa6, 0xd9, 0x15, 0xcb, 0x35, 0x2c, 0xbd, 0xc0, 0xee, 0x57, 0x98, - 0xe3, 0x2a, 0x37, 0xf0, 0x81, 0xd8, 0x55, 0x67, 0xcd, 0xb6, 0x1c, 0x46, 0xb2, 0x78, 0x1f, 0x5d, - 0xb1, 0xcb, 0x2e, 0x2b, 0xaa, 0x9e, 0x0b, 0x54, 0xba, 0xea, 0xed, 0x18, 0x46, 0x07, 0xd1, 0xe4, - 0xee, 0xc2, 0x20, 0x2c, 0x71, 0x59, 0xbe, 0x50, 0x53, 0xb7, 0xc0, 0xdc, 0x5b, 0x15, 0x77, 0xb9, - 0xba, 0xec, 0xc3, 0x87, 0xd3, 0xc8, 0x30, 0xde, 0xc5, 0xd9, 0x5d, 0xbf, 0xcc, 0x55, 0xa4, 0x0a, - 0xc1, 0x23, 0x19, 0xc2, 0x3d, 0x96, 0x6d, 0x69, 0x6c, 0xb8, 0xfb, 0x20, 0x9a, 0xdc, 0x51, 0xf0, - 0x1f, 0x94, 0x0a, 0x1e, 0x89, 0x57, 0x07, 0xf0, 0xde, 0xc6, 0xfd, 0xb6, 0xf0, 0x9e, 0x2b, 0xed, - 0x9b, 0x3e, 0x9e, 0x6d, 0x1a, 0x38, 0x59, 0x51, 0xd5, 0xdc, 0x8e, 0x67, 0xbf, 0x8f, 0x75, 0x15, - 0x42, 0x6a, 0x14, 0x06, 0x2c, 0xf2, 0xa6, 0x19, 0xc7, 0xe2, 0x2a, 0xc6, 0xf5, 0x00, 0x83, 0x33, - 0x8f, 0x64, 0xfd, 0x68, 0xcc, 0x7a, 0xd1, 0x98, 0xf5, 0xa3, 0x18, 0xa2, 0x31, 0xbb, 0x44, 0x75, - 0x06, 0xb2, 0x05, 0x41, 0x52, 0x79, 0x82, 0x80, 0x5e, 0xc3, 0x39, 0x89, 0xf4, 0x52, 0x1d, 0xa0, - 0x47, 0x16, 0x42, 0xf8, 0xbb, 0x39, 0xfe, 0x89, 0x96, 0xf8, 0x7d, 0x4c, 0x21, 0x02, 0x8f, 0x10, - 0x56, 0xe2, 0x08, 0xcc, 0xad, 0xcf, 0x7b, 0x48, 0x02, 0x7b, 0x0d, 0xe1, 0x1e, 0x8e, 0x0c, 0x7c, - 0xee, 0x3f, 0x44, 0xac, 0xd8, 0xdd, 0xb6, 0x15, 0x7f, 0x44, 0x78, 0xbc, 0x29, 0x88, 0x37, 0xc4, - 0x98, 0x1f, 0x20, 0x7c, 0x28, 0xe0, 0x71, 0xdd, 0x4a, 0xb2, 0xe5, 0xbf, 0x71, 0xaf, 0x9f, 0xb9, - 0x8c, 0x62, 0xf8, 0x13, 0x2a, 0x76, 0xcc, 0xa0, 0xdf, 0x09, 0x5e, 0x8d, 0x03, 0x02, 0xf6, 0x2c, - 0xe0, 0x3e, 0xc3, 0x8a, 0x9a, 0xf3, 0x58, 0x0b, 0x73, 0x8a, 0xfa, 0x7c, 0x6b, 0x8a, 0x4a, 0x3a, - 0x67, 0x4c, 0xe1, 0x0b, 0x16, 0x8e, 0x74, 0x3a, 0xfd, 0x05, 0x7f, 0x23, 0x7c, 0xc1, 0xe1, 0x73, - 0xde, 0x04, 0x23, 0x5d, 0xc0, 0xa3, 0x41, 0x76, 0xf5, 0x8e, 0xbc, 0x46, 0x9d, 0xd2, 0xb2, 0x3d, - 0xaf, 0xb9, 0xd5, 0xc0, 0x4c, 0x69, 0xdc, 0x6b, 0xc0, 0x02, 0xa4, 0xfc, 0xda, 0xb3, 0xb2, 0x89, - 0x33, 0x49, 0xc2, 0xc0, 0xfd, 0x5d, 0xbc, 0xd7, 0x08, 0xad, 0x80, 0xa1, 0xa7, 0x24, 0xe8, 0xd7, - 0x85, 0xc0, 0x02, 0x11, 0x55, 0xca, 0x2c, 0x1c, 0x1f, 0xde, 0x7c, 0x99, 0xba, 0x54, 0x06, 0xfc, - 0x43, 0x3c, 0x96, 0x28, 0x0d, 0xe8, 0xef, 0xe0, 0x3d, 0xf3, 0x1e, 0x26, 0x1e, 0xf4, 0xcb, 0x55, - 0x47, 0x32, 0x5f, 0x88, 0x32, 0x00, 0x3d, 0xac, 0x47, 0xd1, 0xc1, 0xea, 0x10, 0x32, 0x8d, 0x56, - 0xef, 0x54, 0x70, 0x3e, 0x45, 0x60, 0xa3, 0x98, 0x93, 0x9a, 0xb8, 0x28, 0xd5, 0x21, 0x17, 0x75, - 0x2e, 0x4e, 0x73, 0xf8, 0x5f, 0x41, 0xa8, 0x2d, 0x50, 0x67, 0xc9, 0xab, 0xcc, 0x84, 0xab, 0xc5, - 0xb0, 0x8a, 0xac, 0x0a, 0x1e, 0xf6, 0x1f, 0x14, 0x15, 0x0f, 0x37, 0x0a, 0x00, 0xe5, 0x79, 0xdc, - 0x1b, 0xbc, 0x03, 0xdb, 0x4e, 0xb4, 0x20, 0x5b, 0x53, 0x51, 0x13, 0x54, 0x28, 0x20, 0xca, 0x9b, - 0x66, 0x14, 0x51, 0xa7, 0xbc, 0xf7, 0x19, 0x02, 0x12, 0xa1, 0x33, 0x62, 0x49, 0xa4, 0xda, 0x22, - 0xd1, 0x39, 0xff, 0xcc, 0xd4, 0x53, 0xc1, 0x22, 0x75, 0xdc, 0x39, 0xaf, 0xb0, 0xbd, 0xc6, 0xeb, - 0xda, 0xe6, 0x6e, 0xda, 0x80, 0xaf, 0x30, 0x4e, 0x0e, 0x88, 0xbe, 0x83, 0x07, 0x22, 0x4b, 0x60, - 0xd2, 0x6c, 0x0b, 0xbe, 0x51, 0x85, 0x51, 0x35, 0x4a, 0xa9, 0xfe, 0x71, 0x24, 0x80, 0xee, 0x94, - 0x27, 0x7f, 0x40, 0xc0, 0x33, 0xee, 0xa8, 0x66, 0x3c, 0x53, 0x1d, 0xe0, 0xd9, 0x39, 0x2f, 0x1f, - 0xc7, 0xfb, 0x02, 0x6f, 0x89, 0xd9, 0x2a, 0xde, 0xb5, 0x8b, 0xd0, 0x74, 0xc0, 0xe6, 0xb9, 0xf5, - 0x9b, 0x5e, 0x3d, 0xdf, 0x6e, 0x1b, 0xa0, 0xe3, 0xa1, 0xf0, 0xd1, 0x60, 0xb5, 0x5b, 0xb8, 0x5f, - 0xcc, 0xad, 0x92, 0xe5, 0xbf, 0x28, 0x52, 0x08, 0x29, 0x50, 0xde, 0x03, 0x8e, 0x79, 0xd3, 0x7c, - 0x1d, 0x19, 0xf9, 0x0b, 0x04, 0x44, 0x6a, 0xfa, 0x13, 0x89, 0xa4, 0xb6, 0x45, 0xa4, 0x73, 0x5e, - 0xbf, 0x09, 0x85, 0xd4, 0xa2, 0xe1, 0x70, 0xdb, 0x2f, 0x31, 0xab, 0x58, 0x6f, 0x1f, 0x9b, 0x95, - 0xa3, 0x43, 0xb8, 0xc7, 0x34, 0x56, 0x0d, 0x97, 0x9f, 0xbe, 0xa7, 0xe0, 0x3f, 0x28, 0x8f, 0x83, - 0x8a, 0xa9, 0x41, 0xe1, 0xeb, 0x32, 0x85, 0x82, 0xfb, 0x5d, 0xdb, 0xa5, 0x26, 0x1c, 0x04, 0x91, - 0x15, 0x7a, 0xa7, 0x5c, 0xc2, 0x93, 0x71, 0xa0, 0xee, 0x18, 0x6e, 0xa9, 0x40, 0x5d, 0xb6, 0xe8, - 0x41, 0x17, 0x02, 0x3e, 0x86, 0xd7, 0x0b, 0x84, 0x8f, 0x4a, 0xa8, 0x00, 0x92, 0xb7, 0xf1, 0xde, - 0xf0, 0x14, 0xa2, 0x2d, 0x9a, 0x9a, 0x48, 0x73, 0x1c, 0xef, 0xe1, 0x94, 0xd4, 0xb5, 0x64, 0x9e, - 0x5e, 0x3b, 0x5f, 0xa6, 0x2e, 0x53, 0x39, 0x66, 0x95, 0x55, 0x35, 0xc6, 0x8a, 0xac, 0x38, 0x9c, - 0x3a, 0x88, 0x26, 0x7b, 0x0b, 0x83, 0xe5, 0x00, 0xe7, 0x15, 0x58, 0xa8, 0xcd, 0x0e, 0xbc, 0xa4, - 0xe2, 0x75, 0xf9, 0xa1, 0x04, 0xa9, 0x9c, 0x09, 0x62, 0x23, 0xb2, 0x0a, 0x24, 0xf7, 0xe3, 0x9d, - 0x42, 0xca, 0x4e, 0x15, 0xe0, 0x49, 0x59, 0x86, 0x08, 0x98, 0xb7, 0xad, 0x07, 0xac, 0xec, 0xdd, - 0xd0, 0xcb, 0xb6, 0x27, 0xde, 0x90, 0x1d, 0x1a, 0x42, 0x2a, 0x8d, 0x7b, 0x75, 0xea, 0x2c, 0xd6, - 0xac, 0xbf, 0xbb, 0x50, 0x7b, 0x56, 0x3e, 0x41, 0x50, 0x57, 0x35, 0xaa, 0x05, 0x3c, 0xff, 0xc5, - 0x83, 0x76, 0xc5, 0x5d, 0xb1, 0x2b, 0x56, 0x71, 0x81, 0x3a, 0xd7, 0x2d, 0x6f, 0x31, 0x98, 0x64, - 0x34, 0x2c, 0x78, 0xbb, 0xf9, 0xfc, 0x44, 0xb3, 0xcd, 0xab, 0x8c, 0xc1, 0x6e, 0xff, 0xd0, 0xc6, - 0x05, 0x32, 0x89, 0x07, 0xbc, 0xbf, 0x62, 0xfe, 0x4e, 0x71, 0xfb, 0x47, 0x5f, 0x2b, 0x13, 0xf8, - 0x30, 0x87, 0x79, 0x83, 0x39, 0x0e, 0xd5, 0xd9, 0x12, 0x75, 0x1c, 0xc3, 0xd2, 0x97, 0xea, 0x1a, - 0x03, 0xeb, 0x5e, 0xc5, 0x47, 0x5a, 0x6d, 0x04, 0x62, 0x23, 0x78, 0xf7, 0xfb, 0x35, 0x88, 0x3e, - 0xa1, 0xfa, 0x8b, 0xe9, 0xbf, 0x46, 0x71, 0x0f, 0x57, 0x44, 0x9e, 0x22, 0xdc, 0x2f, 0xf6, 0xb3, - 0xe4, 0x7c, 0x8b, 0x70, 0x6b, 0x32, 0xca, 0x49, 0x5f, 0x68, 0x4b, 0xd6, 0x47, 0xac, 0x5c, 0x7c, - 0xf4, 0xe2, 0xcf, 0xc7, 0xdd, 0x67, 0xc9, 0x99, 0x9c, 0x27, 0x3a, 0x25, 0xcc, 0xe5, 0x6a, 0xc3, - 0xaf, 0x9a, 0x50, 0x6e, 0x03, 0x2e, 0x87, 0xcd, 0xdc, 0x06, 0xbf, 0x0e, 0x36, 0xc9, 0xd7, 0x08, - 0x0f, 0x88, 0x7a, 0xf3, 0xa6, 0x29, 0xc7, 0x25, 0x7e, 0xa0, 0x23, 0xc7, 0x25, 0x61, 0x48, 0xa3, - 0x1c, 0xe7, 0x5c, 0x0e, 0x93, 0x71, 0x09, 0x2e, 0xe4, 0x37, 0x84, 0xf7, 0x47, 0x90, 0x43, 0x5f, - 0x4d, 0xf2, 0x6d, 0x80, 0x08, 0x0f, 0x07, 0xd2, 0x73, 0xdb, 0x51, 0x01, 0x74, 0xce, 0x73, 0x3a, - 0xa7, 0xc9, 0xb4, 0x04, 0x1d, 0x90, 0x05, 0x0f, 0x6d, 0x92, 0x5f, 0x11, 0xfe, 0xa7, 0xd0, 0xbc, - 0x0a, 0xe4, 0x2e, 0x49, 0x22, 0x4b, 0x1c, 0x7c, 0xa4, 0xf3, 0xdb, 0xd0, 0x00, 0xd4, 0x66, 0x39, - 0xb5, 0x19, 0x72, 0x3a, 0x81, 0x9a, 0x61, 0x25, 0x30, 0x53, 0x8d, 0xe2, 0x26, 0xf9, 0x0a, 0xe1, - 0xbd, 0x61, 0x72, 0xd2, 0x31, 0x17, 0x33, 0x82, 0x90, 0x8e, 0xb9, 0xb8, 0xb1, 0x42, 0xcb, 0x98, - 0x13, 0x98, 0x38, 0xe4, 0x27, 0x00, 0x2e, 0xb4, 0x66, 0xb3, 0x92, 0x1f, 0x6f, 0x6c, 0x83, 0x9a, - 0xbe, 0xd8, 0xa6, 0x34, 0x80, 0xff, 0x1f, 0x07, 0x3f, 0x4d, 0x4e, 0x34, 0x01, 0x5f, 0x17, 0xcb, - 0x6d, 0x04, 0xcf, 0x9b, 0xe4, 0x67, 0x84, 0x49, 0x63, 0xcb, 0x4e, 0xa4, 0xf0, 0x24, 0x0e, 0x0a, - 0xd2, 0xff, 0x6f, 0x57, 0x1c, 0xf8, 0xe4, 0x39, 0x9f, 0x0b, 0xe4, 0x5c, 0x22, 0x9f, 0xe8, 0xbf, - 0x0c, 0xd4, 0x22, 0x75, 0xa9, 0x48, 0xec, 0x5b, 0x84, 0x07, 0xc3, 0x27, 0x78, 0xe1, 0x35, 0xbb, - 0x85, 0x10, 0x69, 0xd3, 0x4b, 0x89, 0xa3, 0x01, 0x65, 0x8a, 0xb3, 0x9a, 0x20, 0x87, 0xa5, 0xbc, - 0x44, 0x3e, 0x47, 0xf5, 0x96, 0x94, 0xcc, 0x48, 0x06, 0x48, 0xa4, 0x77, 0x4e, 0x9f, 0xdd, 0xb2, - 0x1c, 0x80, 0xcd, 0x71, 0xb0, 0x47, 0xc9, 0x44, 0x02, 0x58, 0x1d, 0x04, 0x3c, 0x9b, 0x17, 0x59, - 0x75, 0x93, 0x7c, 0x8a, 0x70, 0x5f, 0xa0, 0xc5, 0x33, 0xf5, 0x8c, 0xa4, 0xb1, 0xda, 0x42, 0x1c, - 0xd3, 0xc1, 0x2b, 0x13, 0x1c, 0xf1, 0x21, 0x32, 0xd6, 0x02, 0x31, 0x79, 0x82, 0xf0, 0x3f, 0xa2, - 0x25, 0x0d, 0x91, 0x4a, 0x1e, 0x09, 0xf5, 0x55, 0x7a, 0xb6, 0x3d, 0x61, 0x49, 0x53, 0x6b, 0x51, - 0xac, 0x4f, 0x11, 0xee, 0x13, 0xaa, 0x16, 0x72, 0x59, 0xe6, 0xf8, 0x56, 0xd5, 0x51, 0xfa, 0xca, - 0x36, 0xb5, 0x00, 0x9b, 0x63, 0x9c, 0xcd, 0x7f, 0x88, 0x92, 0xc0, 0x46, 0xa8, 0xf4, 0xc8, 0x33, - 0xd4, 0xd0, 0xa4, 0x13, 0xd9, 0x54, 0x18, 0x3f, 0x62, 0x90, 0x4b, 0x3d, 0xc9, 0xe3, 0x11, 0x65, - 0x86, 0xc3, 0x3f, 0x41, 0xb2, 0x09, 0xf0, 0xcd, 0xb0, 0x5c, 0x2d, 0xfc, 0xbf, 0x47, 0x98, 0x44, - 0x74, 0x7a, 0x5f, 0x81, 0x6c, 0xca, 0xd8, 0x0e, 0x9b, 0xe4, 0x21, 0x88, 0x92, 0xe5, 0x6c, 0x26, - 0xc9, 0x11, 0x39, 0x36, 0xe4, 0x63, 0x84, 0x77, 0xf0, 0xe4, 0x33, 0x2d, 0x69, 0x46, 0x31, 0x3d, - 0x9e, 0xda, 0x92, 0x8c, 0xe4, 0xbd, 0xab, 0xc1, 0x85, 0xc5, 0x8d, 0xfc, 0x25, 0xc2, 0x7d, 0xc2, - 0xf0, 0x83, 0x9c, 0xdb, 0xc2, 0x89, 0xe1, 0x81, 0x49, 0x7b, 0x60, 0xcf, 0x70, 0xb0, 0x39, 0x32, - 0xd5, 0x14, 0x6c, 0x43, 0x71, 0xfd, 0x11, 0xc2, 0xbb, 0x82, 0x1b, 0x68, 0x5a, 0xd2, 0xa3, 0x5b, - 0x36, 0x6c, 0x64, 0x00, 0xa2, 0x8c, 0x73, 0xac, 0xa3, 0xe4, 0x40, 0x13, 0xac, 0x5e, 0x05, 0x36, - 0xe0, 0x49, 0x79, 0x2d, 0x76, 0xd0, 0xd1, 0x4a, 0x95, 0x60, 0xf1, 0xc3, 0x0b, 0xb9, 0x12, 0x2c, - 0x61, 0x4e, 0xd1, 0x32, 0x73, 0x68, 0x75, 0x19, 0x5e, 0x3a, 0x86, 0xff, 0xc1, 0x2e, 0x17, 0x0c, - 0xb1, 0xff, 0xb2, 0x4f, 0x9f, 0x6f, 0x47, 0x54, 0xf2, 0x56, 0x7f, 0x18, 0x46, 0xe9, 0x01, 0x0f, - 0x77, 0xf7, 0x72, 0xc0, 0x63, 0xe7, 0x05, 0x72, 0xc0, 0xe3, 0x87, 0x09, 0x2d, 0x81, 0x9b, 0x21, - 0xb1, 0xb9, 0xb7, 0x9e, 0xbd, 0xcc, 0xa0, 0xe7, 0x2f, 0x33, 0xe8, 0x8f, 0x97, 0x19, 0xf4, 0xe1, - 0xab, 0x4c, 0xd7, 0xf3, 0x57, 0x99, 0xae, 0x5f, 0x5e, 0x65, 0xba, 0xee, 0x9e, 0xd4, 0x0d, 0xb7, - 0x54, 0x59, 0xc9, 0x6a, 0xf6, 0xaa, 0xa8, 0x2a, 0xc0, 0x93, 0xab, 0x8a, 0x5a, 0xdd, 0xf5, 0x35, - 0xe6, 0xac, 0xec, 0xe4, 0xb7, 0xc0, 0xa9, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0x68, 0x29, 0xb5, - 0x4c, 0xa8, 0x22, 0x00, 0x00, + // 1833 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5a, 0x41, 0x6f, 0xd4, 0xd6, + 0x16, 0xce, 0xcd, 0x10, 0x08, 0x37, 0x81, 0xbc, 0x5c, 0xf2, 0x78, 0x79, 0x26, 0x4c, 0xc0, 0x79, + 0x90, 0x00, 0x2f, 0x63, 0x12, 0x20, 0x3c, 0x20, 0x3c, 0x31, 0x09, 0x10, 0xd0, 0x0b, 0x10, 0x46, + 0x79, 0xa2, 0xa2, 0xaa, 0x2c, 0xc7, 0x73, 0xeb, 0xb1, 0x70, 0xec, 0x30, 0xf6, 0xa0, 0x09, 0x51, + 0x36, 0x2c, 0xba, 0xae, 0xc4, 0xa2, 0x9b, 0x6e, 0xab, 0x76, 0xd1, 0x45, 0x17, 0x55, 0xbb, 0xa8, + 0x44, 0x55, 0xb5, 0xa5, 0x2c, 0x91, 0x90, 0xaa, 0xaa, 0x95, 0xaa, 0x16, 0xba, 0xec, 0x8f, 0xa8, + 0x7c, 0x7d, 0x3c, 0x73, 0xed, 0xb1, 0x67, 0x6e, 0x26, 0xc3, 0x82, 0x15, 0x73, 0x7d, 0xef, 0x39, + 0xe7, 0xfb, 0xce, 0x39, 0x3e, 0x3e, 0xf7, 0x10, 0xbc, 0x5f, 0x2f, 0x3b, 0xae, 0xab, 0x97, 0x34, + 0xd3, 0x56, 0xee, 0x57, 0x68, 0x79, 0x3d, 0xb7, 0x56, 0x76, 0x3c, 0x87, 0x1c, 0x7c, 0x48, 0x3d, + 0x8d, 0x3d, 0xce, 0xb1, 0x5f, 0x4e, 0x99, 0xe6, 0xea, 0x47, 0xa5, 0xe3, 0xba, 0xe3, 0xae, 0x3a, + 0xae, 0xb2, 0xa2, 0xb9, 0x34, 0x90, 0x53, 0x1e, 0x4c, 0xad, 0x50, 0x4f, 0x9b, 0x52, 0xd6, 0x34, + 0xc3, 0xb4, 0x35, 0xcf, 0x74, 0xec, 0x40, 0x95, 0x34, 0xca, 0x99, 0x60, 0x3f, 0x55, 0xf6, 0x5b, + 0xf5, 0xaa, 0x70, 0x40, 0xe2, 0x0e, 0x18, 0x9a, 0xab, 0xae, 0x95, 0x4d, 0x9d, 0xc2, 0xde, 0x18, + 0xb7, 0xc7, 0x64, 0xd4, 0x92, 0xe6, 0x96, 0x54, 0xcf, 0x51, 0x75, 0xbd, 0xa6, 0x20, 0xdb, 0x70, + 0xc8, 0x2b, 0x6b, 0xfa, 0x3d, 0x5a, 0x86, 0x7d, 0x99, 0xdb, 0xb7, 0x34, 0xd7, 0x53, 0x57, 0x2c, + 0x47, 0xbf, 0xa7, 0x96, 0xa8, 0x69, 0x94, 0xbc, 0x04, 0x94, 0x4e, 0xc5, 0x6b, 0x54, 0x32, 0x64, + 0x38, 0x86, 0xc3, 0x7e, 0x2a, 0xfe, 0x2f, 0x78, 0x3a, 0x62, 0x38, 0x8e, 0x61, 0x51, 0x45, 0x5b, + 0x33, 0x15, 0xcd, 0xb6, 0x1d, 0x8f, 0x31, 0x77, 0x83, 0x5d, 0x79, 0x04, 0x4b, 0xb7, 0x7d, 0xe7, + 0xdc, 0xa5, 0x9e, 0x96, 0xd7, 0x75, 0xa7, 0x62, 0x7b, 0xa6, 0x6d, 0x14, 0xe8, 0xfd, 0x0a, 0x75, + 0x3d, 0xf9, 0x06, 0x3e, 0x90, 0xb8, 0xeb, 0xae, 0x39, 0xb6, 0x4b, 0x49, 0x0e, 0xef, 0xd3, 0x56, + 0x9c, 0xb2, 0x47, 0x8b, 0xaa, 0x1f, 0x02, 0x55, 0x5b, 0xf5, 0x4f, 0x0c, 0xa3, 0x43, 0x68, 0x62, + 0x77, 0x61, 0x10, 0xb6, 0x98, 0x2c, 0xdb, 0xa8, 0xa9, 0x5b, 0xa0, 0xde, 0xad, 0x8a, 0xb7, 0x5c, + 0x5d, 0x0e, 0xe0, 0x83, 0x35, 0x32, 0x8c, 0x77, 0x31, 0x76, 0xd7, 0x2f, 0x33, 0x15, 0x99, 0x42, + 0xb8, 0x24, 0x43, 0xb8, 0xc7, 0x76, 0x6c, 0x9d, 0x0e, 0x77, 0x1f, 0x42, 0x13, 0x3b, 0x0a, 0xc1, + 0x42, 0xae, 0xe0, 0x91, 0x64, 0x75, 0x00, 0xef, 0xff, 0xb8, 0xdf, 0xe1, 0x9e, 0x33, 0xa5, 0x7d, + 0xd3, 0x27, 0x72, 0x4d, 0x13, 0x27, 0xc7, 0xab, 0x9a, 0xdb, 0xf1, 0xec, 0xd7, 0xd1, 0xae, 0x42, + 0x44, 0x8d, 0x4c, 0x81, 0x45, 0xde, 0xb2, 0x92, 0x58, 0x5c, 0xc5, 0xb8, 0x9e, 0x60, 0x60, 0xf3, + 0x68, 0x2e, 0xc8, 0xc6, 0x9c, 0x9f, 0x8d, 0xb9, 0x20, 0x8b, 0x21, 0x1b, 0x73, 0x4b, 0x9a, 0x41, + 0x41, 0xb6, 0xc0, 0x49, 0xca, 0x4f, 0x10, 0xd0, 0x6b, 0xb0, 0x93, 0x4a, 0x2f, 0xd3, 0x01, 0x7a, + 0x64, 0x21, 0x82, 0xbf, 0x9b, 0xe1, 0x1f, 0x6f, 0x89, 0x3f, 0xc0, 0x14, 0x21, 0xf0, 0x08, 0x61, + 0x39, 0x89, 0xc0, 0xdc, 0xfa, 0xbc, 0x8f, 0x24, 0xf4, 0xd7, 0x10, 0xee, 0x61, 0xc8, 0x20, 0xe6, + 0xc1, 0x22, 0xe6, 0xc5, 0xee, 0xb6, 0xbd, 0xf8, 0x3d, 0xc2, 0x63, 0x4d, 0x41, 0xbc, 0x21, 0xce, + 0x7c, 0x0f, 0xe1, 0xc3, 0x21, 0x8f, 0xeb, 0x76, 0x9a, 0x2f, 0xff, 0x89, 0x7b, 0x83, 0xca, 0x65, + 0x16, 0xa3, 0xaf, 0x50, 0xb1, 0x63, 0x0e, 0xfd, 0x86, 0x8b, 0x6a, 0x12, 0x10, 0xf0, 0x67, 0x01, + 0xf7, 0x99, 0x76, 0xdc, 0x9d, 0xc7, 0x5b, 0xb8, 0x93, 0xd7, 0x17, 0x78, 0x93, 0x57, 0xd2, 0x39, + 0x67, 0x72, 0x6f, 0x30, 0x67, 0xd2, 0xed, 0xf4, 0x1b, 0xfc, 0x15, 0xf7, 0x06, 0x47, 0xed, 0xbc, + 0x09, 0x4e, 0xba, 0x80, 0x0f, 0x86, 0xd5, 0xd5, 0x37, 0x79, 0x4d, 0x73, 0x4b, 0xcb, 0xce, 0xbc, + 0xee, 0x55, 0x43, 0x37, 0x49, 0xb8, 0xd7, 0x84, 0x0d, 0x28, 0xf9, 0xb5, 0xb5, 0xbc, 0x89, 0xb3, + 0x69, 0xc2, 0xc0, 0xfd, 0x6d, 0xbc, 0xd7, 0x8c, 0xec, 0x80, 0xa3, 0x27, 0x05, 0xe8, 0xd7, 0x85, + 0xc0, 0x03, 0x31, 0x55, 0xf2, 0x2c, 0x98, 0x8f, 0x1e, 0xbe, 0xac, 0x79, 0x9a, 0x08, 0xf8, 0x87, + 0x78, 0x34, 0x55, 0x1a, 0xd0, 0xdf, 0xc1, 0x7b, 0xe6, 0x7d, 0x4c, 0x2c, 0xe9, 0x97, 0xab, 0xae, + 0x60, 0xbd, 0xe0, 0x65, 0x00, 0x7a, 0x54, 0x8f, 0x6c, 0x80, 0xd7, 0x21, 0x65, 0x1a, 0xbd, 0xde, + 0xa9, 0xe4, 0x7c, 0x8a, 0xc0, 0x47, 0x09, 0x96, 0x9a, 0x84, 0x28, 0xd3, 0xa1, 0x10, 0x75, 0x2e, + 0x4f, 0x15, 0xfc, 0x8f, 0x30, 0xd5, 0x16, 0x34, 0x77, 0xc9, 0xef, 0xcc, 0xb8, 0x4f, 0x8b, 0x69, + 0x17, 0x69, 0x15, 0x22, 0x1c, 0x2c, 0x64, 0x15, 0x0f, 0x37, 0x0a, 0x00, 0xe5, 0x79, 0xdc, 0x1b, + 0x3e, 0x03, 0xdf, 0x8e, 0xb7, 0x20, 0x5b, 0x53, 0x51, 0x13, 0x94, 0x35, 0x40, 0x94, 0xb7, 0xac, + 0x38, 0xa2, 0x4e, 0x45, 0xef, 0x13, 0x04, 0x24, 0x22, 0x36, 0x12, 0x49, 0x64, 0xda, 0x22, 0xd1, + 0xb9, 0xf8, 0xcc, 0xd4, 0x4b, 0xc1, 0xa2, 0xe6, 0x7a, 0x73, 0x7e, 0x63, 0x7b, 0x8d, 0xf5, 0xb5, + 0xcd, 0xc3, 0xb4, 0x01, 0x6f, 0x61, 0x92, 0x1c, 0x10, 0x7d, 0x0b, 0x0f, 0xc4, 0xb6, 0xc0, 0xa5, + 0xb9, 0x16, 0x7c, 0xe3, 0x0a, 0xe3, 0x6a, 0xe4, 0x52, 0xfd, 0xe5, 0x48, 0x01, 0xdd, 0xa9, 0x48, + 0x7e, 0x87, 0x80, 0x67, 0x92, 0xa9, 0x66, 0x3c, 0x33, 0x1d, 0xe0, 0xd9, 0xb9, 0x28, 0x9f, 0xc0, + 0xfb, 0xc2, 0x68, 0xf1, 0xd5, 0x2a, 0x39, 0xb4, 0x8b, 0x70, 0xe9, 0x80, 0xc3, 0x73, 0xeb, 0x37, + 0xfd, 0x7e, 0xbe, 0xdd, 0x6b, 0x80, 0x81, 0x87, 0xa2, 0xa6, 0xc1, 0x6b, 0xb7, 0x70, 0x3f, 0x5f, + 0x5b, 0x05, 0xdb, 0x7f, 0x5e, 0xa4, 0x10, 0x51, 0x20, 0xbf, 0x03, 0x1c, 0xf3, 0x96, 0xf5, 0x3a, + 0x2a, 0xf2, 0x67, 0x08, 0x88, 0xd4, 0xf4, 0xa7, 0x12, 0xc9, 0x6c, 0x8b, 0x48, 0xe7, 0xa2, 0x7e, + 0x13, 0x1a, 0xa9, 0x45, 0xd3, 0x65, 0xbe, 0x5f, 0xa2, 0x76, 0xb1, 0x7e, 0x7d, 0x6c, 0xd6, 0x8e, + 0x0e, 0xe1, 0x1e, 0xcb, 0x5c, 0x35, 0x3d, 0x66, 0x7d, 0x4f, 0x21, 0x58, 0xc8, 0x8f, 0xc3, 0x8e, + 0xa9, 0x41, 0xe1, 0xeb, 0x72, 0x85, 0x8c, 0xfb, 0x3d, 0xc7, 0xd3, 0x2c, 0x30, 0x04, 0x99, 0x15, + 0x79, 0x26, 0x5f, 0xc2, 0x13, 0x49, 0xa0, 0xee, 0x98, 0x5e, 0xa9, 0xa0, 0x79, 0x74, 0xd1, 0x87, + 0xce, 0x25, 0x7c, 0x02, 0xaf, 0x17, 0x08, 0x1f, 0x13, 0x50, 0x01, 0x24, 0x6f, 0xe3, 0xbd, 0xd1, + 0x29, 0x44, 0x5b, 0x34, 0x75, 0x9e, 0xe6, 0x18, 0xde, 0xc3, 0x28, 0xa9, 0x6b, 0xe9, 0x3c, 0xfd, + 0xeb, 0x7c, 0x59, 0xf3, 0xa8, 0xca, 0x30, 0xab, 0xb4, 0xaa, 0x53, 0x5a, 0xa4, 0xc5, 0xe1, 0xcc, + 0x21, 0x34, 0xd1, 0x5b, 0x18, 0x2c, 0x87, 0x38, 0xaf, 0xc0, 0x46, 0x6d, 0x76, 0xe0, 0x17, 0x15, + 0xff, 0x96, 0x1f, 0x29, 0x90, 0xf2, 0x99, 0x30, 0x37, 0x62, 0xbb, 0x40, 0x72, 0x3f, 0xde, 0xc9, + 0x95, 0xec, 0x4c, 0x01, 0x56, 0xf2, 0x32, 0x64, 0xc0, 0xbc, 0x63, 0x3f, 0xa0, 0x65, 0xff, 0x0b, + 0xbd, 0xec, 0xf8, 0xe2, 0x0d, 0xd5, 0xa1, 0x21, 0xa5, 0x24, 0xdc, 0x6b, 0x68, 0xee, 0x62, 0xcd, + 0xfb, 0xbb, 0x0b, 0xb5, 0xb5, 0xfc, 0x11, 0x82, 0xbe, 0xaa, 0x51, 0x2d, 0xe0, 0xf9, 0x37, 0x1e, + 0x74, 0x2a, 0xde, 0x8a, 0x53, 0xb1, 0x8b, 0x0b, 0x9a, 0x7b, 0xdd, 0xf6, 0x37, 0xc3, 0x49, 0x46, + 0xc3, 0x86, 0x7f, 0x9a, 0xcd, 0x4f, 0x74, 0xc7, 0xba, 0x4a, 0x29, 0x9c, 0x0e, 0x8c, 0x36, 0x6e, + 0x90, 0x09, 0x3c, 0xe0, 0xff, 0xcb, 0xd7, 0xef, 0x0c, 0xf3, 0x7f, 0xfc, 0xb1, 0x3c, 0x8e, 0x8f, + 0x30, 0x98, 0x37, 0xa8, 0xeb, 0x6a, 0x06, 0x5d, 0xd2, 0x5c, 0xd7, 0xb4, 0x8d, 0xa5, 0xba, 0xc6, + 0xd0, 0xbb, 0x57, 0xf1, 0xd1, 0x56, 0x07, 0x81, 0xd8, 0x08, 0xde, 0xfd, 0x6e, 0x0d, 0x62, 0x40, + 0xa8, 0xfe, 0x60, 0xfa, 0xf7, 0x51, 0xdc, 0xc3, 0x14, 0x91, 0xa7, 0x08, 0xf7, 0xf3, 0xf7, 0x59, + 0x72, 0xbe, 0x45, 0xba, 0x35, 0x19, 0xe5, 0x48, 0x17, 0xda, 0x92, 0x0d, 0x10, 0xcb, 0x17, 0x1f, + 0xbd, 0xf8, 0xe3, 0x71, 0xf7, 0x59, 0x72, 0x46, 0xf1, 0x45, 0x27, 0xb9, 0xb9, 0x5c, 0x6d, 0xf8, + 0x55, 0x13, 0x52, 0x36, 0xe0, 0xe3, 0xb0, 0xa9, 0x6c, 0xb0, 0xcf, 0xc1, 0x26, 0xf9, 0x12, 0xe1, + 0x01, 0x5e, 0x6f, 0xde, 0xb2, 0xc4, 0xb8, 0x24, 0x0f, 0x74, 0xc4, 0xb8, 0xa4, 0x0c, 0x69, 0xe4, + 0x13, 0x8c, 0xcb, 0x11, 0x32, 0x26, 0xc0, 0x85, 0xfc, 0x82, 0xf0, 0xfe, 0x18, 0x72, 0xb8, 0x57, + 0x93, 0x7c, 0x1b, 0x20, 0xa2, 0xc3, 0x01, 0x69, 0x6e, 0x3b, 0x2a, 0x80, 0xce, 0x79, 0x46, 0xe7, + 0x34, 0x99, 0x16, 0xa0, 0x03, 0xb2, 0x10, 0xa1, 0x4d, 0xf2, 0x33, 0xc2, 0x7f, 0xe7, 0x2e, 0xaf, + 0x1c, 0xb9, 0x4b, 0x82, 0xc8, 0x52, 0x07, 0x1f, 0x52, 0x7e, 0x1b, 0x1a, 0x80, 0xda, 0x2c, 0xa3, + 0x36, 0x43, 0x4e, 0xa7, 0x50, 0x33, 0xed, 0x14, 0x66, 0xaa, 0x59, 0xdc, 0x24, 0x5f, 0x20, 0xbc, + 0x37, 0x4a, 0x4e, 0x38, 0xe7, 0x12, 0x46, 0x10, 0xc2, 0x39, 0x97, 0x34, 0x56, 0x68, 0x99, 0x73, + 0x1c, 0x13, 0x97, 0xfc, 0x00, 0xc0, 0xb9, 0xab, 0xd9, 0xac, 0xe0, 0xcb, 0x9b, 0x78, 0x41, 0x95, + 0x2e, 0xb6, 0x29, 0x0d, 0xe0, 0xff, 0xc3, 0xc0, 0x4f, 0x93, 0x93, 0x4d, 0xc0, 0xd7, 0xc5, 0x94, + 0x8d, 0x70, 0xbd, 0x49, 0x7e, 0x44, 0x98, 0x34, 0x5e, 0xd9, 0x89, 0x10, 0x9e, 0xd4, 0x41, 0x81, + 0xf4, 0xdf, 0x76, 0xc5, 0x81, 0x4f, 0x9e, 0xf1, 0xb9, 0x40, 0xce, 0xa5, 0xf2, 0x89, 0xff, 0x97, + 0x81, 0x5a, 0xd4, 0x3c, 0x8d, 0x27, 0xf6, 0x35, 0xc2, 0x83, 0x51, 0x0b, 0x7e, 0x7a, 0xcd, 0x6e, + 0x21, 0x45, 0xda, 0x8c, 0x52, 0xea, 0x68, 0x40, 0x9e, 0x64, 0xac, 0xc6, 0xc9, 0x11, 0xa1, 0x28, + 0x91, 0x4f, 0x51, 0xfd, 0x4a, 0x4a, 0x66, 0x04, 0x13, 0x24, 0x76, 0x77, 0x96, 0xce, 0x6e, 0x59, + 0x0e, 0xc0, 0x2a, 0x0c, 0xec, 0x31, 0x32, 0x9e, 0x02, 0xd6, 0x00, 0x01, 0xdf, 0xe7, 0x45, 0x5a, + 0xdd, 0x24, 0x1f, 0x23, 0xdc, 0x17, 0x6a, 0xf1, 0x5d, 0x3d, 0x23, 0xe8, 0xac, 0xb6, 0x10, 0x27, + 0xdc, 0xe0, 0xe5, 0x71, 0x86, 0xf8, 0x30, 0x19, 0x6d, 0x81, 0x98, 0x3c, 0x41, 0xf8, 0x6f, 0xf1, + 0x96, 0x86, 0x08, 0x15, 0x8f, 0x94, 0xfe, 0x4a, 0x9a, 0x6d, 0x4f, 0x58, 0xd0, 0xd5, 0x7a, 0x1c, + 0xeb, 0x53, 0x84, 0xfb, 0xb8, 0xae, 0x85, 0x5c, 0x16, 0x31, 0xdf, 0xaa, 0x3b, 0x92, 0xae, 0x6c, + 0x53, 0x0b, 0xb0, 0x39, 0xce, 0xd8, 0xfc, 0x8b, 0xc8, 0x29, 0x6c, 0xb8, 0x4e, 0x8f, 0x3c, 0x43, + 0x0d, 0x97, 0x74, 0x22, 0x5a, 0x0a, 0x93, 0x47, 0x0c, 0x62, 0xa5, 0x27, 0x7d, 0x3c, 0x22, 0xcf, + 0x30, 0xf8, 0x27, 0x49, 0x2e, 0x05, 0xbe, 0x15, 0x95, 0xab, 0xa5, 0xff, 0xb7, 0x08, 0x93, 0x98, + 0x4e, 0xff, 0x2d, 0x10, 0x2d, 0x19, 0xdb, 0x61, 0x93, 0x3e, 0x04, 0x91, 0x73, 0x8c, 0xcd, 0x04, + 0x39, 0x2a, 0xc6, 0x86, 0x7c, 0x88, 0xf0, 0x0e, 0x56, 0x7c, 0xa6, 0x05, 0xdd, 0xc8, 0x97, 0xc7, + 0x53, 0x5b, 0x92, 0x11, 0xfc, 0xee, 0xea, 0xf0, 0xc1, 0x62, 0x4e, 0xfe, 0x1c, 0xe1, 0x3e, 0x6e, + 0xf8, 0x41, 0xce, 0x6d, 0xc1, 0x62, 0x74, 0x60, 0xd2, 0x1e, 0xd8, 0x33, 0x0c, 0xac, 0x42, 0x26, + 0x9b, 0x82, 0x6d, 0x68, 0xae, 0x3f, 0x40, 0x78, 0x57, 0xf8, 0x05, 0x9a, 0x16, 0x8c, 0xe8, 0x96, + 0x1d, 0x1b, 0x1b, 0x80, 0xc8, 0x63, 0x0c, 0xeb, 0x41, 0x72, 0xa0, 0x09, 0x56, 0xbf, 0x03, 0x1b, + 0xf0, 0xa5, 0xfc, 0x2b, 0x76, 0x78, 0xa3, 0x15, 0x6a, 0xc1, 0x92, 0x87, 0x17, 0x62, 0x2d, 0x58, + 0xca, 0x9c, 0xa2, 0x65, 0xe5, 0xd0, 0xeb, 0x32, 0xe4, 0x4f, 0x84, 0xb3, 0x31, 0xe0, 0x77, 0x4c, + 0xaf, 0x64, 0xda, 0xb5, 0xc9, 0x00, 0x59, 0x68, 0x03, 0x4b, 0xd2, 0x78, 0x42, 0xba, 0xb6, 0x7d, + 0x45, 0xc0, 0xf0, 0x2c, 0x63, 0x38, 0x45, 0x94, 0xd6, 0x0c, 0x23, 0x0a, 0x58, 0xa7, 0x1c, 0xfd, + 0x7b, 0x02, 0xb1, 0xdc, 0x4f, 0xfc, 0x0b, 0x05, 0xe9, 0x7c, 0x3b, 0xa2, 0x82, 0x4d, 0xcc, 0xc3, + 0x28, 0x4a, 0x1f, 0x78, 0x74, 0x98, 0x21, 0x06, 0x3c, 0x71, 0x3c, 0x22, 0x06, 0x3c, 0x79, 0x76, + 0xd2, 0x12, 0xb8, 0x15, 0x11, 0x9b, 0xfb, 0xdf, 0xb3, 0x97, 0x59, 0xf4, 0xfc, 0x65, 0x16, 0xfd, + 0xf6, 0x32, 0x8b, 0xde, 0x7f, 0x95, 0xed, 0x7a, 0xfe, 0x2a, 0xdb, 0xf5, 0xd3, 0xab, 0x6c, 0xd7, + 0xdd, 0x29, 0xc3, 0xf4, 0x4a, 0x95, 0x95, 0x9c, 0xee, 0xac, 0xf2, 0xaa, 0x42, 0x3c, 0x4a, 0x95, + 0xd7, 0xea, 0xad, 0xaf, 0x51, 0x77, 0x65, 0x27, 0xfb, 0xe8, 0x9d, 0xfa, 0x2b, 0x00, 0x00, 0xff, + 0xff, 0xc0, 0xad, 0x4e, 0xf8, 0x97, 0x23, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2177,6 +2179,8 @@ type QueryClient interface { CctxAll(ctx context.Context, in *QueryAllCctxRequest, opts ...grpc.CallOption) (*QueryAllCctxResponse, error) // Queries a list of pending cctxs. CctxListPending(ctx context.Context, in *QueryListCctxPendingRequest, opts ...grpc.CallOption) (*QueryListCctxPendingResponse, error) + // Queries a list of pending cctxs with rate limit. + CctxListPendingWithinRateLimit(ctx context.Context, in *QueryListCctxPendingWithRateLimitRequest, opts ...grpc.CallOption) (*QueryListCctxPendingWithRateLimitResponse, error) ZetaAccounting(ctx context.Context, in *QueryZetaAccountingRequest, opts ...grpc.CallOption) (*QueryZetaAccountingResponse, error) // Queries a list of lastMetaHeight items. LastZetaHeight(ctx context.Context, in *QueryLastZetaHeightRequest, opts ...grpc.CallOption) (*QueryLastZetaHeightResponse, error) @@ -2352,6 +2356,15 @@ func (c *queryClient) CctxListPending(ctx context.Context, in *QueryListCctxPend return out, nil } +func (c *queryClient) CctxListPendingWithinRateLimit(ctx context.Context, in *QueryListCctxPendingWithRateLimitRequest, opts ...grpc.CallOption) (*QueryListCctxPendingWithRateLimitResponse, error) { + out := new(QueryListCctxPendingWithRateLimitResponse) + err := c.cc.Invoke(ctx, "/zetachain.zetacore.crosschain.Query/CctxListPendingWithinRateLimit", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *queryClient) ZetaAccounting(ctx context.Context, in *QueryZetaAccountingRequest, opts ...grpc.CallOption) (*QueryZetaAccountingResponse, error) { out := new(QueryZetaAccountingResponse) err := c.cc.Invoke(ctx, "/zetachain.zetacore.crosschain.Query/ZetaAccounting", in, out, opts...) @@ -2403,6 +2416,8 @@ type QueryServer interface { CctxAll(context.Context, *QueryAllCctxRequest) (*QueryAllCctxResponse, error) // Queries a list of pending cctxs. CctxListPending(context.Context, *QueryListCctxPendingRequest) (*QueryListCctxPendingResponse, error) + // Queries a list of pending cctxs with rate limit. + CctxListPendingWithinRateLimit(context.Context, *QueryListCctxPendingWithRateLimitRequest) (*QueryListCctxPendingWithRateLimitResponse, error) ZetaAccounting(context.Context, *QueryZetaAccountingRequest) (*QueryZetaAccountingResponse, error) // Queries a list of lastMetaHeight items. LastZetaHeight(context.Context, *QueryLastZetaHeightRequest) (*QueryLastZetaHeightResponse, error) @@ -2466,6 +2481,9 @@ func (*UnimplementedQueryServer) CctxAll(ctx context.Context, req *QueryAllCctxR func (*UnimplementedQueryServer) CctxListPending(ctx context.Context, req *QueryListCctxPendingRequest) (*QueryListCctxPendingResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method CctxListPending not implemented") } +func (*UnimplementedQueryServer) CctxListPendingWithinRateLimit(ctx context.Context, req *QueryListCctxPendingWithRateLimitRequest) (*QueryListCctxPendingWithRateLimitResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CctxListPendingWithinRateLimit not implemented") +} func (*UnimplementedQueryServer) ZetaAccounting(ctx context.Context, req *QueryZetaAccountingRequest) (*QueryZetaAccountingResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ZetaAccounting not implemented") } @@ -2801,6 +2819,24 @@ func _Query_CctxListPending_Handler(srv interface{}, ctx context.Context, dec fu return interceptor(ctx, in, info, handler) } +func _Query_CctxListPendingWithinRateLimit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryListCctxPendingWithRateLimitRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).CctxListPendingWithinRateLimit(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/zetachain.zetacore.crosschain.Query/CctxListPendingWithinRateLimit", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).CctxListPendingWithinRateLimit(ctx, req.(*QueryListCctxPendingWithRateLimitRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Query_ZetaAccounting_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(QueryZetaAccountingRequest) if err := dec(in); err != nil { @@ -2913,6 +2949,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "CctxListPending", Handler: _Query_CctxListPending_Handler, }, + { + MethodName: "CctxListPendingWithinRateLimit", + Handler: _Query_CctxListPendingWithinRateLimit_Handler, + }, { MethodName: "ZetaAccounting", Handler: _Query_ZetaAccounting_Handler, diff --git a/x/crosschain/types/query.pb.gw.go b/x/crosschain/types/query.pb.gw.go index 6234a732ea..a32163b011 100644 --- a/x/crosschain/types/query.pb.gw.go +++ b/x/crosschain/types/query.pb.gw.go @@ -905,6 +905,42 @@ func local_request_Query_CctxListPending_0(ctx context.Context, marshaler runtim } +var ( + filter_Query_CctxListPendingWithinRateLimit_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_CctxListPendingWithinRateLimit_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryListCctxPendingWithRateLimitRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_CctxListPendingWithinRateLimit_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.CctxListPendingWithinRateLimit(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_CctxListPendingWithinRateLimit_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryListCctxPendingWithRateLimitRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_CctxListPendingWithinRateLimit_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.CctxListPendingWithinRateLimit(ctx, &protoReq) + return msg, metadata, err + +} + func request_Query_ZetaAccounting_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryZetaAccountingRequest var metadata runtime.ServerMetadata @@ -1361,6 +1397,29 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_CctxListPendingWithinRateLimit_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_CctxListPendingWithinRateLimit_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_CctxListPendingWithinRateLimit_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_Query_ZetaAccounting_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1808,6 +1867,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_CctxListPendingWithinRateLimit_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_CctxListPendingWithinRateLimit_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_CctxListPendingWithinRateLimit_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_Query_ZetaAccounting_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1888,6 +1967,8 @@ var ( pattern_Query_CctxListPending_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"zeta-chain", "crosschain", "cctxPending"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_CctxListPendingWithinRateLimit_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"zeta-chain", "crosschain", "cctxPendingWithRateLimit"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_ZetaAccounting_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"zeta-chain", "crosschain", "zetaAccounting"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_LastZetaHeight_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"zeta-chain", "crosschain", "lastZetaHeight"}, "", runtime.AssumeColonVerbOpt(false))) @@ -1930,6 +2011,8 @@ var ( forward_Query_CctxListPending_0 = runtime.ForwardResponseMessage + forward_Query_CctxListPendingWithinRateLimit_0 = runtime.ForwardResponseMessage + forward_Query_ZetaAccounting_0 = runtime.ForwardResponseMessage forward_Query_LastZetaHeight_0 = runtime.ForwardResponseMessage diff --git a/x/crosschain/types/rate_limiter_flags.pb.go b/x/crosschain/types/rate_limiter_flags.pb.go index ce24f8baf3..899a1d7099 100644 --- a/x/crosschain/types/rate_limiter_flags.pb.go +++ b/x/crosschain/types/rate_limiter_flags.pb.go @@ -4,7 +4,6 @@ package types import ( - encoding_binary "encoding/binary" fmt "fmt" io "io" math "math" @@ -13,7 +12,6 @@ import ( github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/gogo/protobuf/proto" - coin "github.com/zeta-chain/zetacore/pkg/coin" ) // Reference imports to suppress errors if they are not otherwise used. @@ -27,26 +25,28 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// ZRC20Rate defines the conversion rate of ZRC20 to ZETA -type ZRC20Rate struct { - ChainId int64 `protobuf:"varint,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` - CoinType coin.CoinType `protobuf:"varint,2,opt,name=coin_type,json=coinType,proto3,enum=coin.CoinType" json:"coin_type,omitempty"` - Asset string `protobuf:"bytes,3,opt,name=asset,proto3" json:"asset,omitempty"` - ConversionRate float64 `protobuf:"fixed64,4,opt,name=conversion_rate,json=conversionRate,proto3" json:"conversion_rate,omitempty"` +type RateLimiterFlags struct { + Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` + // window in blocks + Window int64 `protobuf:"varint,2,opt,name=window,proto3" json:"window,omitempty"` + // rate in azeta per block + Rate github_com_cosmos_cosmos_sdk_types.Uint `protobuf:"bytes,3,opt,name=rate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint" json:"rate"` + // conversion in azeta per token + Conversions []Conversion `protobuf:"bytes,4,rep,name=conversions,proto3" json:"conversions"` } -func (m *ZRC20Rate) Reset() { *m = ZRC20Rate{} } -func (m *ZRC20Rate) String() string { return proto.CompactTextString(m) } -func (*ZRC20Rate) ProtoMessage() {} -func (*ZRC20Rate) Descriptor() ([]byte, []int) { +func (m *RateLimiterFlags) Reset() { *m = RateLimiterFlags{} } +func (m *RateLimiterFlags) String() string { return proto.CompactTextString(m) } +func (*RateLimiterFlags) ProtoMessage() {} +func (*RateLimiterFlags) Descriptor() ([]byte, []int) { return fileDescriptor_b17ae80d5af4e97e, []int{0} } -func (m *ZRC20Rate) XXX_Unmarshal(b []byte) error { +func (m *RateLimiterFlags) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *ZRC20Rate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *RateLimiterFlags) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_ZRC20Rate.Marshal(b, m, deterministic) + return xxx_messageInfo_RateLimiterFlags.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -56,66 +56,56 @@ func (m *ZRC20Rate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return b[:n], nil } } -func (m *ZRC20Rate) XXX_Merge(src proto.Message) { - xxx_messageInfo_ZRC20Rate.Merge(m, src) +func (m *RateLimiterFlags) XXX_Merge(src proto.Message) { + xxx_messageInfo_RateLimiterFlags.Merge(m, src) } -func (m *ZRC20Rate) XXX_Size() int { +func (m *RateLimiterFlags) XXX_Size() int { return m.Size() } -func (m *ZRC20Rate) XXX_DiscardUnknown() { - xxx_messageInfo_ZRC20Rate.DiscardUnknown(m) +func (m *RateLimiterFlags) XXX_DiscardUnknown() { + xxx_messageInfo_RateLimiterFlags.DiscardUnknown(m) } -var xxx_messageInfo_ZRC20Rate proto.InternalMessageInfo - -func (m *ZRC20Rate) GetChainId() int64 { - if m != nil { - return m.ChainId - } - return 0 -} +var xxx_messageInfo_RateLimiterFlags proto.InternalMessageInfo -func (m *ZRC20Rate) GetCoinType() coin.CoinType { +func (m *RateLimiterFlags) GetEnabled() bool { if m != nil { - return m.CoinType + return m.Enabled } - return coin.CoinType_Zeta + return false } -func (m *ZRC20Rate) GetAsset() string { +func (m *RateLimiterFlags) GetWindow() int64 { if m != nil { - return m.Asset + return m.Window } - return "" + return 0 } -func (m *ZRC20Rate) GetConversionRate() float64 { +func (m *RateLimiterFlags) GetConversions() []Conversion { if m != nil { - return m.ConversionRate + return m.Conversions } - return 0 + return nil } -// RateLimiterFlags defines the outbound rate limiter flags -type RateLimiterFlags struct { - IsEnabled bool `protobuf:"varint,1,opt,name=is_enabled,json=isEnabled,proto3" json:"is_enabled,omitempty"` - RateLimitWindow int64 `protobuf:"varint,2,opt,name=rate_limit_window,json=rateLimitWindow,proto3" json:"rate_limit_window,omitempty"` - RateLimitInZeta github_com_cosmos_cosmos_sdk_types.Uint `protobuf:"bytes,3,opt,name=rate_limit_in_zeta,json=rateLimitInZeta,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Uint" json:"rate_limit_in_zeta"` - Zrc20Rates []*ZRC20Rate `protobuf:"bytes,4,rep,name=zrc20_rates,json=zrc20Rates,proto3" json:"zrc20_rates,omitempty"` +type Conversion struct { + Zrc20 string `protobuf:"bytes,1,opt,name=zrc20,proto3" json:"zrc20,omitempty"` + Rate github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=rate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"rate"` } -func (m *RateLimiterFlags) Reset() { *m = RateLimiterFlags{} } -func (m *RateLimiterFlags) String() string { return proto.CompactTextString(m) } -func (*RateLimiterFlags) ProtoMessage() {} -func (*RateLimiterFlags) Descriptor() ([]byte, []int) { +func (m *Conversion) Reset() { *m = Conversion{} } +func (m *Conversion) String() string { return proto.CompactTextString(m) } +func (*Conversion) ProtoMessage() {} +func (*Conversion) Descriptor() ([]byte, []int) { return fileDescriptor_b17ae80d5af4e97e, []int{1} } -func (m *RateLimiterFlags) XXX_Unmarshal(b []byte) error { +func (m *Conversion) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *RateLimiterFlags) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *Conversion) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_RateLimiterFlags.Marshal(b, m, deterministic) + return xxx_messageInfo_Conversion.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -125,42 +115,28 @@ func (m *RateLimiterFlags) XXX_Marshal(b []byte, deterministic bool) ([]byte, er return b[:n], nil } } -func (m *RateLimiterFlags) XXX_Merge(src proto.Message) { - xxx_messageInfo_RateLimiterFlags.Merge(m, src) +func (m *Conversion) XXX_Merge(src proto.Message) { + xxx_messageInfo_Conversion.Merge(m, src) } -func (m *RateLimiterFlags) XXX_Size() int { +func (m *Conversion) XXX_Size() int { return m.Size() } -func (m *RateLimiterFlags) XXX_DiscardUnknown() { - xxx_messageInfo_RateLimiterFlags.DiscardUnknown(m) +func (m *Conversion) XXX_DiscardUnknown() { + xxx_messageInfo_Conversion.DiscardUnknown(m) } -var xxx_messageInfo_RateLimiterFlags proto.InternalMessageInfo +var xxx_messageInfo_Conversion proto.InternalMessageInfo -func (m *RateLimiterFlags) GetIsEnabled() bool { +func (m *Conversion) GetZrc20() string { if m != nil { - return m.IsEnabled + return m.Zrc20 } - return false -} - -func (m *RateLimiterFlags) GetRateLimitWindow() int64 { - if m != nil { - return m.RateLimitWindow - } - return 0 -} - -func (m *RateLimiterFlags) GetZrc20Rates() []*ZRC20Rate { - if m != nil { - return m.Zrc20Rates - } - return nil + return "" } func init() { - proto.RegisterType((*ZRC20Rate)(nil), "zetachain.zetacore.crosschain.ZRC20Rate") proto.RegisterType((*RateLimiterFlags)(nil), "zetachain.zetacore.crosschain.RateLimiterFlags") + proto.RegisterType((*Conversion)(nil), "zetachain.zetacore.crosschain.Conversion") } func init() { @@ -168,36 +144,31 @@ func init() { } var fileDescriptor_b17ae80d5af4e97e = []byte{ - // 416 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x52, 0x41, 0x6b, 0x14, 0x31, - 0x14, 0xde, 0x74, 0xab, 0xee, 0xa6, 0xb0, 0xd5, 0xd8, 0xc3, 0x58, 0xe8, 0x74, 0xa8, 0x87, 0x0e, - 0x4a, 0x93, 0x3a, 0xfe, 0x83, 0x16, 0x85, 0x45, 0x4f, 0x41, 0x11, 0x16, 0x21, 0x64, 0x33, 0x71, - 0x1a, 0xba, 0x9b, 0x0c, 0x49, 0xb4, 0xb6, 0x3f, 0xc0, 0xb3, 0xf8, 0xab, 0x7a, 0xec, 0x51, 0x3c, - 0x14, 0xd9, 0xfd, 0x23, 0x92, 0xa4, 0xeb, 0xce, 0xa9, 0x97, 0x99, 0x2f, 0x8f, 0xf7, 0x7d, 0x7c, - 0xdf, 0x7b, 0x0f, 0x3e, 0x17, 0xd6, 0x38, 0x27, 0xce, 0xb8, 0xd2, 0xc4, 0x72, 0x2f, 0xd9, 0x4c, - 0xcd, 0x95, 0x97, 0x96, 0x7d, 0x99, 0xf1, 0xc6, 0xe1, 0xd6, 0x1a, 0x6f, 0xd0, 0xde, 0x95, 0xf4, - 0x3c, 0xf6, 0xe0, 0x88, 0x8c, 0x95, 0x78, 0xcd, 0xdb, 0xdd, 0x69, 0x4c, 0x63, 0x62, 0x27, 0x09, - 0x28, 0x91, 0x76, 0x9f, 0xb6, 0xe7, 0x0d, 0x11, 0x46, 0xe9, 0xf8, 0x49, 0xc5, 0x83, 0x5f, 0x00, - 0x0e, 0x27, 0xf4, 0xb4, 0x3a, 0xa6, 0xdc, 0x4b, 0xf4, 0x0c, 0x0e, 0xa2, 0x02, 0x53, 0x75, 0x06, - 0x0a, 0x50, 0xf6, 0xe9, 0xa3, 0xf8, 0x1e, 0xd7, 0xe8, 0x25, 0x1c, 0x06, 0x1a, 0xf3, 0x97, 0xad, - 0xcc, 0x36, 0x0a, 0x50, 0x8e, 0xaa, 0x11, 0x8e, 0x42, 0xa7, 0x46, 0xe9, 0x0f, 0x97, 0xad, 0xa4, - 0x03, 0x71, 0x87, 0xd0, 0x0e, 0x7c, 0xc0, 0x9d, 0x93, 0x3e, 0xeb, 0x17, 0xa0, 0x1c, 0xd2, 0xf4, - 0x40, 0x87, 0x70, 0x5b, 0x18, 0xfd, 0x4d, 0x5a, 0xa7, 0x8c, 0x66, 0x21, 0x5c, 0xb6, 0x59, 0x80, - 0x12, 0xd0, 0xd1, 0xba, 0x1c, 0x6c, 0x1c, 0xfc, 0xd8, 0x80, 0x8f, 0x03, 0x78, 0x9f, 0xa2, 0xbf, - 0x0d, 0xc9, 0xd1, 0x1e, 0x84, 0xca, 0x31, 0xa9, 0xf9, 0x74, 0x26, 0x93, 0xbb, 0x01, 0x1d, 0x2a, - 0xf7, 0x26, 0x15, 0xd0, 0x0b, 0xf8, 0x64, 0x3d, 0x2e, 0x76, 0xa1, 0x74, 0x6d, 0x2e, 0xa2, 0xcf, - 0x3e, 0xdd, 0xb6, 0x2b, 0xad, 0x4f, 0xb1, 0x8c, 0x3e, 0x43, 0xd4, 0xe9, 0x55, 0x9a, 0x85, 0x21, - 0x26, 0xaf, 0x27, 0xe4, 0xfa, 0x76, 0xbf, 0xf7, 0xe7, 0x76, 0xff, 0xb0, 0x51, 0xfe, 0xec, 0xeb, - 0x14, 0x0b, 0x33, 0x27, 0xc2, 0xb8, 0xb9, 0x71, 0x77, 0xbf, 0x23, 0x57, 0x9f, 0x93, 0x30, 0x05, - 0x87, 0x3f, 0x2a, 0xed, 0x3b, 0xea, 0x63, 0x3d, 0x91, 0x9e, 0xa3, 0x31, 0xdc, 0xba, 0xb2, 0xa2, - 0x3a, 0x8e, 0x09, 0x5d, 0xb6, 0x59, 0xf4, 0xcb, 0xad, 0xaa, 0xc4, 0xf7, 0xae, 0x0c, 0xff, 0xdf, - 0x01, 0x85, 0x91, 0x1c, 0xa0, 0x3b, 0x79, 0x77, 0xbd, 0xc8, 0xc1, 0xcd, 0x22, 0x07, 0x7f, 0x17, - 0x39, 0xf8, 0xb9, 0xcc, 0x7b, 0x37, 0xcb, 0xbc, 0xf7, 0x7b, 0x99, 0xf7, 0x26, 0xaf, 0x3a, 0xf6, - 0x82, 0xde, 0x51, 0xba, 0x98, 0x95, 0x34, 0xf9, 0x4e, 0x3a, 0x77, 0x14, 0xdd, 0x4e, 0x1f, 0xc6, - 0x8d, 0xbf, 0xfe, 0x17, 0x00, 0x00, 0xff, 0xff, 0xba, 0xde, 0xfb, 0xd3, 0x62, 0x02, 0x00, 0x00, + // 331 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x91, 0xc1, 0x4e, 0x32, 0x31, + 0x14, 0x85, 0xa7, 0xc0, 0xcf, 0x2f, 0x65, 0x63, 0x1a, 0x62, 0x26, 0x26, 0x0e, 0x13, 0x4c, 0x74, + 0x5c, 0xd0, 0x2a, 0xbe, 0xc1, 0x60, 0xdc, 0xe8, 0xc6, 0x49, 0xdc, 0xb8, 0x21, 0x43, 0x29, 0x43, + 0x23, 0xb4, 0xa4, 0xad, 0xa2, 0x3c, 0x85, 0x8f, 0xc5, 0x92, 0xa5, 0x31, 0x86, 0x18, 0x78, 0x11, + 0x33, 0x9d, 0x41, 0x66, 0x65, 0x5c, 0xf5, 0xde, 0xe4, 0x9e, 0xd3, 0xef, 0xe4, 0xc0, 0x63, 0xaa, + 0xa4, 0xd6, 0x74, 0x14, 0x73, 0x41, 0x54, 0x6c, 0x58, 0x6f, 0xcc, 0x27, 0xdc, 0x30, 0xd5, 0x1b, + 0x8e, 0xe3, 0x44, 0xe3, 0xa9, 0x92, 0x46, 0xa2, 0xa3, 0x39, 0x33, 0xb1, 0xbd, 0xc1, 0x76, 0x92, + 0x8a, 0xe1, 0x9d, 0xee, 0xb0, 0x91, 0xc8, 0x44, 0xda, 0x4b, 0x92, 0x4e, 0x99, 0xa8, 0xf5, 0x09, + 0xe0, 0x7e, 0x14, 0x1b, 0x76, 0x9b, 0x19, 0x5e, 0xa7, 0x7e, 0xc8, 0x85, 0xff, 0x99, 0x88, 0xfb, + 0x63, 0x36, 0x70, 0x81, 0x0f, 0x82, 0xbd, 0x68, 0xbb, 0xa2, 0x03, 0x58, 0x9d, 0x71, 0x31, 0x90, + 0x33, 0xb7, 0xe4, 0x83, 0xa0, 0x1c, 0xe5, 0x1b, 0xea, 0xc2, 0x4a, 0xca, 0xe5, 0x96, 0x7d, 0x10, + 0xd4, 0x42, 0xb2, 0x58, 0x35, 0x9d, 0x8f, 0x55, 0xf3, 0x34, 0xe1, 0x66, 0xf4, 0xd4, 0xc7, 0x54, + 0x4e, 0x08, 0x95, 0x7a, 0x22, 0x75, 0xfe, 0xb4, 0xf5, 0xe0, 0x91, 0x98, 0xd7, 0x29, 0xd3, 0xf8, + 0x9e, 0x0b, 0x13, 0x59, 0x31, 0xba, 0x83, 0x75, 0x2a, 0xc5, 0x33, 0x53, 0x9a, 0x4b, 0xa1, 0xdd, + 0x8a, 0x5f, 0x0e, 0xea, 0x9d, 0x33, 0xfc, 0x6b, 0x2c, 0xdc, 0xfd, 0x51, 0x84, 0x95, 0xf4, 0xdb, + 0xa8, 0xe8, 0xd1, 0x1a, 0x42, 0xb8, 0x3b, 0x40, 0x0d, 0xf8, 0x6f, 0xae, 0x68, 0xe7, 0xdc, 0xa6, + 0xaa, 0x45, 0xd9, 0x82, 0xc2, 0x9c, 0xbd, 0x64, 0xd9, 0x71, 0xce, 0x7e, 0xf2, 0x07, 0xf6, 0x2b, + 0x46, 0x33, 0xf4, 0xf0, 0x66, 0xb1, 0xf6, 0xc0, 0x72, 0xed, 0x81, 0xaf, 0xb5, 0x07, 0xde, 0x36, + 0x9e, 0xb3, 0xdc, 0x78, 0xce, 0xfb, 0xc6, 0x73, 0x1e, 0x2e, 0x0a, 0x3e, 0x29, 0x7f, 0x3b, 0x6b, + 0x71, 0x1b, 0x85, 0xbc, 0x90, 0x42, 0xb7, 0xd6, 0xb6, 0x5f, 0xb5, 0xd5, 0x5c, 0x7e, 0x07, 0x00, + 0x00, 0xff, 0xff, 0xd2, 0x2c, 0x21, 0x90, 0xf6, 0x01, 0x00, 0x00, } -func (m *ZRC20Rate) Marshal() (dAtA []byte, err error) { +func (m *RateLimiterFlags) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -207,43 +178,59 @@ func (m *ZRC20Rate) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *ZRC20Rate) MarshalTo(dAtA []byte) (int, error) { +func (m *RateLimiterFlags) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *ZRC20Rate) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *RateLimiterFlags) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if m.ConversionRate != 0 { - i -= 8 - encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(math.Float64bits(float64(m.ConversionRate)))) - i-- - dAtA[i] = 0x21 + if len(m.Conversions) > 0 { + for iNdEx := len(m.Conversions) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Conversions[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRateLimiterFlags(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } } - if len(m.Asset) > 0 { - i -= len(m.Asset) - copy(dAtA[i:], m.Asset) - i = encodeVarintRateLimiterFlags(dAtA, i, uint64(len(m.Asset))) - i-- - dAtA[i] = 0x1a + { + size := m.Rate.Size() + i -= size + if _, err := m.Rate.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintRateLimiterFlags(dAtA, i, uint64(size)) } - if m.CoinType != 0 { - i = encodeVarintRateLimiterFlags(dAtA, i, uint64(m.CoinType)) + i-- + dAtA[i] = 0x1a + if m.Window != 0 { + i = encodeVarintRateLimiterFlags(dAtA, i, uint64(m.Window)) i-- dAtA[i] = 0x10 } - if m.ChainId != 0 { - i = encodeVarintRateLimiterFlags(dAtA, i, uint64(m.ChainId)) + if m.Enabled { + i-- + if m.Enabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } i-- dAtA[i] = 0x8 } return len(dAtA) - i, nil } -func (m *RateLimiterFlags) Marshal() (dAtA []byte, err error) { +func (m *Conversion) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -253,54 +240,32 @@ func (m *RateLimiterFlags) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *RateLimiterFlags) MarshalTo(dAtA []byte) (int, error) { +func (m *Conversion) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *RateLimiterFlags) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *Conversion) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if len(m.Zrc20Rates) > 0 { - for iNdEx := len(m.Zrc20Rates) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Zrc20Rates[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintRateLimiterFlags(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x22 - } - } { - size := m.RateLimitInZeta.Size() + size := m.Rate.Size() i -= size - if _, err := m.RateLimitInZeta.MarshalTo(dAtA[i:]); err != nil { + if _, err := m.Rate.MarshalTo(dAtA[i:]); err != nil { return 0, err } i = encodeVarintRateLimiterFlags(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x1a - if m.RateLimitWindow != 0 { - i = encodeVarintRateLimiterFlags(dAtA, i, uint64(m.RateLimitWindow)) - i-- - dAtA[i] = 0x10 - } - if m.IsEnabled { - i-- - if m.IsEnabled { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } + dAtA[i] = 0x12 + if len(m.Zrc20) > 0 { + i -= len(m.Zrc20) + copy(dAtA[i:], m.Zrc20) + i = encodeVarintRateLimiterFlags(dAtA, i, uint64(len(m.Zrc20))) i-- - dAtA[i] = 0x8 + dAtA[i] = 0xa } return len(dAtA) - i, nil } @@ -316,48 +281,41 @@ func encodeVarintRateLimiterFlags(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } -func (m *ZRC20Rate) Size() (n int) { +func (m *RateLimiterFlags) Size() (n int) { if m == nil { return 0 } var l int _ = l - if m.ChainId != 0 { - n += 1 + sovRateLimiterFlags(uint64(m.ChainId)) - } - if m.CoinType != 0 { - n += 1 + sovRateLimiterFlags(uint64(m.CoinType)) + if m.Enabled { + n += 2 } - l = len(m.Asset) - if l > 0 { - n += 1 + l + sovRateLimiterFlags(uint64(l)) + if m.Window != 0 { + n += 1 + sovRateLimiterFlags(uint64(m.Window)) } - if m.ConversionRate != 0 { - n += 9 + l = m.Rate.Size() + n += 1 + l + sovRateLimiterFlags(uint64(l)) + if len(m.Conversions) > 0 { + for _, e := range m.Conversions { + l = e.Size() + n += 1 + l + sovRateLimiterFlags(uint64(l)) + } } return n } -func (m *RateLimiterFlags) Size() (n int) { +func (m *Conversion) Size() (n int) { if m == nil { return 0 } var l int _ = l - if m.IsEnabled { - n += 2 - } - if m.RateLimitWindow != 0 { - n += 1 + sovRateLimiterFlags(uint64(m.RateLimitWindow)) + l = len(m.Zrc20) + if l > 0 { + n += 1 + l + sovRateLimiterFlags(uint64(l)) } - l = m.RateLimitInZeta.Size() + l = m.Rate.Size() n += 1 + l + sovRateLimiterFlags(uint64(l)) - if len(m.Zrc20Rates) > 0 { - for _, e := range m.Zrc20Rates { - l = e.Size() - n += 1 + l + sovRateLimiterFlags(uint64(l)) - } - } return n } @@ -367,7 +325,7 @@ func sovRateLimiterFlags(x uint64) (n int) { func sozRateLimiterFlags(x uint64) (n int) { return sovRateLimiterFlags(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (m *ZRC20Rate) Unmarshal(dAtA []byte) error { +func (m *RateLimiterFlags) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -390,17 +348,17 @@ func (m *ZRC20Rate) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ZRC20Rate: wiretype end group for non-group") + return fmt.Errorf("proto: RateLimiterFlags: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ZRC20Rate: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: RateLimiterFlags: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Enabled", wireType) } - m.ChainId = 0 + var v int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowRateLimiterFlags @@ -410,16 +368,17 @@ func (m *ZRC20Rate) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.ChainId |= int64(b&0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } } + m.Enabled = bool(v != 0) case 2: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field CoinType", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Window", wireType) } - m.CoinType = 0 + m.Window = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowRateLimiterFlags @@ -429,14 +388,14 @@ func (m *ZRC20Rate) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.CoinType |= coin.CoinType(b&0x7F) << shift + m.Window |= int64(b&0x7F) << shift if b < 0x80 { break } } case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Asset", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Rate", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -464,19 +423,44 @@ func (m *ZRC20Rate) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Asset = string(dAtA[iNdEx:postIndex]) + if err := m.Rate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex case 4: - if wireType != 1 { - return fmt.Errorf("proto: wrong wireType = %d for field ConversionRate", wireType) + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Conversions", wireType) } - var v uint64 - if (iNdEx + 8) > l { + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRateLimiterFlags + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRateLimiterFlags + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRateLimiterFlags + } + if postIndex > l { return io.ErrUnexpectedEOF } - v = uint64(encoding_binary.LittleEndian.Uint64(dAtA[iNdEx:])) - iNdEx += 8 - m.ConversionRate = float64(math.Float64frombits(v)) + m.Conversions = append(m.Conversions, Conversion{}) + if err := m.Conversions[len(m.Conversions)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipRateLimiterFlags(dAtA[iNdEx:]) @@ -498,7 +482,7 @@ func (m *ZRC20Rate) Unmarshal(dAtA []byte) error { } return nil } -func (m *RateLimiterFlags) Unmarshal(dAtA []byte) error { +func (m *Conversion) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -521,54 +505,15 @@ func (m *RateLimiterFlags) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: RateLimiterFlags: wiretype end group for non-group") + return fmt.Errorf("proto: Conversion: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: RateLimiterFlags: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: Conversion: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field IsEnabled", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRateLimiterFlags - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.IsEnabled = bool(v != 0) - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field RateLimitWindow", wireType) - } - m.RateLimitWindow = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRateLimiterFlags - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.RateLimitWindow |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RateLimitInZeta", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Zrc20", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -596,15 +541,13 @@ func (m *RateLimiterFlags) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.RateLimitInZeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.Zrc20 = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 4: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Zrc20Rates", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Rate", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowRateLimiterFlags @@ -614,23 +557,23 @@ func (m *RateLimiterFlags) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthRateLimiterFlags } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthRateLimiterFlags } if postIndex > l { return io.ErrUnexpectedEOF } - m.Zrc20Rates = append(m.Zrc20Rates, &ZRC20Rate{}) - if err := m.Zrc20Rates[len(m.Zrc20Rates)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Rate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/x/fungible/keeper/foreign_coins.go b/x/fungible/keeper/foreign_coins.go index ee424e92c1..5f0a31da4a 100644 --- a/x/fungible/keeper/foreign_coins.go +++ b/x/fungible/keeper/foreign_coins.go @@ -1,6 +1,8 @@ package keeper import ( + "strings" + "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" ethcommon "github.com/ethereum/go-ethereum/common" @@ -79,6 +81,22 @@ func (k Keeper) GetAllForeignCoins(ctx sdk.Context) (list []types.ForeignCoins) return } +// GetAllForeignERC20CoinMap returns all foreign ERC20 coins in a map of chainID -> asset -> coin +func (k Keeper) GetAllForeignERC20CoinMap(ctx sdk.Context) map[int64]map[string]types.ForeignCoins { + allForeignCoins := k.GetAllForeignCoins(ctx) + + erc20CoinMap := make(map[int64]map[string]types.ForeignCoins) + for _, c := range allForeignCoins { + if c.CoinType == coin.CoinType_ERC20 { + if _, found := erc20CoinMap[c.ForeignChainId]; !found { + erc20CoinMap[c.ForeignChainId] = make(map[string]types.ForeignCoins) + } + erc20CoinMap[c.ForeignChainId][strings.ToLower(c.Asset)] = c + } + } + return erc20CoinMap +} + // GetGasCoinForForeignCoin returns the gas coin for a given chain func (k Keeper) GetGasCoinForForeignCoin(ctx sdk.Context, chainID int64) (types.ForeignCoins, bool) { foreignCoinList := k.GetAllForeignCoinsForChain(ctx, chainID) From 60cdbd0acbab06e0660ea052064dc4b43f796749 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Thu, 18 Apr 2024 15:11:44 -0500 Subject: [PATCH 03/33] split big loop into backwards loop and forwards loop to be more accurate --- x/crosschain/keeper/grpc_query_cctx.go | 46 ++++++++++++++++++-------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/x/crosschain/keeper/grpc_query_cctx.go b/x/crosschain/keeper/grpc_query_cctx.go index ac3d2da63a..6a1b643863 100644 --- a/x/crosschain/keeper/grpc_query_cctx.go +++ b/x/crosschain/keeper/grpc_query_cctx.go @@ -11,6 +11,7 @@ import ( "github.com/zeta-chain/zetacore/pkg/coin" "github.com/zeta-chain/zetacore/x/crosschain/types" fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -226,7 +227,6 @@ func (k Keeper) CctxListPendingWithinRateLimit(c context.Context, req *types.Que if applyLimit { gasCoinRates, erc20CoinRates = k.GetRatelimiterRates(ctx) erc20Coins = k.fungibleKeeper.GetAllForeignERC20CoinMap(ctx) - //rateLimitInZeta = new(big.Float).SetInt(rateLimitFlags.RateLimitInZeta.BigInt()) rateLimitInZeta = sdk.NewDecFromBigInt(rateLimitFlags.Rate.BigInt()) } @@ -235,31 +235,39 @@ func (k Keeper) CctxListPendingWithinRateLimit(c context.Context, req *types.Que totalPending := uint64(0) totalCctxValueInZeta := sdk.NewDec(0) cctxs := make([]*types.CrossChainTx, 0) + pendingNoncesMap := make(map[int64]*observertypes.PendingNonces) - // the criteria to stop adding cctxs to the result + // the criteria to stop adding cctxs to the rpc response maxCCTXsReached := func() bool { // #nosec G701 len always positive return uint32(len(cctxs)) >= limit } - // query pending cctxs for each supported chain + // query pending nonces for each supported chain + // Note: The pending nonces could change during the RPC call, so query them beforehand chains := k.zetaObserverKeeper.GetSupportedChains(ctx) -ChainLoop: for _, chain := range chains { - // skip zeta chain if chain.IsZetaChain() { continue } - - // get pending nonces for this chain pendingNonces, found := k.GetObserverKeeper().GetPendingNonces(ctx, tss.TssPubkey, chain.ChainId) if !found { return nil, status.Error(codes.Internal, "pending nonces not found") } + pendingNoncesMap[chain.ChainId] = &pendingNonces + } + + // query backwards for potential missed pending cctxs for each supported chain +LoopBackwards: + for _, chain := range chains { + if chain.IsZetaChain() { + continue + } // we should at least query 1000 prior to find any pending cctx that we might have missed // this logic is needed because a confirmation of higher nonce will automatically update the p.NonceLow // therefore might mask some lower nonce cctx that is still pending. + pendingNonces := pendingNoncesMap[chain.ChainId] startNonce := pendingNonces.NonceLow - 1 endNonce := pendingNonces.NonceLow - 1000 if endNonce < 0 { @@ -293,7 +301,7 @@ ChainLoop: // criteria #3: if rate limiter is enabled, we should finish the RPC call if the rate limit is exceeded if rateLimitExceeded(chain.ChainId, &cctx, gasCoinRates, erc20CoinRates, erc20Coins, &totalCctxValueInZeta, rateLimitInZeta) { limitExceeded = true - break ChainLoop + break LoopBackwards } } @@ -307,10 +315,21 @@ ChainLoop: } // add the pending nonces to the total pending + // Note: the `totalPending` may not be accurate only if the rate limiter triggers early exit + // `totalPending` is now used for metrics only and it's okay to trade off accuracy for performance // #nosec G701 always in range totalPending += uint64(pendingNonces.NonceHigh - pendingNonces.NonceLow) + } + + // query forwards for pending cctxs for each supported chain +LoopForwards: + for _, chain := range chains { + if chain.IsZetaChain() { + continue + } - // now query the pending nonces that we know are pending + // query the pending cctxs in range [NonceLow, NonceHigh) + pendingNonces := pendingNoncesMap[chain.ChainId] for i := pendingNonces.NonceLow; i < pendingNonces.NonceHigh; i++ { nonceToCctx, found := k.GetObserverKeeper().GetNonceToCctx(ctx, tss.TssPubkey, chain.ChainId, i) if !found { @@ -323,12 +342,12 @@ ChainLoop: // only take a `limit` number of pending cctxs as result if maxCCTXsReached() { - break ChainLoop + break LoopForwards } // criteria #3: if rate limiter is enabled, we should finish the RPC call if the rate limit is exceeded if applyLimit && rateLimitExceeded(chain.ChainId, &cctx, gasCoinRates, erc20CoinRates, erc20Coins, &totalCctxValueInZeta, rateLimitInZeta) { limitExceeded = true - break ChainLoop + break LoopForwards } cctxs = append(cctxs, &cctx) } @@ -389,10 +408,9 @@ func convertCctxValue( return sdk.NewDec(0) } - // calculate the reciprocal of `rate` as the amount of zrc20 needed to buy 1 ZETA + // the reciprocal of `rate` is the amount of zrc20 needed to buy 1 ZETA // for example, given rate = 0.8, the reciprocal is 1.25, which means 1.25 ZRC20 can buy 1 ZETA - // given decimals = 6, below calculation is equivalent to 1,000,000 / 1.25 = 800,000 - // which means 800,000 ZRC20 can buy 1 ZETA + // given decimals = 6, the `oneZeta` amount will be 1.25 * 10^6 = 1250000 oneZrc20 := sdk.NewDec(1).Power(decimals) oneZeta := oneZrc20.Quo(rate) From 3f63f227783b1c804eb7a07463f8f14c8c608ed2 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Thu, 18 Apr 2024 17:10:00 -0500 Subject: [PATCH 04/33] adjust zetaclient code to query pending cctx with rate limit --- zetaclient/interfaces/interfaces.go | 1 + zetaclient/testutils/stub/core_bridge.go | 7 ++++ zetaclient/zetabridge/query.go | 26 +++++++++++-- zetaclient/zetacore_observer.go | 48 +++++++++++++++++++----- 4 files changed, 69 insertions(+), 13 deletions(-) diff --git a/zetaclient/interfaces/interfaces.go b/zetaclient/interfaces/interfaces.go index 387e764688..0c803c3497 100644 --- a/zetaclient/interfaces/interfaces.go +++ b/zetaclient/interfaces/interfaces.go @@ -98,6 +98,7 @@ type ZetaCoreBridger interface { GetZetaBlockHeight() (int64, error) GetLastBlockHeightByChain(chain chains.Chain) (*crosschaintypes.LastBlockHeight, error) ListPendingCctx(chainID int64) ([]*crosschaintypes.CrossChainTx, uint64, error) + ListPendingCctxWithRatelimit() ([]*crosschaintypes.CrossChainTx, uint64, bool, error) GetPendingNoncesByChain(chainID int64) (observertypes.PendingNonces, error) GetCctxByNonce(chainID int64, nonce uint64) (*crosschaintypes.CrossChainTx, error) GetOutTxTracker(chain chains.Chain, nonce uint64) (*crosschaintypes.OutTxTracker, error) diff --git a/zetaclient/testutils/stub/core_bridge.go b/zetaclient/testutils/stub/core_bridge.go index 2f0ddaa732..51c2afb7ef 100644 --- a/zetaclient/testutils/stub/core_bridge.go +++ b/zetaclient/testutils/stub/core_bridge.go @@ -121,6 +121,13 @@ func (z *MockZetaCoreBridge) ListPendingCctx(_ int64) ([]*cctxtypes.CrossChainTx return []*cctxtypes.CrossChainTx{}, 0, nil } +func (z *MockZetaCoreBridge) ListPendingCctxWithRatelimit() ([]*cctxtypes.CrossChainTx, uint64, bool, error) { + if z.paused { + return nil, 0, false, errors.New(ErrMsgPaused) + } + return []*cctxtypes.CrossChainTx{}, 0, false, nil +} + func (z *MockZetaCoreBridge) GetPendingNoncesByChain(_ int64) (observerTypes.PendingNonces, error) { if z.paused { return observerTypes.PendingNonces{}, errors.New(ErrMsgPaused) diff --git a/zetaclient/zetabridge/query.go b/zetaclient/zetabridge/query.go index b9e08bef56..fab225c571 100644 --- a/zetaclient/zetabridge/query.go +++ b/zetaclient/zetabridge/query.go @@ -121,18 +121,38 @@ func (b *ZetaCoreBridge) GetObserverList() ([]string, error) { } // ListPendingCctx returns a list of pending cctxs for a given chainID -// the returned list has a limited size of crosschainkeeper.MaxPendingCctxs -// the total number of pending cctxs is returned +// - The max size of the list is crosschainkeeper.MaxPendingCctxs func (b *ZetaCoreBridge) ListPendingCctx(chainID int64) ([]*types.CrossChainTx, uint64, error) { client := types.NewQueryClient(b.grpcConn) maxSizeOption := grpc.MaxCallRecvMsgSize(32 * 1024 * 1024) - resp, err := client.CctxListPending(context.Background(), &types.QueryListCctxPendingRequest{ChainId: chainID}, maxSizeOption) + resp, err := client.CctxListPending( + context.Background(), + &types.QueryListCctxPendingRequest{ChainId: chainID}, + maxSizeOption, + ) if err != nil { return nil, 0, err } return resp.CrossChainTx, resp.TotalPending, nil } +// ListPendingCctxWithRatelimit returns a list of pending cctxs that do not exceed the outbound rate limit +// - The max size of the list is crosschainkeeper.MaxPendingCctxs +// - The returned `rateLimitExceeded` flag indicates if the rate limit is exceeded or not +func (b *ZetaCoreBridge) ListPendingCctxWithRatelimit() ([]*types.CrossChainTx, uint64, bool, error) { + client := types.NewQueryClient(b.grpcConn) + maxSizeOption := grpc.MaxCallRecvMsgSize(32 * 1024 * 1024) + resp, err := client.CctxListPendingWithinRateLimit( + context.Background(), + &types.QueryListCctxPendingWithRateLimitRequest{}, + maxSizeOption, + ) + if err != nil { + return nil, 0, false, err + } + return resp.CrossChainTx, resp.TotalPending, resp.RateLimitExceeded, nil +} + func (b *ZetaCoreBridge) GetAbortedZetaAmount() (string, error) { client := types.NewQueryClient(b.grpcConn) resp, err := client.ZetaAccounting(context.Background(), &types.QueryZetaAccountingRequest{}) diff --git a/zetaclient/zetacore_observer.go b/zetaclient/zetacore_observer.go index 48771bc9bc..a40b7f22b8 100644 --- a/zetaclient/zetacore_observer.go +++ b/zetaclient/zetacore_observer.go @@ -130,16 +130,29 @@ func (co *CoreObserver) startCctxScheduler(appContext *appcontext.AppContext) { } } - // Set Current Hot key burn rate + // set current hot key burn rate metrics.HotKeyBurnRate.Set(float64(co.ts.HotKeyBurnRate.GetBurnRate().Int64())) + // query pending cctxs across all foreign chains with rate limit + cctxMap, err := co.getAllPendingCctxWithRatelimit() + if err != nil { + co.logger.ZetaChainWatcher.Error().Err(err).Msgf("startCctxScheduler: queryPendingCctxWithRatelimit failed") + } + // schedule keysign for pending cctxs on each chain coreContext := appContext.ZetaCoreContext() supportedChains := coreContext.GetEnabledChains() for _, c := range supportedChains { - if c.ChainId == co.bridge.ZetaChain().ChainId { + if c.IsZetaChain() { + continue + } + // get cctxs from map and set pending transactions prometheus gauge + cctxList := cctxMap[c.ChainId] + metrics.PendingTxsPerChain.WithLabelValues(c.ChainName.String()).Set(float64(len(cctxList))) + if len(cctxList) == 0 { continue } + // update chain parameters for signer and chain client signer, err := co.GetUpdatedSigner(coreContext, c.ChainId) if err != nil { @@ -155,14 +168,6 @@ func (co *CoreObserver) startCctxScheduler(appContext *appcontext.AppContext) { continue } - cctxList, totalPending, err := co.bridge.ListPendingCctx(c.ChainId) - if err != nil { - co.logger.ZetaChainWatcher.Error().Err(err).Msgf("startCctxScheduler: ListPendingCctx failed for chain %d", c.ChainId) - continue - } - // Set Pending transactions prometheus gauge - metrics.PendingTxsPerChain.WithLabelValues(c.ChainName.String()).Set(float64(totalPending)) - // #nosec G701 range is verified zetaHeight := uint64(bn) if chains.IsEVMChain(c.ChainId) { @@ -184,6 +189,29 @@ func (co *CoreObserver) startCctxScheduler(appContext *appcontext.AppContext) { } } +// getAllPendingCctxWithRatelimit get pending cctxs across all foreign chains with rate limit +func (co *CoreObserver) getAllPendingCctxWithRatelimit() (map[int64][]*types.CrossChainTx, error) { + cctxList, totalPending, rateLimitExceeded, err := co.bridge.ListPendingCctxWithRatelimit() + if err != nil { + return nil, err + } + if rateLimitExceeded { + co.logger.ZetaChainWatcher.Warn().Msgf("rate limit exceeded, fetched %d cctxs out of %d", len(cctxList), totalPending) + } + + // classify pending cctxs by chain id + cctxMap := make(map[int64][]*types.CrossChainTx) + for _, cctx := range cctxList { + chainID := cctx.GetCurrentOutTxParam().ReceiverChainId + if _, found := cctxMap[chainID]; !found { + cctxMap[chainID] = make([]*types.CrossChainTx, 0) + } + cctxMap[chainID] = append(cctxMap[chainID], cctx) + } + + return cctxMap, nil +} + // scheduleCctxEVM schedules evm outtx keysign on each ZetaChain block (the ticker) func (co *CoreObserver) scheduleCctxEVM( outTxMan *outtxprocessor.Processor, From f0b0677643268b221197d84acb5a69d20cf2708a Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Thu, 18 Apr 2024 22:33:53 -0500 Subject: [PATCH 05/33] update change log and add one more rate limiter flag test --- changelog.md | 1 + .../keeper/rate_limiter_flags_test.go | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/changelog.md b/changelog.md index fd1a9c8b99..c5c6c413d1 100644 --- a/changelog.md +++ b/changelog.md @@ -53,6 +53,7 @@ * [1935](https://github.com/zeta-chain/node/pull/1935) - add an operational authority group * [1954](https://github.com/zeta-chain/node/pull/1954) - add metric for concurrent keysigns * [2006](https://github.com/zeta-chain/node/pull/2006) - add Amoy testnet static chain information +* [2045](https://github.com/zeta-chain/node/pull/2046) - add grpc query with outbound rate limit for zetaclient to use * [2046](https://github.com/zeta-chain/node/pull/2046) - add state variable in crosschain for rate limiter flags ### Tests diff --git a/x/crosschain/keeper/rate_limiter_flags_test.go b/x/crosschain/keeper/rate_limiter_flags_test.go index 044d02bc67..0b8010031d 100644 --- a/x/crosschain/keeper/rate_limiter_flags_test.go +++ b/x/crosschain/keeper/rate_limiter_flags_test.go @@ -1,11 +1,16 @@ package keeper_test import ( + "strings" "testing" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/pkg/chains" + "github.com/zeta-chain/zetacore/pkg/coin" 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_GetRateLimiterFlags(t *testing.T) { @@ -22,3 +27,65 @@ func TestKeeper_GetRateLimiterFlags(t *testing.T) { require.True(t, found) require.Equal(t, flags, r) } + +func TestKeeper_GetRateLimiterRates(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + + // create test flags + zrc20GasAddr := sample.EthAddress().Hex() + zrc20ERC20Addr1 := sample.EthAddress().Hex() + zrc20ERC20Addr2 := sample.EthAddress().Hex() + flags := types.RateLimiterFlags{ + Rate: sdk.NewUint(100), + Conversions: []types.Conversion{ + { + Zrc20: zrc20GasAddr, + Rate: sdk.NewDec(1), + }, + { + Zrc20: zrc20ERC20Addr1, + Rate: sdk.NewDec(2), + }, + { + Zrc20: zrc20ERC20Addr2, + Rate: sdk.NewDec(3), + }, + }, + } + + chainID := chains.GoerliLocalnetChain().ChainId + + // add gas coin + fcGas := sample.ForeignCoins(t, zrc20GasAddr) + fcGas.CoinType = coin.CoinType_Gas + fcGas.ForeignChainId = chainID + zk.FungibleKeeper.SetForeignCoins(ctx, fcGas) + + // add two erc20 coins + asset1 := sample.EthAddress().Hex() + fcERC20 := sample.ForeignCoins(t, zrc20ERC20Addr1) + fcERC20.Asset = asset1 + fcERC20.ForeignChainId = chainID + zk.FungibleKeeper.SetForeignCoins(ctx, fcERC20) + + asset2 := sample.EthAddress().Hex() + fcERC20 = sample.ForeignCoins(t, zrc20ERC20Addr2) + fcERC20.Asset = asset2 + fcERC20.ForeignChainId = chainID + zk.FungibleKeeper.SetForeignCoins(ctx, fcERC20) + + // set flags + k.SetRateLimiterFlags(ctx, flags) + r, found := k.GetRateLimiterFlags(ctx) + require.True(t, found) + require.Equal(t, flags, r) + + // get rates + gasRates, erc20Rates := k.GetRateLimiterRates(ctx) + require.Equal(t, 1, len(gasRates)) + require.Equal(t, 1, len(erc20Rates)) + require.Equal(t, sdk.NewDec(1), gasRates[chainID]) + require.Equal(t, 2, len(erc20Rates[chainID])) + require.Equal(t, sdk.NewDec(2), erc20Rates[chainID][strings.ToLower(asset1)]) + require.Equal(t, sdk.NewDec(3), erc20Rates[chainID][strings.ToLower(asset2)]) +} From aab441e9a7a6e8a5bfb20e91a1b502ca9475beee Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Thu, 18 Apr 2024 23:25:34 -0500 Subject: [PATCH 06/33] use outboun amount for calculation --- x/crosschain/keeper/grpc_query_cctx.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/crosschain/keeper/grpc_query_cctx.go b/x/crosschain/keeper/grpc_query_cctx.go index 9c6290aa26..1ab7078b1a 100644 --- a/x/crosschain/keeper/grpc_query_cctx.go +++ b/x/crosschain/keeper/grpc_query_cctx.go @@ -415,7 +415,7 @@ func convertCctxValue( oneZeta := oneZrc20.Quo(rate) // convert asset amount into ZETA - amountCctx := sdk.NewDecFromBigInt(cctx.InboundTxParams.Amount.BigInt()) + amountCctx := sdk.NewDecFromBigInt(cctx.GetCurrentOutTxParam().Amount.BigInt()) amountZeta := amountCctx.Quo(oneZeta) return amountZeta } From 00ab5acde7a9f40fdef26c38abd573b2c49d60cd Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Fri, 19 Apr 2024 10:55:11 -0500 Subject: [PATCH 07/33] some minimum code refactor --- testutil/keeper/mocks/crosschain/observer.go | 20 ++++ x/crosschain/keeper/cctx_utils.go | 2 +- x/crosschain/keeper/cctx_utils_test.go | 2 +- x/crosschain/keeper/grpc_query_cctx.go | 98 ++++++++----------- .../keeper/msg_server_add_to_outtx_tracker.go | 2 +- x/crosschain/types/expected_keepers.go | 1 + x/observer/keeper/chain_params.go | 13 +++ zetaclient/evm/evm_signer.go | 2 +- 8 files changed, 78 insertions(+), 62 deletions(-) diff --git a/testutil/keeper/mocks/crosschain/observer.go b/testutil/keeper/mocks/crosschain/observer.go index aa05e13226..37b8ea2720 100644 --- a/testutil/keeper/mocks/crosschain/observer.go +++ b/testutil/keeper/mocks/crosschain/observer.go @@ -596,6 +596,26 @@ func (_m *CrosschainObserverKeeper) GetSupportedChains(ctx types.Context) []*cha return r0 } +// GetSupportedForeignChains provides a mock function with given fields: ctx +func (_m *CrosschainObserverKeeper) GetSupportedForeignChains(ctx types.Context) []*chains.Chain { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for GetSupportedForeignChains") + } + + var r0 []*chains.Chain + if rf, ok := ret.Get(0).(func(types.Context) []*chains.Chain); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*chains.Chain) + } + } + + return r0 +} + // GetTSS provides a mock function with given fields: ctx func (_m *CrosschainObserverKeeper) GetTSS(ctx types.Context) (observertypes.TSS, bool) { ret := _m.Called(ctx) diff --git a/x/crosschain/keeper/cctx_utils.go b/x/crosschain/keeper/cctx_utils.go index 6ae826f9ed..6f9651967a 100644 --- a/x/crosschain/keeper/cctx_utils.go +++ b/x/crosschain/keeper/cctx_utils.go @@ -86,7 +86,7 @@ func (k Keeper) GetRevertGasLimit(ctx sdk.Context, cctx types.CrossChainTx) (uin return 0, nil } -func IsPending(cctx types.CrossChainTx) bool { +func IsPending(cctx *types.CrossChainTx) bool { // pending inbound is not considered a "pending" state because it has not reached consensus yet return cctx.CctxStatus.Status == types.CctxStatus_PendingOutbound || cctx.CctxStatus.Status == types.CctxStatus_PendingRevert } diff --git a/x/crosschain/keeper/cctx_utils_test.go b/x/crosschain/keeper/cctx_utils_test.go index 1c807a97c1..e0dedbb41d 100644 --- a/x/crosschain/keeper/cctx_utils_test.go +++ b/x/crosschain/keeper/cctx_utils_test.go @@ -215,7 +215,7 @@ func Test_IsPending(t *testing.T) { } for _, tc := range tt { t.Run(fmt.Sprintf("status %s", tc.status), func(t *testing.T) { - require.Equal(t, tc.expected, crosschainkeeper.IsPending(types.CrossChainTx{CctxStatus: &types.Status{Status: tc.status}})) + require.Equal(t, tc.expected, crosschainkeeper.IsPending(&types.CrossChainTx{CctxStatus: &types.Status{Status: tc.status}})) }) } } diff --git a/x/crosschain/keeper/grpc_query_cctx.go b/x/crosschain/keeper/grpc_query_cctx.go index 1ab7078b1a..95a2336f31 100644 --- a/x/crosschain/keeper/grpc_query_cctx.go +++ b/x/crosschain/keeper/grpc_query_cctx.go @@ -82,16 +82,12 @@ func (k Keeper) CctxByNonce(c context.Context, req *types.QueryGetCctxByNonceReq return nil, status.Error(codes.Internal, "tss not found") } // #nosec G701 always in range - res, found := k.GetObserverKeeper().GetNonceToCctx(ctx, tss.TssPubkey, req.ChainID, int64(req.Nonce)) - if !found { - return nil, status.Error(codes.Internal, fmt.Sprintf("nonceToCctx not found: nonce %d, chainid %d", req.Nonce, req.ChainID)) - } - val, found := k.GetCrossChainTx(ctx, res.CctxIndex) - if !found { - return nil, status.Error(codes.Internal, fmt.Sprintf("cctx not found: index %s", res.CctxIndex)) + cctx, err := getCctxByChainIDAndNonce(k, ctx, tss.TssPubkey, req.ChainID, int64(req.Nonce)) + if err != nil { + return nil, err } - return &types.QueryGetCctxResponse{CrossChainTx: &val}, nil + return &types.QueryGetCctxResponse{CrossChainTx: cctx}, nil } // CctxListPending returns a list of pending cctxs and the total number of pending cctxs @@ -138,20 +134,16 @@ func (k Keeper) CctxListPending(c context.Context, req *types.QueryListCctxPendi startNonce = 0 } for i := startNonce; i < pendingNonces.NonceLow; i++ { - nonceToCctx, found := k.GetObserverKeeper().GetNonceToCctx(ctx, tss.TssPubkey, req.ChainId, i) - if !found { - return nil, status.Error(codes.Internal, fmt.Sprintf("nonceToCctx not found: nonce %d, chainid %d", i, req.ChainId)) - } - cctx, found := k.GetCrossChainTx(ctx, nonceToCctx.CctxIndex) - if !found { - return nil, status.Error(codes.Internal, fmt.Sprintf("cctx not found: index %s", nonceToCctx.CctxIndex)) + cctx, err := getCctxByChainIDAndNonce(k, ctx, tss.TssPubkey, req.ChainId, i) + if err != nil { + return nil, err } // only take a `limit` number of pending cctxs as result but still count the total pending cctxs if IsPending(cctx) { totalPending++ if !maxCCTXsReached() { - cctxs = append(cctxs, &cctx) + cctxs = append(cctxs, cctx) } } } @@ -162,15 +154,11 @@ func (k Keeper) CctxListPending(c context.Context, req *types.QueryListCctxPendi // now query the pending nonces that we know are pending for i := pendingNonces.NonceLow; i < pendingNonces.NonceHigh && !maxCCTXsReached(); i++ { - nonceToCctx, found := k.GetObserverKeeper().GetNonceToCctx(ctx, tss.TssPubkey, req.ChainId, i) - if !found { - return nil, status.Error(codes.Internal, "nonceToCctx not found") + cctx, err := getCctxByChainIDAndNonce(k, ctx, tss.TssPubkey, req.ChainId, i) + if err != nil { + return nil, err } - cctx, found := k.GetCrossChainTx(ctx, nonceToCctx.CctxIndex) - if !found { - return nil, status.Error(codes.Internal, "cctxIndex not found") - } - cctxs = append(cctxs, &cctx) + cctxs = append(cctxs, cctx) } return &types.QueryListCctxPendingResponse{ @@ -243,13 +231,10 @@ func (k Keeper) CctxListPendingWithinRateLimit(c context.Context, req *types.Que return uint32(len(cctxs)) >= limit } - // query pending nonces for each supported chain + // query pending nonces for each foreign chain // Note: The pending nonces could change during the RPC call, so query them beforehand - chains := k.zetaObserverKeeper.GetSupportedChains(ctx) + chains := k.zetaObserverKeeper.GetSupportedForeignChains(ctx) for _, chain := range chains { - if chain.IsZetaChain() { - continue - } pendingNonces, found := k.GetObserverKeeper().GetPendingNonces(ctx, tss.TssPubkey, chain.ChainId) if !found { return nil, status.Error(codes.Internal, "pending nonces not found") @@ -257,13 +242,9 @@ func (k Keeper) CctxListPendingWithinRateLimit(c context.Context, req *types.Que pendingNoncesMap[chain.ChainId] = &pendingNonces } - // query backwards for potential missed pending cctxs for each supported chain + // query backwards for potential missed pending cctxs for each foreign chain LoopBackwards: for _, chain := range chains { - if chain.IsZetaChain() { - continue - } - // we should at least query 1000 prior to find any pending cctx that we might have missed // this logic is needed because a confirmation of higher nonce will automatically update the p.NonceLow // therefore might mask some lower nonce cctx that is still pending. @@ -276,13 +257,9 @@ LoopBackwards: // query cctx by nonce backwards to the left boundary of the rate limit sliding window for nonce := startNonce; nonce >= 0; nonce-- { - nonceToCctx, found := k.GetObserverKeeper().GetNonceToCctx(ctx, tss.TssPubkey, chain.ChainId, nonce) - if !found { - return nil, status.Error(codes.Internal, fmt.Sprintf("nonceToCctx not found: chainid %d, nonce %d", chain.ChainId, nonce)) - } - cctx, found := k.GetCrossChainTx(ctx, nonceToCctx.CctxIndex) - if !found { - return nil, status.Error(codes.Internal, fmt.Sprintf("cctx not found: index %s", nonceToCctx.CctxIndex)) + cctx, err := getCctxByChainIDAndNonce(k, ctx, tss.TssPubkey, chain.ChainId, nonce) + if err != nil { + return nil, err } // We should at least go backwards by 1000 nonces to pick up missed pending cctxs @@ -299,7 +276,7 @@ LoopBackwards: break } // criteria #3: if rate limiter is enabled, we should finish the RPC call if the rate limit is exceeded - if rateLimitExceeded(chain.ChainId, &cctx, gasCoinRates, erc20CoinRates, erc20Coins, &totalCctxValueInZeta, rateLimitInZeta) { + if rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, erc20Coins, &totalCctxValueInZeta, rateLimitInZeta) { limitExceeded = true break LoopBackwards } @@ -309,7 +286,7 @@ LoopBackwards: if IsPending(cctx) { totalPending++ if !maxCCTXsReached() { - cctxs = append(cctxs, &cctx) + cctxs = append(cctxs, cctx) } } } @@ -321,23 +298,15 @@ LoopBackwards: totalPending += uint64(pendingNonces.NonceHigh - pendingNonces.NonceLow) } - // query forwards for pending cctxs for each supported chain + // query forwards for pending cctxs for each foreign chain LoopForwards: for _, chain := range chains { - if chain.IsZetaChain() { - continue - } - // query the pending cctxs in range [NonceLow, NonceHigh) pendingNonces := pendingNoncesMap[chain.ChainId] - for i := pendingNonces.NonceLow; i < pendingNonces.NonceHigh; i++ { - nonceToCctx, found := k.GetObserverKeeper().GetNonceToCctx(ctx, tss.TssPubkey, chain.ChainId, i) - if !found { - return nil, status.Error(codes.Internal, "nonceToCctx not found") - } - cctx, found := k.GetCrossChainTx(ctx, nonceToCctx.CctxIndex) - if !found { - return nil, status.Error(codes.Internal, "cctxIndex not found") + for nonce := pendingNonces.NonceLow; nonce < pendingNonces.NonceHigh; nonce++ { + cctx, err := getCctxByChainIDAndNonce(k, ctx, tss.TssPubkey, chain.ChainId, nonce) + if err != nil { + return nil, err } // only take a `limit` number of pending cctxs as result @@ -345,11 +314,11 @@ LoopForwards: break LoopForwards } // criteria #3: if rate limiter is enabled, we should finish the RPC call if the rate limit is exceeded - if applyLimit && rateLimitExceeded(chain.ChainId, &cctx, gasCoinRates, erc20CoinRates, erc20Coins, &totalCctxValueInZeta, rateLimitInZeta) { + if applyLimit && rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, erc20Coins, &totalCctxValueInZeta, rateLimitInZeta) { limitExceeded = true break LoopForwards } - cctxs = append(cctxs, &cctx) + cctxs = append(cctxs, cctx) } } @@ -360,6 +329,19 @@ LoopForwards: }, nil } +// getCctxByChainIDAndNonce returns the cctx by chainID and nonce +func getCctxByChainIDAndNonce(k Keeper, ctx sdk.Context, tssPubkey string, chainID int64, nonce int64) (*types.CrossChainTx, error) { + nonceToCctx, found := k.GetObserverKeeper().GetNonceToCctx(ctx, tssPubkey, chainID, nonce) + if !found { + return nil, status.Error(codes.Internal, fmt.Sprintf("nonceToCctx not found: chainid %d, nonce %d", chainID, nonce)) + } + cctx, found := k.GetCrossChainTx(ctx, nonceToCctx.CctxIndex) + if !found { + return nil, status.Error(codes.Internal, fmt.Sprintf("cctx not found: index %s", nonceToCctx.CctxIndex)) + } + return &cctx, nil +} + // convertCctxValue converts the value of the cctx in ZETA using given conversion rates func convertCctxValue( chainID int64, diff --git a/x/crosschain/keeper/msg_server_add_to_outtx_tracker.go b/x/crosschain/keeper/msg_server_add_to_outtx_tracker.go index 9031d0bfe5..4f149a901f 100644 --- a/x/crosschain/keeper/msg_server_add_to_outtx_tracker.go +++ b/x/crosschain/keeper/msg_server_add_to_outtx_tracker.go @@ -41,7 +41,7 @@ func (k msgServer) AddToOutTxTracker(goCtx context.Context, msg *types.MsgAddToO } // tracker submission is only allowed when the cctx is pending - if !IsPending(*cctx.CrossChainTx) { + if !IsPending(cctx.CrossChainTx) { // garbage tracker (for any reason) is harmful to outTx observation and should be removed if it exists // it if does not exist, RemoveOutTxTracker is a no-op k.RemoveOutTxTracker(ctx, msg.ChainId, msg.Nonce) diff --git a/x/crosschain/types/expected_keepers.go b/x/crosschain/types/expected_keepers.go index cbcaede349..3d524a91cb 100644 --- a/x/crosschain/types/expected_keepers.go +++ b/x/crosschain/types/expected_keepers.go @@ -90,6 +90,7 @@ type ObserverKeeper interface { ) (bool, bool, observertypes.Ballot, string, error) GetSupportedChainFromChainID(ctx sdk.Context, chainID int64) *chains.Chain GetSupportedChains(ctx sdk.Context) []*chains.Chain + GetSupportedForeignChains(ctx sdk.Context) []*chains.Chain } type FungibleKeeper interface { diff --git a/x/observer/keeper/chain_params.go b/x/observer/keeper/chain_params.go index 7b5e0a246e..8c4d7301fb 100644 --- a/x/observer/keeper/chain_params.go +++ b/x/observer/keeper/chain_params.go @@ -71,3 +71,16 @@ func (k Keeper) GetSupportedChains(ctx sdk.Context) []*chains.Chain { } return c } + +// GetSupportedForeignChains returns the list of supported foreign chains +func (k Keeper) GetSupportedForeignChains(ctx sdk.Context) []*chains.Chain { + allChains := k.GetSupportedChains(ctx) + + foreignChains := make([]*chains.Chain, 0) + for _, chain := range allChains { + if !chain.IsZetaChain() { + foreignChains = append(foreignChains, chain) + } + } + return foreignChains +} diff --git a/zetaclient/evm/evm_signer.go b/zetaclient/evm/evm_signer.go index e077d19fe2..cd038f2912 100644 --- a/zetaclient/evm/evm_signer.go +++ b/zetaclient/evm/evm_signer.go @@ -560,7 +560,7 @@ func (signer *Signer) reportToOutTxTracker(zetaBridge interfaces.ZetaCoreBridger cctx, err := zetaBridge.GetCctxByNonce(chainID, nonce) if err != nil { logger.Err(err).Msgf("reportToOutTxTracker: error getting cctx for chain %d nonce %d outTxHash %s", chainID, nonce, outTxHash) - } else if !crosschainkeeper.IsPending(*cctx) { + } else if !crosschainkeeper.IsPending(cctx) { logger.Info().Msgf("reportToOutTxTracker: cctx already finalized for chain %d nonce %d outTxHash %s", chainID, nonce, outTxHash) break } From f31c988378329b4e88a85ebeee43b57990b09b92 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Fri, 19 Apr 2024 11:20:15 -0500 Subject: [PATCH 08/33] created separate file for cctx query with rate limit --- x/crosschain/keeper/grpc_query_cctx.go | 242 ----------------- .../keeper/grpc_query_cctx_rate_limit.go | 253 ++++++++++++++++++ .../keeper/grpc_query_cctx_rate_limit_test.go | 38 +++ x/crosschain/keeper/grpc_query_cctx_test.go | 30 --- 4 files changed, 291 insertions(+), 272 deletions(-) create mode 100644 x/crosschain/keeper/grpc_query_cctx_rate_limit.go create mode 100644 x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go diff --git a/x/crosschain/keeper/grpc_query_cctx.go b/x/crosschain/keeper/grpc_query_cctx.go index 95a2336f31..5e916beeac 100644 --- a/x/crosschain/keeper/grpc_query_cctx.go +++ b/x/crosschain/keeper/grpc_query_cctx.go @@ -3,15 +3,11 @@ package keeper import ( "context" "fmt" - "strings" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" - "github.com/zeta-chain/zetacore/pkg/coin" "github.com/zeta-chain/zetacore/x/crosschain/types" - fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" - observertypes "github.com/zeta-chain/zetacore/x/observer/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -167,168 +163,6 @@ func (k Keeper) CctxListPending(c context.Context, req *types.QueryListCctxPendi }, nil } -// CctxListPendingWithinRateLimit returns a list of pending cctxs that do not exceed the outbound rate limit -// a limit for the number of cctxs to return can be specified or the default is MaxPendingCctxs -func (k Keeper) CctxListPendingWithinRateLimit(c context.Context, req *types.QueryListCctxPendingWithRateLimitRequest) (*types.QueryListCctxPendingWithRateLimitResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - - // check limit and use default MaxPendingCctxs if not specified - if req.Limit > MaxPendingCctxs { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("limit exceeds max limit of %d", MaxPendingCctxs)) - } - limit := req.Limit - if limit == 0 { - limit = MaxPendingCctxs - } - - // get current height and tss - ctx := sdk.UnwrapSDKContext(c) - height := ctx.BlockHeight() - if height <= 0 { - return nil, status.Error(codes.OutOfRange, "height out of range") - } - tss, found := k.zetaObserverKeeper.GetTSS(ctx) - if !found { - return nil, status.Error(codes.Internal, "tss not found") - } - - // check rate limit flags to decide if we should apply rate limit - applyLimit := true - rateLimitFlags, found := k.GetRateLimiterFlags(ctx) - if !found || !rateLimitFlags.Enabled { - applyLimit = false - } - - // calculate the rate limiter sliding window left boundary (inclusive) - leftWindowBoundary := height - rateLimitFlags.Window - if leftWindowBoundary < 0 { - leftWindowBoundary = 0 - } - - // get the conversion rates for all foreign coins - var gasCoinRates map[int64]sdk.Dec - var erc20CoinRates map[int64]map[string]sdk.Dec - var erc20Coins map[int64]map[string]fungibletypes.ForeignCoins - var rateLimitInZeta sdk.Dec - if applyLimit { - gasCoinRates, erc20CoinRates = k.GetRateLimiterRates(ctx) - erc20Coins = k.fungibleKeeper.GetAllForeignERC20CoinMap(ctx) - rateLimitInZeta = sdk.NewDecFromBigInt(rateLimitFlags.Rate.BigInt()) - } - - // define a few variables to be used in the below loops - limitExceeded := false - totalPending := uint64(0) - totalCctxValueInZeta := sdk.NewDec(0) - cctxs := make([]*types.CrossChainTx, 0) - pendingNoncesMap := make(map[int64]*observertypes.PendingNonces) - - // the criteria to stop adding cctxs to the rpc response - maxCCTXsReached := func() bool { - // #nosec G701 len always positive - return uint32(len(cctxs)) >= limit - } - - // query pending nonces for each foreign chain - // Note: The pending nonces could change during the RPC call, so query them beforehand - chains := k.zetaObserverKeeper.GetSupportedForeignChains(ctx) - for _, chain := range chains { - pendingNonces, found := k.GetObserverKeeper().GetPendingNonces(ctx, tss.TssPubkey, chain.ChainId) - if !found { - return nil, status.Error(codes.Internal, "pending nonces not found") - } - pendingNoncesMap[chain.ChainId] = &pendingNonces - } - - // query backwards for potential missed pending cctxs for each foreign chain -LoopBackwards: - for _, chain := range chains { - // we should at least query 1000 prior to find any pending cctx that we might have missed - // this logic is needed because a confirmation of higher nonce will automatically update the p.NonceLow - // therefore might mask some lower nonce cctx that is still pending. - pendingNonces := pendingNoncesMap[chain.ChainId] - startNonce := pendingNonces.NonceLow - 1 - endNonce := pendingNonces.NonceLow - 1000 - if endNonce < 0 { - endNonce = 0 - } - - // query cctx by nonce backwards to the left boundary of the rate limit sliding window - for nonce := startNonce; nonce >= 0; nonce-- { - cctx, err := getCctxByChainIDAndNonce(k, ctx, tss.TssPubkey, chain.ChainId, nonce) - if err != nil { - return nil, err - } - - // We should at least go backwards by 1000 nonces to pick up missed pending cctxs - // We might go even further back if rate limiter is enabled and the endNonce hasn't hit the left window boundary yet - // There are three criteria to stop scanning backwards: - // criteria #1: if rate limiter is disabled, we should stop exactly on the `endNonce` - if !applyLimit && nonce < endNonce { - break - } - if applyLimit { - // criteria #2: if rate limiter is enabled, we'll stop at the left window boundary if the `endNonce` hasn't hit it yet - // #nosec G701 always positive - if nonce < endNonce && cctx.InboundTxParams.InboundTxObservedExternalHeight < uint64(leftWindowBoundary) { - break - } - // criteria #3: if rate limiter is enabled, we should finish the RPC call if the rate limit is exceeded - if rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, erc20Coins, &totalCctxValueInZeta, rateLimitInZeta) { - limitExceeded = true - break LoopBackwards - } - } - - // only take a `limit` number of pending cctxs as result but still count the total pending cctxs - if IsPending(cctx) { - totalPending++ - if !maxCCTXsReached() { - cctxs = append(cctxs, cctx) - } - } - } - - // add the pending nonces to the total pending - // Note: the `totalPending` may not be accurate only if the rate limiter triggers early exit - // `totalPending` is now used for metrics only and it's okay to trade off accuracy for performance - // #nosec G701 always in range - totalPending += uint64(pendingNonces.NonceHigh - pendingNonces.NonceLow) - } - - // query forwards for pending cctxs for each foreign chain -LoopForwards: - for _, chain := range chains { - // query the pending cctxs in range [NonceLow, NonceHigh) - pendingNonces := pendingNoncesMap[chain.ChainId] - for nonce := pendingNonces.NonceLow; nonce < pendingNonces.NonceHigh; nonce++ { - cctx, err := getCctxByChainIDAndNonce(k, ctx, tss.TssPubkey, chain.ChainId, nonce) - if err != nil { - return nil, err - } - - // only take a `limit` number of pending cctxs as result - if maxCCTXsReached() { - break LoopForwards - } - // criteria #3: if rate limiter is enabled, we should finish the RPC call if the rate limit is exceeded - if applyLimit && rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, erc20Coins, &totalCctxValueInZeta, rateLimitInZeta) { - limitExceeded = true - break LoopForwards - } - cctxs = append(cctxs, cctx) - } - } - - return &types.QueryListCctxPendingWithRateLimitResponse{ - CrossChainTx: cctxs, - TotalPending: totalPending, - RateLimitExceeded: limitExceeded, - }, nil -} - // getCctxByChainIDAndNonce returns the cctx by chainID and nonce func getCctxByChainIDAndNonce(k Keeper, ctx sdk.Context, tssPubkey string, chainID int64, nonce int64) (*types.CrossChainTx, error) { nonceToCctx, found := k.GetObserverKeeper().GetNonceToCctx(ctx, tssPubkey, chainID, nonce) @@ -341,79 +175,3 @@ func getCctxByChainIDAndNonce(k Keeper, ctx sdk.Context, tssPubkey string, chain } return &cctx, nil } - -// convertCctxValue converts the value of the cctx in ZETA using given conversion rates -func convertCctxValue( - chainID int64, - cctx *types.CrossChainTx, - gasCoinRates map[int64]sdk.Dec, - erc20CoinRates map[int64]map[string]sdk.Dec, - erc20Coins map[int64]map[string]fungibletypes.ForeignCoins, -) sdk.Dec { - var rate sdk.Dec - var decimals uint64 - switch cctx.InboundTxParams.CoinType { - case coin.CoinType_Zeta: - // no conversion needed for ZETA - rate = sdk.NewDec(1) - case coin.CoinType_Gas: - rate = gasCoinRates[chainID] - case coin.CoinType_ERC20: - // get the ERC20 coin decimals - _, found := erc20Coins[chainID] - if !found { - // skip if no coin found for this chainID - return sdk.NewDec(0) - } - fCoin, found := erc20Coins[chainID][strings.ToLower(cctx.InboundTxParams.Asset)] - if !found { - // skip if no coin found for this Asset - return sdk.NewDec(0) - } - // #nosec G701 always in range - decimals = uint64(fCoin.Decimals) - - // get the ERC20 coin rate - _, found = erc20CoinRates[chainID] - if !found { - // skip if no rate found for this chainID - return sdk.NewDec(0) - } - rate = erc20CoinRates[chainID][strings.ToLower(cctx.InboundTxParams.Asset)] - default: - // skip CoinType_Cmd - return sdk.NewDec(0) - } - - // should not happen, return 0 to skip if it happens - if rate.LTE(sdk.NewDec(0)) { - return sdk.NewDec(0) - } - - // the reciprocal of `rate` is the amount of zrc20 needed to buy 1 ZETA - // for example, given rate = 0.8, the reciprocal is 1.25, which means 1.25 ZRC20 can buy 1 ZETA - // given decimals = 6, the `oneZeta` amount will be 1.25 * 10^6 = 1250000 - oneZrc20 := sdk.NewDec(1).Power(decimals) - oneZeta := oneZrc20.Quo(rate) - - // convert asset amount into ZETA - amountCctx := sdk.NewDecFromBigInt(cctx.GetCurrentOutTxParam().Amount.BigInt()) - amountZeta := amountCctx.Quo(oneZeta) - return amountZeta -} - -// rateLimitExceeded accumulates the cctx value and then checks if the rate limit is exceeded -// returns true if the rate limit is exceeded -func rateLimitExceeded( - chainID int64, - cctx *types.CrossChainTx, - gasCoinRates map[int64]sdk.Dec, - erc20CoinRates map[int64]map[string]sdk.Dec, - erc20Coins map[int64]map[string]fungibletypes.ForeignCoins, - currentCctxValue *sdk.Dec, - rateLimitValue sdk.Dec, -) bool { - amountZeta := convertCctxValue(chainID, cctx, gasCoinRates, erc20CoinRates, erc20Coins) - *currentCctxValue = currentCctxValue.Add(amountZeta) - return currentCctxValue.GT(rateLimitValue) -} diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go new file mode 100644 index 0000000000..9f277cc556 --- /dev/null +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go @@ -0,0 +1,253 @@ +package keeper + +import ( + "context" + "fmt" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/zeta-chain/zetacore/pkg/coin" + "github.com/zeta-chain/zetacore/x/crosschain/types" + fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// CctxListPendingWithinRateLimit returns a list of pending cctxs that do not exceed the outbound rate limit +// a limit for the number of cctxs to return can be specified or the default is MaxPendingCctxs +func (k Keeper) CctxListPendingWithinRateLimit(c context.Context, req *types.QueryListCctxPendingWithRateLimitRequest) (*types.QueryListCctxPendingWithRateLimitResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + + // check limit and use default MaxPendingCctxs if not specified + if req.Limit > MaxPendingCctxs { + return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("limit exceeds max limit of %d", MaxPendingCctxs)) + } + limit := req.Limit + if limit == 0 { + limit = MaxPendingCctxs + } + + // get current height and tss + ctx := sdk.UnwrapSDKContext(c) + height := ctx.BlockHeight() + if height <= 0 { + return nil, status.Error(codes.OutOfRange, "height out of range") + } + tss, found := k.zetaObserverKeeper.GetTSS(ctx) + if !found { + return nil, status.Error(codes.Internal, "tss not found") + } + + // check rate limit flags to decide if we should apply rate limit + applyLimit := true + rateLimitFlags, found := k.GetRateLimiterFlags(ctx) + if !found || !rateLimitFlags.Enabled { + applyLimit = false + } + + // calculate the rate limiter sliding window left boundary (inclusive) + leftWindowBoundary := height - rateLimitFlags.Window + if leftWindowBoundary < 0 { + leftWindowBoundary = 0 + } + + // get the conversion rates for all foreign coins + var gasCoinRates map[int64]sdk.Dec + var erc20CoinRates map[int64]map[string]sdk.Dec + var erc20Coins map[int64]map[string]fungibletypes.ForeignCoins + var rateLimitInZeta sdk.Dec + if applyLimit { + gasCoinRates, erc20CoinRates = k.GetRateLimiterRates(ctx) + erc20Coins = k.fungibleKeeper.GetAllForeignERC20CoinMap(ctx) + rateLimitInZeta = sdk.NewDecFromBigInt(rateLimitFlags.Rate.BigInt()) + } + + // define a few variables to be used in the below loops + limitExceeded := false + totalPending := uint64(0) + totalCctxValueInZeta := sdk.NewDec(0) + cctxs := make([]*types.CrossChainTx, 0) + pendingNoncesMap := make(map[int64]*observertypes.PendingNonces) + + // the criteria to stop adding cctxs to the rpc response + maxCCTXsReached := func() bool { + // #nosec G701 len always positive + return uint32(len(cctxs)) >= limit + } + + // query pending nonces for each foreign chain + // Note: The pending nonces could change during the RPC call, so query them beforehand + chains := k.zetaObserverKeeper.GetSupportedForeignChains(ctx) + for _, chain := range chains { + pendingNonces, found := k.GetObserverKeeper().GetPendingNonces(ctx, tss.TssPubkey, chain.ChainId) + if !found { + return nil, status.Error(codes.Internal, "pending nonces not found") + } + pendingNoncesMap[chain.ChainId] = &pendingNonces + } + + // query backwards for potential missed pending cctxs for each foreign chain +LoopBackwards: + for _, chain := range chains { + // we should at least query 1000 prior to find any pending cctx that we might have missed + // this logic is needed because a confirmation of higher nonce will automatically update the p.NonceLow + // therefore might mask some lower nonce cctx that is still pending. + pendingNonces := pendingNoncesMap[chain.ChainId] + startNonce := pendingNonces.NonceLow - 1 + endNonce := pendingNonces.NonceLow - 1000 + if endNonce < 0 { + endNonce = 0 + } + + // query cctx by nonce backwards to the left boundary of the rate limit sliding window + for nonce := startNonce; nonce >= 0; nonce-- { + cctx, err := getCctxByChainIDAndNonce(k, ctx, tss.TssPubkey, chain.ChainId, nonce) + if err != nil { + return nil, err + } + + // We should at least go backwards by 1000 nonces to pick up missed pending cctxs + // We might go even further back if rate limiter is enabled and the endNonce hasn't hit the left window boundary yet + // There are three criteria to stop scanning backwards: + // criteria #1: if rate limiter is disabled, we should stop exactly on the `endNonce` + if !applyLimit && nonce < endNonce { + break + } + if applyLimit { + // criteria #2: if rate limiter is enabled, we'll stop at the left window boundary if the `endNonce` hasn't hit it yet + // #nosec G701 always positive + if nonce < endNonce && cctx.InboundTxParams.InboundTxObservedExternalHeight < uint64(leftWindowBoundary) { + break + } + // criteria #3: if rate limiter is enabled, we should finish the RPC call if the rate limit is exceeded + if rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, erc20Coins, &totalCctxValueInZeta, rateLimitInZeta) { + limitExceeded = true + break LoopBackwards + } + } + + // only take a `limit` number of pending cctxs as result but still count the total pending cctxs + if IsPending(cctx) { + totalPending++ + if !maxCCTXsReached() { + cctxs = append(cctxs, cctx) + } + } + } + + // add the pending nonces to the total pending + // Note: the `totalPending` may not be accurate only if the rate limiter triggers early exit + // `totalPending` is now used for metrics only and it's okay to trade off accuracy for performance + // #nosec G701 always in range + totalPending += uint64(pendingNonces.NonceHigh - pendingNonces.NonceLow) + } + + // query forwards for pending cctxs for each foreign chain +LoopForwards: + for _, chain := range chains { + // query the pending cctxs in range [NonceLow, NonceHigh) + pendingNonces := pendingNoncesMap[chain.ChainId] + for nonce := pendingNonces.NonceLow; nonce < pendingNonces.NonceHigh; nonce++ { + cctx, err := getCctxByChainIDAndNonce(k, ctx, tss.TssPubkey, chain.ChainId, nonce) + if err != nil { + return nil, err + } + + // only take a `limit` number of pending cctxs as result + if maxCCTXsReached() { + break LoopForwards + } + // criteria #3: if rate limiter is enabled, we should finish the RPC call if the rate limit is exceeded + if applyLimit && rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, erc20Coins, &totalCctxValueInZeta, rateLimitInZeta) { + limitExceeded = true + break LoopForwards + } + cctxs = append(cctxs, cctx) + } + } + + return &types.QueryListCctxPendingWithRateLimitResponse{ + CrossChainTx: cctxs, + TotalPending: totalPending, + RateLimitExceeded: limitExceeded, + }, nil +} + +// convertCctxValue converts the value of the cctx in ZETA using given conversion rates +func convertCctxValue( + chainID int64, + cctx *types.CrossChainTx, + gasCoinRates map[int64]sdk.Dec, + erc20CoinRates map[int64]map[string]sdk.Dec, + erc20Coins map[int64]map[string]fungibletypes.ForeignCoins, +) sdk.Dec { + var rate sdk.Dec + var decimals uint64 + switch cctx.InboundTxParams.CoinType { + case coin.CoinType_Zeta: + // no conversion needed for ZETA + rate = sdk.NewDec(1) + case coin.CoinType_Gas: + rate = gasCoinRates[chainID] + case coin.CoinType_ERC20: + // get the ERC20 coin decimals + _, found := erc20Coins[chainID] + if !found { + // skip if no coin found for this chainID + return sdk.NewDec(0) + } + fCoin, found := erc20Coins[chainID][strings.ToLower(cctx.InboundTxParams.Asset)] + if !found { + // skip if no coin found for this Asset + return sdk.NewDec(0) + } + // #nosec G701 always in range + decimals = uint64(fCoin.Decimals) + + // get the ERC20 coin rate + _, found = erc20CoinRates[chainID] + if !found { + // skip if no rate found for this chainID + return sdk.NewDec(0) + } + rate = erc20CoinRates[chainID][strings.ToLower(cctx.InboundTxParams.Asset)] + default: + // skip CoinType_Cmd + return sdk.NewDec(0) + } + + // should not happen, return 0 to skip if it happens + if rate.LTE(sdk.NewDec(0)) { + return sdk.NewDec(0) + } + + // the reciprocal of `rate` is the amount of zrc20 needed to buy 1 ZETA + // for example, given rate = 0.8, the reciprocal is 1.25, which means 1.25 ZRC20 can buy 1 ZETA + // given decimals = 6, the `oneZeta` amount will be 1.25 * 10^6 = 1250000 + oneZrc20 := sdk.NewDec(1).Power(decimals) + oneZeta := oneZrc20.Quo(rate) + + // convert asset amount into ZETA + amountCctx := sdk.NewDecFromBigInt(cctx.GetCurrentOutTxParam().Amount.BigInt()) + amountZeta := amountCctx.Quo(oneZeta) + return amountZeta +} + +// rateLimitExceeded accumulates the cctx value and then checks if the rate limit is exceeded +// returns true if the rate limit is exceeded +func rateLimitExceeded( + chainID int64, + cctx *types.CrossChainTx, + gasCoinRates map[int64]sdk.Dec, + erc20CoinRates map[int64]map[string]sdk.Dec, + erc20Coins map[int64]map[string]fungibletypes.ForeignCoins, + currentCctxValue *sdk.Dec, + rateLimitValue sdk.Dec, +) bool { + amountZeta := convertCctxValue(chainID, cctx, gasCoinRates, erc20CoinRates, erc20Coins) + *currentCctxValue = currentCctxValue.Add(amountZeta) + return currentCctxValue.GT(rateLimitValue) +} diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go new file mode 100644 index 0000000000..97f6664b9c --- /dev/null +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go @@ -0,0 +1,38 @@ +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/keeper" + "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +func TestKeeper_CctxListPendingWithRateLimit(t *testing.T) { + t.Run("should fail for empty req", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + _, err := k.CctxListPendingWithinRateLimit(ctx, nil) + require.ErrorContains(t, err, "invalid request") + }) + t.Run("should fail if limit is too high", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + _, err := k.CctxListPendingWithinRateLimit(ctx, &types.QueryListCctxPendingWithRateLimitRequest{Limit: keeper.MaxPendingCctxs + 1}) + require.ErrorContains(t, err, "limit exceeds max limit of") + }) + t.Run("should fail if no TSS", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + _, err := k.CctxListPendingWithinRateLimit(ctx, &types.QueryListCctxPendingWithRateLimitRequest{Limit: 1}) + require.ErrorContains(t, err, "tss not found") + }) + t.Run("should return empty list if no nonces", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + + // set TSS + zk.ObserverKeeper.SetTSS(ctx, sample.Tss()) + + _, err := k.CctxListPendingWithinRateLimit(ctx, &types.QueryListCctxPendingWithRateLimitRequest{Limit: 1}) + require.ErrorContains(t, err, "pending nonces not found") + }) +} diff --git a/x/crosschain/keeper/grpc_query_cctx_test.go b/x/crosschain/keeper/grpc_query_cctx_test.go index 883315c0a0..59b0b68863 100644 --- a/x/crosschain/keeper/grpc_query_cctx_test.go +++ b/x/crosschain/keeper/grpc_query_cctx_test.go @@ -185,36 +185,6 @@ func TestKeeper_CctxListPending(t *testing.T) { }) } -func TestKeeper_CctxListPendingWithRateLimit(t *testing.T) { - t.Run("should fail for empty req", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - _, err := k.CctxListPendingWithinRateLimit(ctx, nil) - require.ErrorContains(t, err, "invalid request") - }) - - t.Run("should fail if limit is too high", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - _, err := k.CctxListPendingWithinRateLimit(ctx, &types.QueryListCctxPendingWithRateLimitRequest{Limit: keeper.MaxPendingCctxs + 1}) - require.ErrorContains(t, err, "limit exceeds max limit of") - }) - - t.Run("should fail if no TSS", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - _, err := k.CctxListPendingWithinRateLimit(ctx, &types.QueryListCctxPendingWithRateLimitRequest{Limit: 1}) - require.ErrorContains(t, err, "tss not found") - }) - - t.Run("should return empty list if no nonces", func(t *testing.T) { - k, ctx, _, zk := keepertest.CrosschainKeeper(t) - - // set TSS - zk.ObserverKeeper.SetTSS(ctx, sample.Tss()) - - _, err := k.CctxListPendingWithinRateLimit(ctx, &types.QueryListCctxPendingWithRateLimitRequest{Limit: 1}) - require.ErrorContains(t, err, "pending nonces not found") - }) -} - func TestKeeper_ZetaAccounting(t *testing.T) { t.Run("should error if zeta accounting not found", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) From 6ad94af0ccf6399dbf75ed82b1a52178fc30ec1b Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Fri, 19 Apr 2024 12:16:54 -0500 Subject: [PATCH 09/33] improved a few error handlling --- x/crosschain/keeper/grpc_query_cctx.go | 11 ++++------- x/crosschain/keeper/grpc_query_cctx_rate_limit.go | 12 ++++-------- .../keeper/grpc_query_cctx_rate_limit_test.go | 4 ++-- x/crosschain/keeper/grpc_query_cctx_test.go | 4 ++-- 4 files changed, 12 insertions(+), 19 deletions(-) diff --git a/x/crosschain/keeper/grpc_query_cctx.go b/x/crosschain/keeper/grpc_query_cctx.go index 5e916beeac..0cc659869c 100644 --- a/x/crosschain/keeper/grpc_query_cctx.go +++ b/x/crosschain/keeper/grpc_query_cctx.go @@ -8,6 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" "github.com/zeta-chain/zetacore/x/crosschain/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -93,21 +94,17 @@ func (k Keeper) CctxListPending(c context.Context, req *types.QueryListCctxPendi return nil, status.Error(codes.InvalidArgument, "invalid request") } - // check limit and use default MaxPendingCctxs if not specified - if req.Limit > MaxPendingCctxs { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("limit exceeds max limit of %d", MaxPendingCctxs)) - } + // use default MaxPendingCctxs if not specified or too high limit := req.Limit - if limit == 0 { + if limit == 0 || limit > MaxPendingCctxs { limit = MaxPendingCctxs } - ctx := sdk.UnwrapSDKContext(c) // query the nonces that are pending tss, found := k.zetaObserverKeeper.GetTSS(ctx) if !found { - return nil, status.Error(codes.Internal, "tss not found") + return nil, observertypes.ErrTssNotFound } pendingNonces, found := k.GetObserverKeeper().GetPendingNonces(ctx, tss.TssPubkey, req.ChainId) if !found { diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go index 9f277cc556..78f73b9d78 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go @@ -2,7 +2,6 @@ package keeper import ( "context" - "fmt" "strings" sdk "github.com/cosmos/cosmos-sdk/types" @@ -21,24 +20,21 @@ func (k Keeper) CctxListPendingWithinRateLimit(c context.Context, req *types.Que return nil, status.Error(codes.InvalidArgument, "invalid request") } - // check limit and use default MaxPendingCctxs if not specified - if req.Limit > MaxPendingCctxs { - return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("limit exceeds max limit of %d", MaxPendingCctxs)) - } + // use default MaxPendingCctxs if not specified or too high limit := req.Limit - if limit == 0 { + if limit == 0 || limit > MaxPendingCctxs { limit = MaxPendingCctxs } + ctx := sdk.UnwrapSDKContext(c) // get current height and tss - ctx := sdk.UnwrapSDKContext(c) height := ctx.BlockHeight() if height <= 0 { return nil, status.Error(codes.OutOfRange, "height out of range") } tss, found := k.zetaObserverKeeper.GetTSS(ctx) if !found { - return nil, status.Error(codes.Internal, "tss not found") + return nil, observertypes.ErrTssNotFound } // check rate limit flags to decide if we should apply rate limit diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go index 97f6664b9c..1f994872d8 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go @@ -16,10 +16,10 @@ func TestKeeper_CctxListPendingWithRateLimit(t *testing.T) { _, err := k.CctxListPendingWithinRateLimit(ctx, nil) require.ErrorContains(t, err, "invalid request") }) - t.Run("should fail if limit is too high", func(t *testing.T) { + t.Run("should use max limit if limit is too high", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) _, err := k.CctxListPendingWithinRateLimit(ctx, &types.QueryListCctxPendingWithRateLimitRequest{Limit: keeper.MaxPendingCctxs + 1}) - require.ErrorContains(t, err, "limit exceeds max limit of") + require.ErrorContains(t, err, "tss not found") }) t.Run("should fail if no TSS", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) diff --git a/x/crosschain/keeper/grpc_query_cctx_test.go b/x/crosschain/keeper/grpc_query_cctx_test.go index 59b0b68863..2387f9dc3a 100644 --- a/x/crosschain/keeper/grpc_query_cctx_test.go +++ b/x/crosschain/keeper/grpc_query_cctx_test.go @@ -70,10 +70,10 @@ func TestKeeper_CctxListPending(t *testing.T) { require.ErrorContains(t, err, "invalid request") }) - t.Run("should fail if limit is too high", func(t *testing.T) { + t.Run("should use max limit if limit is too high", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) _, err := k.CctxListPending(ctx, &types.QueryListCctxPendingRequest{Limit: keeper.MaxPendingCctxs + 1}) - require.ErrorContains(t, err, "limit exceeds max limit of") + require.ErrorContains(t, err, "tss not found") }) t.Run("should fail if no TSS", func(t *testing.T) { From 27e94a74a22d6f31bfb64ad3f5119e9c68135bf1 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Fri, 19 Apr 2024 15:16:40 -0500 Subject: [PATCH 10/33] use old cctx query as fallback when rate limiter is disabled; some renaming --- cmd/zetae2e/stress.go | 2 +- docs/openapi/openapi.swagger.yaml | 98 ++-- proto/crosschain/query.proto | 20 +- typescript/crosschain/query_pb.d.ts | 66 +-- x/crosschain/client/cli/cli_cctx.go | 4 +- x/crosschain/keeper/abci.go | 2 +- x/crosschain/keeper/grpc_query_cctx.go | 6 +- .../keeper/grpc_query_cctx_rate_limit.go | 78 +-- .../keeper/grpc_query_cctx_rate_limit_test.go | 24 +- x/crosschain/keeper/grpc_query_cctx_test.go | 18 +- x/crosschain/types/query.pb.go | 505 +++++++++--------- x/crosschain/types/query.pb.gw.go | 68 +-- zetaclient/interfaces/interfaces.go | 2 +- zetaclient/testutils/stub/core_bridge.go | 2 +- zetaclient/zetabridge/query.go | 12 +- zetaclient/zetacore_observer.go | 2 +- 16 files changed, 449 insertions(+), 460 deletions(-) diff --git a/cmd/zetae2e/stress.go b/cmd/zetae2e/stress.go index 5228905074..f8ca5b9f28 100644 --- a/cmd/zetae2e/stress.go +++ b/cmd/zetae2e/stress.go @@ -252,7 +252,7 @@ func EchoNetworkMetrics(runner *runner.E2ERunner) { case <-ticker.C: numTicks++ // Get all pending outbound transactions - cctxResp, err := runner.CctxClient.CctxListPending(context.Background(), &crosschaintypes.QueryListCctxPendingRequest{ + cctxResp, err := runner.CctxClient.ListPendingCctx(context.Background(), &crosschaintypes.QueryListPendingCctxRequest{ ChainId: chainID.Int64(), }) if err != nil { diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index 1d9296f6a1..1eb8fe4593 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -26582,53 +26582,6 @@ paths: type: string tags: - Query - /zeta-chain/crosschain/cctxPending: - get: - summary: Queries a list of pending cctxs. - operationId: Query_CctxListPending - responses: - "200": - description: A successful response. - schema: - $ref: '#/definitions/crosschainQueryListCctxPendingResponse' - default: - description: An unexpected error response. - schema: - $ref: '#/definitions/googlerpcStatus' - parameters: - - name: chain_id - in: query - required: false - type: string - format: int64 - - name: limit - in: query - required: false - type: integer - format: int64 - tags: - - Query - /zeta-chain/crosschain/cctxPendingWithRateLimit: - get: - summary: Queries a list of pending cctxs with rate limit. - operationId: Query_CctxListPendingWithinRateLimit - responses: - "200": - description: A successful response. - schema: - $ref: '#/definitions/crosschainQueryListCctxPendingWithRateLimitResponse' - default: - description: An unexpected error response. - schema: - $ref: '#/definitions/googlerpcStatus' - parameters: - - name: limit - in: query - required: false - type: integer - format: int64 - tags: - - Query /zeta-chain/crosschain/convertGasToZeta: get: operationId: Query_ConvertGasToZeta @@ -27194,6 +27147,53 @@ paths: type: boolean tags: - Query + /zeta-chain/crosschain/pendingCctx: + get: + summary: Queries a list of pending cctxs. + operationId: Query_ListPendingCctx + responses: + "200": + description: A successful response. + schema: + $ref: '#/definitions/crosschainQueryListPendingCctxResponse' + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/googlerpcStatus' + parameters: + - name: chain_id + in: query + required: false + type: string + format: int64 + - name: limit + in: query + required: false + type: integer + format: int64 + tags: + - Query + /zeta-chain/crosschain/pendingCctxWithinRateLimit: + get: + summary: Queries a list of pending cctxs within rate limit. + operationId: Query_ListPendingCctxWithinRateLimit + responses: + "200": + description: A successful response. + schema: + $ref: '#/definitions/crosschainQueryListPendingCctxWithinRateLimitResponse' + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/googlerpcStatus' + parameters: + - name: limit + in: query + required: false + type: integer + format: int64 + tags: + - Query /zeta-chain/crosschain/protocolFee: get: operationId: Query_ProtocolFee @@ -53991,7 +53991,7 @@ definitions: Height: type: string format: int64 - crosschainQueryListCctxPendingResponse: + crosschainQueryListPendingCctxResponse: type: object properties: CrossChainTx: @@ -54002,7 +54002,7 @@ definitions: totalPending: type: string format: uint64 - crosschainQueryListCctxPendingWithRateLimitResponse: + crosschainQueryListPendingCctxWithinRateLimitResponse: type: object properties: cross_chain_tx: diff --git a/proto/crosschain/query.proto b/proto/crosschain/query.proto index b4c6a9a753..b017e2c523 100644 --- a/proto/crosschain/query.proto +++ b/proto/crosschain/query.proto @@ -95,13 +95,13 @@ service Query { } // Queries a list of pending cctxs. - rpc CctxListPending(QueryListCctxPendingRequest) returns (QueryListCctxPendingResponse) { - option (google.api.http).get = "/zeta-chain/crosschain/cctxPending"; + rpc ListPendingCctx(QueryListPendingCctxRequest) returns (QueryListPendingCctxResponse) { + option (google.api.http).get = "/zeta-chain/crosschain/pendingCctx"; } - // Queries a list of pending cctxs with rate limit. - rpc CctxListPendingWithinRateLimit(QueryListCctxPendingWithRateLimitRequest) returns (QueryListCctxPendingWithRateLimitResponse) { - option (google.api.http).get = "/zeta-chain/crosschain/cctxPendingWithRateLimit"; + // Queries a list of pending cctxs within rate limit. + rpc ListPendingCctxWithinRateLimit(QueryListPendingCctxWithinRateLimitRequest) returns (QueryListPendingCctxWithinRateLimitResponse) { + option (google.api.http).get = "/zeta-chain/crosschain/pendingCctxWithinRateLimit"; } rpc ZetaAccounting(QueryZetaAccountingRequest) returns (QueryZetaAccountingResponse) { @@ -253,21 +253,21 @@ message QueryAllCctxResponse { cosmos.base.query.v1beta1.PageResponse pagination = 2; } -message QueryListCctxPendingRequest { +message QueryListPendingCctxRequest { int64 chain_id = 1; uint32 limit = 2; } -message QueryListCctxPendingResponse { +message QueryListPendingCctxResponse { repeated CrossChainTx CrossChainTx = 1; uint64 totalPending = 2; } -message QueryListCctxPendingWithRateLimitRequest { - uint32 limit = 2; +message QueryListPendingCctxWithinRateLimitRequest { + uint32 limit = 1; } -message QueryListCctxPendingWithRateLimitResponse { +message QueryListPendingCctxWithinRateLimitResponse { repeated CrossChainTx cross_chain_tx = 1; uint64 total_pending = 2; bool rate_limit_exceeded = 3; diff --git a/typescript/crosschain/query_pb.d.ts b/typescript/crosschain/query_pb.d.ts index cc093b0b13..34b4a44f38 100644 --- a/typescript/crosschain/query_pb.d.ts +++ b/typescript/crosschain/query_pb.d.ts @@ -814,9 +814,9 @@ export declare class QueryAllCctxResponse extends Message } /** - * @generated from message zetachain.zetacore.crosschain.QueryListCctxPendingRequest + * @generated from message zetachain.zetacore.crosschain.QueryListPendingCctxRequest */ -export declare class QueryListCctxPendingRequest extends Message { +export declare class QueryListPendingCctxRequest extends Message { /** * @generated from field: int64 chain_id = 1; */ @@ -827,25 +827,25 @@ export declare class QueryListCctxPendingRequest extends Message); + constructor(data?: PartialMessage); static readonly runtime: typeof proto3; - static readonly typeName = "zetachain.zetacore.crosschain.QueryListCctxPendingRequest"; + static readonly typeName = "zetachain.zetacore.crosschain.QueryListPendingCctxRequest"; static readonly fields: FieldList; - static fromBinary(bytes: Uint8Array, options?: Partial): QueryListCctxPendingRequest; + static fromBinary(bytes: Uint8Array, options?: Partial): QueryListPendingCctxRequest; - static fromJson(jsonValue: JsonValue, options?: Partial): QueryListCctxPendingRequest; + static fromJson(jsonValue: JsonValue, options?: Partial): QueryListPendingCctxRequest; - static fromJsonString(jsonString: string, options?: Partial): QueryListCctxPendingRequest; + static fromJsonString(jsonString: string, options?: Partial): QueryListPendingCctxRequest; - static equals(a: QueryListCctxPendingRequest | PlainMessage | undefined, b: QueryListCctxPendingRequest | PlainMessage | undefined): boolean; + static equals(a: QueryListPendingCctxRequest | PlainMessage | undefined, b: QueryListPendingCctxRequest | PlainMessage | undefined): boolean; } /** - * @generated from message zetachain.zetacore.crosschain.QueryListCctxPendingResponse + * @generated from message zetachain.zetacore.crosschain.QueryListPendingCctxResponse */ -export declare class QueryListCctxPendingResponse extends Message { +export declare class QueryListPendingCctxResponse extends Message { /** * @generated from field: repeated zetachain.zetacore.crosschain.CrossChainTx CrossChainTx = 1; */ @@ -856,49 +856,49 @@ export declare class QueryListCctxPendingResponse extends Message); + constructor(data?: PartialMessage); static readonly runtime: typeof proto3; - static readonly typeName = "zetachain.zetacore.crosschain.QueryListCctxPendingResponse"; + static readonly typeName = "zetachain.zetacore.crosschain.QueryListPendingCctxResponse"; static readonly fields: FieldList; - static fromBinary(bytes: Uint8Array, options?: Partial): QueryListCctxPendingResponse; + static fromBinary(bytes: Uint8Array, options?: Partial): QueryListPendingCctxResponse; - static fromJson(jsonValue: JsonValue, options?: Partial): QueryListCctxPendingResponse; + static fromJson(jsonValue: JsonValue, options?: Partial): QueryListPendingCctxResponse; - static fromJsonString(jsonString: string, options?: Partial): QueryListCctxPendingResponse; + static fromJsonString(jsonString: string, options?: Partial): QueryListPendingCctxResponse; - static equals(a: QueryListCctxPendingResponse | PlainMessage | undefined, b: QueryListCctxPendingResponse | PlainMessage | undefined): boolean; + static equals(a: QueryListPendingCctxResponse | PlainMessage | undefined, b: QueryListPendingCctxResponse | PlainMessage | undefined): boolean; } /** - * @generated from message zetachain.zetacore.crosschain.QueryListCctxPendingWithRateLimitRequest + * @generated from message zetachain.zetacore.crosschain.QueryListPendingCctxWithinRateLimitRequest */ -export declare class QueryListCctxPendingWithRateLimitRequest extends Message { +export declare class QueryListPendingCctxWithinRateLimitRequest extends Message { /** - * @generated from field: uint32 limit = 2; + * @generated from field: uint32 limit = 1; */ limit: number; - constructor(data?: PartialMessage); + constructor(data?: PartialMessage); static readonly runtime: typeof proto3; - static readonly typeName = "zetachain.zetacore.crosschain.QueryListCctxPendingWithRateLimitRequest"; + static readonly typeName = "zetachain.zetacore.crosschain.QueryListPendingCctxWithinRateLimitRequest"; static readonly fields: FieldList; - static fromBinary(bytes: Uint8Array, options?: Partial): QueryListCctxPendingWithRateLimitRequest; + static fromBinary(bytes: Uint8Array, options?: Partial): QueryListPendingCctxWithinRateLimitRequest; - static fromJson(jsonValue: JsonValue, options?: Partial): QueryListCctxPendingWithRateLimitRequest; + static fromJson(jsonValue: JsonValue, options?: Partial): QueryListPendingCctxWithinRateLimitRequest; - static fromJsonString(jsonString: string, options?: Partial): QueryListCctxPendingWithRateLimitRequest; + static fromJsonString(jsonString: string, options?: Partial): QueryListPendingCctxWithinRateLimitRequest; - static equals(a: QueryListCctxPendingWithRateLimitRequest | PlainMessage | undefined, b: QueryListCctxPendingWithRateLimitRequest | PlainMessage | undefined): boolean; + static equals(a: QueryListPendingCctxWithinRateLimitRequest | PlainMessage | undefined, b: QueryListPendingCctxWithinRateLimitRequest | PlainMessage | undefined): boolean; } /** - * @generated from message zetachain.zetacore.crosschain.QueryListCctxPendingWithRateLimitResponse + * @generated from message zetachain.zetacore.crosschain.QueryListPendingCctxWithinRateLimitResponse */ -export declare class QueryListCctxPendingWithRateLimitResponse extends Message { +export declare class QueryListPendingCctxWithinRateLimitResponse extends Message { /** * @generated from field: repeated zetachain.zetacore.crosschain.CrossChainTx cross_chain_tx = 1; */ @@ -914,19 +914,19 @@ export declare class QueryListCctxPendingWithRateLimitResponse extends Message); + constructor(data?: PartialMessage); static readonly runtime: typeof proto3; - static readonly typeName = "zetachain.zetacore.crosschain.QueryListCctxPendingWithRateLimitResponse"; + static readonly typeName = "zetachain.zetacore.crosschain.QueryListPendingCctxWithinRateLimitResponse"; static readonly fields: FieldList; - static fromBinary(bytes: Uint8Array, options?: Partial): QueryListCctxPendingWithRateLimitResponse; + static fromBinary(bytes: Uint8Array, options?: Partial): QueryListPendingCctxWithinRateLimitResponse; - static fromJson(jsonValue: JsonValue, options?: Partial): QueryListCctxPendingWithRateLimitResponse; + static fromJson(jsonValue: JsonValue, options?: Partial): QueryListPendingCctxWithinRateLimitResponse; - static fromJsonString(jsonString: string, options?: Partial): QueryListCctxPendingWithRateLimitResponse; + static fromJsonString(jsonString: string, options?: Partial): QueryListPendingCctxWithinRateLimitResponse; - static equals(a: QueryListCctxPendingWithRateLimitResponse | PlainMessage | undefined, b: QueryListCctxPendingWithRateLimitResponse | PlainMessage | undefined): boolean; + static equals(a: QueryListPendingCctxWithinRateLimitResponse | PlainMessage | undefined, b: QueryListPendingCctxWithinRateLimitResponse | PlainMessage | undefined): boolean; } /** diff --git a/x/crosschain/client/cli/cli_cctx.go b/x/crosschain/client/cli/cli_cctx.go index 87991442d1..b5add8610b 100644 --- a/x/crosschain/client/cli/cli_cctx.go +++ b/x/crosschain/client/cli/cli_cctx.go @@ -69,13 +69,13 @@ func CmdPendingCctx() *cobra.Command { return err } - params := &types.QueryListCctxPendingRequest{ + params := &types.QueryListPendingCctxRequest{ ChainId: chainID, // #nosec G701 bit size verified Limit: uint32(limit), } - res, err := queryClient.CctxListPending(context.Background(), params) + res, err := queryClient.ListPendingCctx(context.Background(), params) if err != nil { return err } diff --git a/x/crosschain/keeper/abci.go b/x/crosschain/keeper/abci.go index 5a02c53676..f893e795bb 100644 --- a/x/crosschain/keeper/abci.go +++ b/x/crosschain/keeper/abci.go @@ -51,7 +51,7 @@ IterateChains: for _, chain := range chains { // support only external evm chains if zetachains.IsEVMChain(chain.ChainId) && !zetachains.IsZetaChain(chain.ChainId) { - res, err := k.CctxListPending(sdk.UnwrapSDKContext(ctx), &types.QueryListCctxPendingRequest{ + res, err := k.ListPendingCctx(sdk.UnwrapSDKContext(ctx), &types.QueryListPendingCctxRequest{ ChainId: chain.ChainId, Limit: gasPriceIncreaseFlags.MaxPendingCctxs, }) diff --git a/x/crosschain/keeper/grpc_query_cctx.go b/x/crosschain/keeper/grpc_query_cctx.go index 0cc659869c..8e96757b44 100644 --- a/x/crosschain/keeper/grpc_query_cctx.go +++ b/x/crosschain/keeper/grpc_query_cctx.go @@ -87,9 +87,9 @@ func (k Keeper) CctxByNonce(c context.Context, req *types.QueryGetCctxByNonceReq return &types.QueryGetCctxResponse{CrossChainTx: cctx}, nil } -// CctxListPending returns a list of pending cctxs and the total number of pending cctxs +// ListPendingCctx returns a list of pending cctxs and the total number of pending cctxs // a limit for the number of cctxs to return can be specified or the default is MaxPendingCctxs -func (k Keeper) CctxListPending(c context.Context, req *types.QueryListCctxPendingRequest) (*types.QueryListCctxPendingResponse, error) { +func (k Keeper) ListPendingCctx(c context.Context, req *types.QueryListPendingCctxRequest) (*types.QueryListPendingCctxResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } @@ -154,7 +154,7 @@ func (k Keeper) CctxListPending(c context.Context, req *types.QueryListCctxPendi cctxs = append(cctxs, cctx) } - return &types.QueryListCctxPendingResponse{ + return &types.QueryListPendingCctxResponse{ CrossChainTx: cctxs, TotalPending: totalPending, }, nil diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go index 78f73b9d78..b3b30ca939 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go @@ -13,9 +13,9 @@ import ( "google.golang.org/grpc/status" ) -// CctxListPendingWithinRateLimit returns a list of pending cctxs that do not exceed the outbound rate limit +// ListPendingCctxWithinRateLimit returns a list of pending cctxs that do not exceed the outbound rate limit // a limit for the number of cctxs to return can be specified or the default is MaxPendingCctxs -func (k Keeper) CctxListPendingWithinRateLimit(c context.Context, req *types.QueryListCctxPendingWithRateLimitRequest) (*types.QueryListCctxPendingWithRateLimitResponse, error) { +func (k Keeper) ListPendingCctxWithinRateLimit(c context.Context, req *types.QueryListPendingCctxWithinRateLimitRequest) (*types.QueryListPendingCctxWithinRateLimitResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } @@ -27,6 +27,36 @@ func (k Keeper) CctxListPendingWithinRateLimit(c context.Context, req *types.Que } ctx := sdk.UnwrapSDKContext(c) + // define a few variables to be used in the query loops + limitExceeded := false + totalPending := uint64(0) + totalCctxValueInZeta := sdk.NewDec(0) + cctxs := make([]*types.CrossChainTx, 0) + chains := k.zetaObserverKeeper.GetSupportedForeignChains(ctx) + + // check rate limit flags to decide if we should apply rate limit + applyLimit := true + rateLimitFlags, found := k.GetRateLimiterFlags(ctx) + if !found || !rateLimitFlags.Enabled { + applyLimit = false + } + + // fallback to non-rate-limited query if rate limiter is disabled + if !applyLimit { + for _, chain := range chains { + resp, err := k.ListPendingCctx(ctx, &types.QueryListPendingCctxRequest{ChainId: chain.ChainId, Limit: limit}) + if err == nil { + cctxs = append(cctxs, resp.CrossChainTx...) + totalPending += resp.TotalPending + } + } + return &types.QueryListPendingCctxWithinRateLimitResponse{ + CrossChainTx: cctxs, + TotalPending: totalPending, + RateLimitExceeded: false, + }, nil + } + // get current height and tss height := ctx.BlockHeight() if height <= 0 { @@ -37,13 +67,6 @@ func (k Keeper) CctxListPendingWithinRateLimit(c context.Context, req *types.Que return nil, observertypes.ErrTssNotFound } - // check rate limit flags to decide if we should apply rate limit - applyLimit := true - rateLimitFlags, found := k.GetRateLimiterFlags(ctx) - if !found || !rateLimitFlags.Enabled { - applyLimit = false - } - // calculate the rate limiter sliding window left boundary (inclusive) leftWindowBoundary := height - rateLimitFlags.Window if leftWindowBoundary < 0 { @@ -61,13 +84,6 @@ func (k Keeper) CctxListPendingWithinRateLimit(c context.Context, req *types.Que rateLimitInZeta = sdk.NewDecFromBigInt(rateLimitFlags.Rate.BigInt()) } - // define a few variables to be used in the below loops - limitExceeded := false - totalPending := uint64(0) - totalCctxValueInZeta := sdk.NewDec(0) - cctxs := make([]*types.CrossChainTx, 0) - pendingNoncesMap := make(map[int64]*observertypes.PendingNonces) - // the criteria to stop adding cctxs to the rpc response maxCCTXsReached := func() bool { // #nosec G701 len always positive @@ -76,7 +92,7 @@ func (k Keeper) CctxListPendingWithinRateLimit(c context.Context, req *types.Que // query pending nonces for each foreign chain // Note: The pending nonces could change during the RPC call, so query them beforehand - chains := k.zetaObserverKeeper.GetSupportedForeignChains(ctx) + pendingNoncesMap := make(map[int64]*observertypes.PendingNonces) for _, chain := range chains { pendingNonces, found := k.GetObserverKeeper().GetPendingNonces(ctx, tss.TssPubkey, chain.ChainId) if !found { @@ -107,22 +123,16 @@ LoopBackwards: // We should at least go backwards by 1000 nonces to pick up missed pending cctxs // We might go even further back if rate limiter is enabled and the endNonce hasn't hit the left window boundary yet - // There are three criteria to stop scanning backwards: - // criteria #1: if rate limiter is disabled, we should stop exactly on the `endNonce` - if !applyLimit && nonce < endNonce { + // There are two criteria to stop scanning backwards: + // criteria #1: we'll stop at the left window boundary if the `endNonce` hasn't hit it yet + // #nosec G701 always positive + if nonce < endNonce && cctx.InboundTxParams.InboundTxObservedExternalHeight < uint64(leftWindowBoundary) { break } - if applyLimit { - // criteria #2: if rate limiter is enabled, we'll stop at the left window boundary if the `endNonce` hasn't hit it yet - // #nosec G701 always positive - if nonce < endNonce && cctx.InboundTxParams.InboundTxObservedExternalHeight < uint64(leftWindowBoundary) { - break - } - // criteria #3: if rate limiter is enabled, we should finish the RPC call if the rate limit is exceeded - if rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, erc20Coins, &totalCctxValueInZeta, rateLimitInZeta) { - limitExceeded = true - break LoopBackwards - } + // criteria #2: we should finish the RPC call if the rate limit is exceeded + if rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, erc20Coins, &totalCctxValueInZeta, rateLimitInZeta) { + limitExceeded = true + break LoopBackwards } // only take a `limit` number of pending cctxs as result but still count the total pending cctxs @@ -156,8 +166,8 @@ LoopForwards: if maxCCTXsReached() { break LoopForwards } - // criteria #3: if rate limiter is enabled, we should finish the RPC call if the rate limit is exceeded - if applyLimit && rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, erc20Coins, &totalCctxValueInZeta, rateLimitInZeta) { + // criteria #2: we should finish the RPC call if the rate limit is exceeded + if rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, erc20Coins, &totalCctxValueInZeta, rateLimitInZeta) { limitExceeded = true break LoopForwards } @@ -165,7 +175,7 @@ LoopForwards: } } - return &types.QueryListCctxPendingWithRateLimitResponse{ + return &types.QueryListPendingCctxWithinRateLimitResponse{ CrossChainTx: cctxs, TotalPending: totalPending, RateLimitExceeded: limitExceeded, diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go index 1f994872d8..5c2eee4066 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go @@ -5,34 +5,12 @@ import ( "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/keeper" - "github.com/zeta-chain/zetacore/x/crosschain/types" ) func TestKeeper_CctxListPendingWithRateLimit(t *testing.T) { t.Run("should fail for empty req", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) - _, err := k.CctxListPendingWithinRateLimit(ctx, nil) + _, err := k.ListPendingCctxWithinRateLimit(ctx, nil) require.ErrorContains(t, err, "invalid request") }) - t.Run("should use max limit if limit is too high", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - _, err := k.CctxListPendingWithinRateLimit(ctx, &types.QueryListCctxPendingWithRateLimitRequest{Limit: keeper.MaxPendingCctxs + 1}) - require.ErrorContains(t, err, "tss not found") - }) - t.Run("should fail if no TSS", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - _, err := k.CctxListPendingWithinRateLimit(ctx, &types.QueryListCctxPendingWithRateLimitRequest{Limit: 1}) - require.ErrorContains(t, err, "tss not found") - }) - t.Run("should return empty list if no nonces", func(t *testing.T) { - k, ctx, _, zk := keepertest.CrosschainKeeper(t) - - // set TSS - zk.ObserverKeeper.SetTSS(ctx, sample.Tss()) - - _, err := k.CctxListPendingWithinRateLimit(ctx, &types.QueryListCctxPendingWithRateLimitRequest{Limit: 1}) - require.ErrorContains(t, err, "pending nonces not found") - }) } diff --git a/x/crosschain/keeper/grpc_query_cctx_test.go b/x/crosschain/keeper/grpc_query_cctx_test.go index 2387f9dc3a..240d0bfe92 100644 --- a/x/crosschain/keeper/grpc_query_cctx_test.go +++ b/x/crosschain/keeper/grpc_query_cctx_test.go @@ -66,19 +66,19 @@ func createCctxWithNonceRange( func TestKeeper_CctxListPending(t *testing.T) { t.Run("should fail for empty req", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) - _, err := k.CctxListPending(ctx, nil) + _, err := k.ListPendingCctx(ctx, nil) require.ErrorContains(t, err, "invalid request") }) t.Run("should use max limit if limit is too high", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) - _, err := k.CctxListPending(ctx, &types.QueryListCctxPendingRequest{Limit: keeper.MaxPendingCctxs + 1}) + _, err := k.ListPendingCctx(ctx, &types.QueryListPendingCctxRequest{Limit: keeper.MaxPendingCctxs + 1}) require.ErrorContains(t, err, "tss not found") }) t.Run("should fail if no TSS", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) - _, err := k.CctxListPending(ctx, &types.QueryListCctxPendingRequest{Limit: 1}) + _, err := k.ListPendingCctx(ctx, &types.QueryListPendingCctxRequest{Limit: 1}) require.ErrorContains(t, err, "tss not found") }) @@ -88,7 +88,7 @@ func TestKeeper_CctxListPending(t *testing.T) { // set TSS zk.ObserverKeeper.SetTSS(ctx, sample.Tss()) - _, err := k.CctxListPending(ctx, &types.QueryListCctxPendingRequest{Limit: 1}) + _, err := k.ListPendingCctx(ctx, &types.QueryListPendingCctxRequest{Limit: 1}) require.ErrorContains(t, err, "pending nonces not found") }) @@ -99,13 +99,13 @@ func TestKeeper_CctxListPending(t *testing.T) { zk.ObserverKeeper.SetTSS(ctx, tss) cctxs := createCctxWithNonceRange(t, ctx, *k, 1000, 2000, chainID, tss, zk) - res, err := k.CctxListPending(ctx, &types.QueryListCctxPendingRequest{ChainId: chainID, Limit: 100}) + res, err := k.ListPendingCctx(ctx, &types.QueryListPendingCctxRequest{ChainId: chainID, Limit: 100}) require.NoError(t, err) require.Equal(t, 100, len(res.CrossChainTx)) require.EqualValues(t, cctxs[0:100], res.CrossChainTx) require.EqualValues(t, uint64(1000), res.TotalPending) - res, err = k.CctxListPending(ctx, &types.QueryListCctxPendingRequest{ChainId: chainID}) + res, err = k.ListPendingCctx(ctx, &types.QueryListPendingCctxRequest{ChainId: chainID}) require.NoError(t, err) require.Equal(t, keeper.MaxPendingCctxs, len(res.CrossChainTx)) require.EqualValues(t, cctxs[0:keeper.MaxPendingCctxs], res.CrossChainTx) @@ -119,7 +119,7 @@ func TestKeeper_CctxListPending(t *testing.T) { zk.ObserverKeeper.SetTSS(ctx, tss) cctxs := createCctxWithNonceRange(t, ctx, *k, 1000, 1100, chainID, tss, zk) - res, err := k.CctxListPending(ctx, &types.QueryListCctxPendingRequest{ChainId: chainID}) + res, err := k.ListPendingCctx(ctx, &types.QueryListPendingCctxRequest{ChainId: chainID}) require.NoError(t, err) require.Equal(t, 100, len(res.CrossChainTx)) require.EqualValues(t, cctxs, res.CrossChainTx) @@ -144,7 +144,7 @@ func TestKeeper_CctxListPending(t *testing.T) { cctx2.CctxStatus.Status = types.CctxStatus_PendingOutbound k.SetCrossChainTx(ctx, cctx2) - res, err := k.CctxListPending(ctx, &types.QueryListCctxPendingRequest{ChainId: chainID, Limit: 100}) + res, err := k.ListPendingCctx(ctx, &types.QueryListPendingCctxRequest{ChainId: chainID, Limit: 100}) require.NoError(t, err) require.Equal(t, 100, len(res.CrossChainTx)) @@ -173,7 +173,7 @@ func TestKeeper_CctxListPending(t *testing.T) { cctx2.CctxStatus.Status = types.CctxStatus_PendingOutbound k.SetCrossChainTx(ctx, cctx2) - res, err := k.CctxListPending(ctx, &types.QueryListCctxPendingRequest{ChainId: chainID, Limit: 100}) + res, err := k.ListPendingCctx(ctx, &types.QueryListPendingCctxRequest{ChainId: chainID, Limit: 100}) require.NoError(t, err) require.Equal(t, 100, len(res.CrossChainTx)) diff --git a/x/crosschain/types/query.pb.go b/x/crosschain/types/query.pb.go index 7d88a5f6df..879dcce901 100644 --- a/x/crosschain/types/query.pb.go +++ b/x/crosschain/types/query.pb.go @@ -1483,23 +1483,23 @@ func (m *QueryAllCctxResponse) GetPagination() *query.PageResponse { return nil } -type QueryListCctxPendingRequest struct { +type QueryListPendingCctxRequest struct { ChainId int64 `protobuf:"varint,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` Limit uint32 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` } -func (m *QueryListCctxPendingRequest) Reset() { *m = QueryListCctxPendingRequest{} } -func (m *QueryListCctxPendingRequest) String() string { return proto.CompactTextString(m) } -func (*QueryListCctxPendingRequest) ProtoMessage() {} -func (*QueryListCctxPendingRequest) Descriptor() ([]byte, []int) { +func (m *QueryListPendingCctxRequest) Reset() { *m = QueryListPendingCctxRequest{} } +func (m *QueryListPendingCctxRequest) String() string { return proto.CompactTextString(m) } +func (*QueryListPendingCctxRequest) ProtoMessage() {} +func (*QueryListPendingCctxRequest) Descriptor() ([]byte, []int) { return fileDescriptor_65a992045e92a606, []int{31} } -func (m *QueryListCctxPendingRequest) XXX_Unmarshal(b []byte) error { +func (m *QueryListPendingCctxRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *QueryListCctxPendingRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *QueryListPendingCctxRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_QueryListCctxPendingRequest.Marshal(b, m, deterministic) + return xxx_messageInfo_QueryListPendingCctxRequest.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -1509,49 +1509,49 @@ func (m *QueryListCctxPendingRequest) XXX_Marshal(b []byte, deterministic bool) return b[:n], nil } } -func (m *QueryListCctxPendingRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryListCctxPendingRequest.Merge(m, src) +func (m *QueryListPendingCctxRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryListPendingCctxRequest.Merge(m, src) } -func (m *QueryListCctxPendingRequest) XXX_Size() int { +func (m *QueryListPendingCctxRequest) XXX_Size() int { return m.Size() } -func (m *QueryListCctxPendingRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryListCctxPendingRequest.DiscardUnknown(m) +func (m *QueryListPendingCctxRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryListPendingCctxRequest.DiscardUnknown(m) } -var xxx_messageInfo_QueryListCctxPendingRequest proto.InternalMessageInfo +var xxx_messageInfo_QueryListPendingCctxRequest proto.InternalMessageInfo -func (m *QueryListCctxPendingRequest) GetChainId() int64 { +func (m *QueryListPendingCctxRequest) GetChainId() int64 { if m != nil { return m.ChainId } return 0 } -func (m *QueryListCctxPendingRequest) GetLimit() uint32 { +func (m *QueryListPendingCctxRequest) GetLimit() uint32 { if m != nil { return m.Limit } return 0 } -type QueryListCctxPendingResponse struct { +type QueryListPendingCctxResponse struct { CrossChainTx []*CrossChainTx `protobuf:"bytes,1,rep,name=CrossChainTx,proto3" json:"CrossChainTx,omitempty"` TotalPending uint64 `protobuf:"varint,2,opt,name=totalPending,proto3" json:"totalPending,omitempty"` } -func (m *QueryListCctxPendingResponse) Reset() { *m = QueryListCctxPendingResponse{} } -func (m *QueryListCctxPendingResponse) String() string { return proto.CompactTextString(m) } -func (*QueryListCctxPendingResponse) ProtoMessage() {} -func (*QueryListCctxPendingResponse) Descriptor() ([]byte, []int) { +func (m *QueryListPendingCctxResponse) Reset() { *m = QueryListPendingCctxResponse{} } +func (m *QueryListPendingCctxResponse) String() string { return proto.CompactTextString(m) } +func (*QueryListPendingCctxResponse) ProtoMessage() {} +func (*QueryListPendingCctxResponse) Descriptor() ([]byte, []int) { return fileDescriptor_65a992045e92a606, []int{32} } -func (m *QueryListCctxPendingResponse) XXX_Unmarshal(b []byte) error { +func (m *QueryListPendingCctxResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *QueryListCctxPendingResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *QueryListPendingCctxResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_QueryListCctxPendingResponse.Marshal(b, m, deterministic) + return xxx_messageInfo_QueryListPendingCctxResponse.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -1561,50 +1561,52 @@ func (m *QueryListCctxPendingResponse) XXX_Marshal(b []byte, deterministic bool) return b[:n], nil } } -func (m *QueryListCctxPendingResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryListCctxPendingResponse.Merge(m, src) +func (m *QueryListPendingCctxResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryListPendingCctxResponse.Merge(m, src) } -func (m *QueryListCctxPendingResponse) XXX_Size() int { +func (m *QueryListPendingCctxResponse) XXX_Size() int { return m.Size() } -func (m *QueryListCctxPendingResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryListCctxPendingResponse.DiscardUnknown(m) +func (m *QueryListPendingCctxResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryListPendingCctxResponse.DiscardUnknown(m) } -var xxx_messageInfo_QueryListCctxPendingResponse proto.InternalMessageInfo +var xxx_messageInfo_QueryListPendingCctxResponse proto.InternalMessageInfo -func (m *QueryListCctxPendingResponse) GetCrossChainTx() []*CrossChainTx { +func (m *QueryListPendingCctxResponse) GetCrossChainTx() []*CrossChainTx { if m != nil { return m.CrossChainTx } return nil } -func (m *QueryListCctxPendingResponse) GetTotalPending() uint64 { +func (m *QueryListPendingCctxResponse) GetTotalPending() uint64 { if m != nil { return m.TotalPending } return 0 } -type QueryListCctxPendingWithRateLimitRequest struct { - Limit uint32 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` +type QueryListPendingCctxWithinRateLimitRequest struct { + Limit uint32 `protobuf:"varint,1,opt,name=limit,proto3" json:"limit,omitempty"` } -func (m *QueryListCctxPendingWithRateLimitRequest) Reset() { - *m = QueryListCctxPendingWithRateLimitRequest{} +func (m *QueryListPendingCctxWithinRateLimitRequest) Reset() { + *m = QueryListPendingCctxWithinRateLimitRequest{} } -func (m *QueryListCctxPendingWithRateLimitRequest) String() string { return proto.CompactTextString(m) } -func (*QueryListCctxPendingWithRateLimitRequest) ProtoMessage() {} -func (*QueryListCctxPendingWithRateLimitRequest) Descriptor() ([]byte, []int) { +func (m *QueryListPendingCctxWithinRateLimitRequest) String() string { + return proto.CompactTextString(m) +} +func (*QueryListPendingCctxWithinRateLimitRequest) ProtoMessage() {} +func (*QueryListPendingCctxWithinRateLimitRequest) Descriptor() ([]byte, []int) { return fileDescriptor_65a992045e92a606, []int{33} } -func (m *QueryListCctxPendingWithRateLimitRequest) XXX_Unmarshal(b []byte) error { +func (m *QueryListPendingCctxWithinRateLimitRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *QueryListCctxPendingWithRateLimitRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *QueryListPendingCctxWithinRateLimitRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_QueryListCctxPendingWithRateLimitRequest.Marshal(b, m, deterministic) + return xxx_messageInfo_QueryListPendingCctxWithinRateLimitRequest.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -1614,47 +1616,47 @@ func (m *QueryListCctxPendingWithRateLimitRequest) XXX_Marshal(b []byte, determi return b[:n], nil } } -func (m *QueryListCctxPendingWithRateLimitRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryListCctxPendingWithRateLimitRequest.Merge(m, src) +func (m *QueryListPendingCctxWithinRateLimitRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryListPendingCctxWithinRateLimitRequest.Merge(m, src) } -func (m *QueryListCctxPendingWithRateLimitRequest) XXX_Size() int { +func (m *QueryListPendingCctxWithinRateLimitRequest) XXX_Size() int { return m.Size() } -func (m *QueryListCctxPendingWithRateLimitRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryListCctxPendingWithRateLimitRequest.DiscardUnknown(m) +func (m *QueryListPendingCctxWithinRateLimitRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryListPendingCctxWithinRateLimitRequest.DiscardUnknown(m) } -var xxx_messageInfo_QueryListCctxPendingWithRateLimitRequest proto.InternalMessageInfo +var xxx_messageInfo_QueryListPendingCctxWithinRateLimitRequest proto.InternalMessageInfo -func (m *QueryListCctxPendingWithRateLimitRequest) GetLimit() uint32 { +func (m *QueryListPendingCctxWithinRateLimitRequest) GetLimit() uint32 { if m != nil { return m.Limit } return 0 } -type QueryListCctxPendingWithRateLimitResponse struct { +type QueryListPendingCctxWithinRateLimitResponse struct { CrossChainTx []*CrossChainTx `protobuf:"bytes,1,rep,name=cross_chain_tx,json=crossChainTx,proto3" json:"cross_chain_tx,omitempty"` TotalPending uint64 `protobuf:"varint,2,opt,name=total_pending,json=totalPending,proto3" json:"total_pending,omitempty"` RateLimitExceeded bool `protobuf:"varint,3,opt,name=rate_limit_exceeded,json=rateLimitExceeded,proto3" json:"rate_limit_exceeded,omitempty"` } -func (m *QueryListCctxPendingWithRateLimitResponse) Reset() { - *m = QueryListCctxPendingWithRateLimitResponse{} +func (m *QueryListPendingCctxWithinRateLimitResponse) Reset() { + *m = QueryListPendingCctxWithinRateLimitResponse{} } -func (m *QueryListCctxPendingWithRateLimitResponse) String() string { +func (m *QueryListPendingCctxWithinRateLimitResponse) String() string { return proto.CompactTextString(m) } -func (*QueryListCctxPendingWithRateLimitResponse) ProtoMessage() {} -func (*QueryListCctxPendingWithRateLimitResponse) Descriptor() ([]byte, []int) { +func (*QueryListPendingCctxWithinRateLimitResponse) ProtoMessage() {} +func (*QueryListPendingCctxWithinRateLimitResponse) Descriptor() ([]byte, []int) { return fileDescriptor_65a992045e92a606, []int{34} } -func (m *QueryListCctxPendingWithRateLimitResponse) XXX_Unmarshal(b []byte) error { +func (m *QueryListPendingCctxWithinRateLimitResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *QueryListCctxPendingWithRateLimitResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *QueryListPendingCctxWithinRateLimitResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_QueryListCctxPendingWithRateLimitResponse.Marshal(b, m, deterministic) + return xxx_messageInfo_QueryListPendingCctxWithinRateLimitResponse.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -1664,33 +1666,33 @@ func (m *QueryListCctxPendingWithRateLimitResponse) XXX_Marshal(b []byte, determ return b[:n], nil } } -func (m *QueryListCctxPendingWithRateLimitResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryListCctxPendingWithRateLimitResponse.Merge(m, src) +func (m *QueryListPendingCctxWithinRateLimitResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryListPendingCctxWithinRateLimitResponse.Merge(m, src) } -func (m *QueryListCctxPendingWithRateLimitResponse) XXX_Size() int { +func (m *QueryListPendingCctxWithinRateLimitResponse) XXX_Size() int { return m.Size() } -func (m *QueryListCctxPendingWithRateLimitResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryListCctxPendingWithRateLimitResponse.DiscardUnknown(m) +func (m *QueryListPendingCctxWithinRateLimitResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryListPendingCctxWithinRateLimitResponse.DiscardUnknown(m) } -var xxx_messageInfo_QueryListCctxPendingWithRateLimitResponse proto.InternalMessageInfo +var xxx_messageInfo_QueryListPendingCctxWithinRateLimitResponse proto.InternalMessageInfo -func (m *QueryListCctxPendingWithRateLimitResponse) GetCrossChainTx() []*CrossChainTx { +func (m *QueryListPendingCctxWithinRateLimitResponse) GetCrossChainTx() []*CrossChainTx { if m != nil { return m.CrossChainTx } return nil } -func (m *QueryListCctxPendingWithRateLimitResponse) GetTotalPending() uint64 { +func (m *QueryListPendingCctxWithinRateLimitResponse) GetTotalPending() uint64 { if m != nil { return m.TotalPending } return 0 } -func (m *QueryListCctxPendingWithRateLimitResponse) GetRateLimitExceeded() bool { +func (m *QueryListPendingCctxWithinRateLimitResponse) GetRateLimitExceeded() bool { if m != nil { return m.RateLimitExceeded } @@ -2083,10 +2085,10 @@ func init() { proto.RegisterType((*QueryGetCctxResponse)(nil), "zetachain.zetacore.crosschain.QueryGetCctxResponse") proto.RegisterType((*QueryAllCctxRequest)(nil), "zetachain.zetacore.crosschain.QueryAllCctxRequest") proto.RegisterType((*QueryAllCctxResponse)(nil), "zetachain.zetacore.crosschain.QueryAllCctxResponse") - proto.RegisterType((*QueryListCctxPendingRequest)(nil), "zetachain.zetacore.crosschain.QueryListCctxPendingRequest") - proto.RegisterType((*QueryListCctxPendingResponse)(nil), "zetachain.zetacore.crosschain.QueryListCctxPendingResponse") - proto.RegisterType((*QueryListCctxPendingWithRateLimitRequest)(nil), "zetachain.zetacore.crosschain.QueryListCctxPendingWithRateLimitRequest") - proto.RegisterType((*QueryListCctxPendingWithRateLimitResponse)(nil), "zetachain.zetacore.crosschain.QueryListCctxPendingWithRateLimitResponse") + proto.RegisterType((*QueryListPendingCctxRequest)(nil), "zetachain.zetacore.crosschain.QueryListPendingCctxRequest") + proto.RegisterType((*QueryListPendingCctxResponse)(nil), "zetachain.zetacore.crosschain.QueryListPendingCctxResponse") + proto.RegisterType((*QueryListPendingCctxWithinRateLimitRequest)(nil), "zetachain.zetacore.crosschain.QueryListPendingCctxWithinRateLimitRequest") + proto.RegisterType((*QueryListPendingCctxWithinRateLimitResponse)(nil), "zetachain.zetacore.crosschain.QueryListPendingCctxWithinRateLimitResponse") proto.RegisterType((*QueryLastZetaHeightRequest)(nil), "zetachain.zetacore.crosschain.QueryLastZetaHeightRequest") proto.RegisterType((*QueryLastZetaHeightResponse)(nil), "zetachain.zetacore.crosschain.QueryLastZetaHeightResponse") proto.RegisterType((*QueryConvertGasToZetaRequest)(nil), "zetachain.zetacore.crosschain.QueryConvertGasToZetaRequest") @@ -2100,127 +2102,126 @@ func init() { func init() { proto.RegisterFile("crosschain/query.proto", fileDescriptor_65a992045e92a606) } var fileDescriptor_65a992045e92a606 = []byte{ - // 1911 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5a, 0x41, 0x6f, 0x1c, 0x49, - 0x15, 0x76, 0x79, 0xe2, 0x5d, 0xa7, 0xec, 0xc4, 0xeb, 0x5a, 0x13, 0x4c, 0xaf, 0x3d, 0x4e, 0xda, - 0x24, 0xf6, 0x26, 0x78, 0x7a, 0xed, 0xdd, 0x38, 0x6c, 0xe2, 0x45, 0x3b, 0x76, 0xd6, 0x4e, 0x84, - 0x77, 0xe3, 0x8c, 0x8c, 0x82, 0x82, 0x50, 0xab, 0xdc, 0x53, 0xe9, 0x69, 0xa5, 0xdd, 0xed, 0x4c, - 0xd7, 0x44, 0xe3, 0x58, 0xbe, 0xe4, 0xc0, 0x19, 0x29, 0x07, 0x2e, 0x9c, 0x90, 0x10, 0x1c, 0x38, - 0x70, 0x40, 0x70, 0x40, 0x0a, 0x42, 0x40, 0xc8, 0x31, 0x52, 0x24, 0x84, 0x40, 0x42, 0x28, 0xe1, - 0xc8, 0x8f, 0x58, 0x75, 0xcd, 0xeb, 0x99, 0xea, 0x9e, 0xee, 0x99, 0xf2, 0x78, 0x72, 0xc8, 0x29, - 0x53, 0x5d, 0xf5, 0xde, 0xfb, 0xbe, 0xf7, 0x5e, 0xbf, 0x7e, 0xf5, 0x62, 0x7c, 0xc6, 0xaa, 0xfa, - 0x41, 0x60, 0x55, 0xa8, 0xe3, 0x19, 0x0f, 0x6a, 0xac, 0xba, 0x5f, 0xd8, 0xab, 0xfa, 0xdc, 0x27, - 0xd3, 0x8f, 0x18, 0xa7, 0xe2, 0x71, 0x41, 0xfc, 0xf2, 0xab, 0xac, 0xd0, 0x3a, 0xaa, 0x5d, 0xb4, - 0xfc, 0x60, 0xd7, 0x0f, 0x8c, 0x1d, 0x1a, 0xb0, 0x86, 0x9c, 0xf1, 0x70, 0x71, 0x87, 0x71, 0xba, - 0x68, 0xec, 0x51, 0xdb, 0xf1, 0x28, 0x77, 0x7c, 0xaf, 0xa1, 0x4a, 0x9b, 0x91, 0x4c, 0x88, 0x9f, - 0xa6, 0xf8, 0x6d, 0xf2, 0x3a, 0x1c, 0xd0, 0xa4, 0x03, 0x36, 0x0d, 0xcc, 0xbd, 0xaa, 0x63, 0x31, - 0xd8, 0x9b, 0x95, 0xf6, 0x84, 0x8c, 0x59, 0xa1, 0x41, 0xc5, 0xe4, 0xbe, 0x69, 0x59, 0x4d, 0x05, - 0xf9, 0xb6, 0x43, 0xbc, 0x4a, 0xad, 0xfb, 0xac, 0x0a, 0xfb, 0xba, 0xb4, 0xef, 0xd2, 0x80, 0x9b, - 0x3b, 0xae, 0x6f, 0xdd, 0x37, 0x2b, 0xcc, 0xb1, 0x2b, 0x3c, 0x05, 0xa5, 0x5f, 0xe3, 0xed, 0x4a, - 0x64, 0x24, 0x55, 0xca, 0x99, 0xe9, 0x3a, 0xbb, 0x0e, 0x67, 0x55, 0xf3, 0x9e, 0x4b, 0xed, 0x00, - 0x0e, 0x4d, 0xd8, 0xbe, 0xed, 0x8b, 0x9f, 0x46, 0xf8, 0x0b, 0x9e, 0x4e, 0xd9, 0xbe, 0x6f, 0xbb, - 0xcc, 0xa0, 0x7b, 0x8e, 0x41, 0x3d, 0xcf, 0xe7, 0xc2, 0x3d, 0x20, 0xa3, 0x4f, 0x61, 0xed, 0x76, - 0xe8, 0xc1, 0xbb, 0x8c, 0xd3, 0xa2, 0x65, 0xf9, 0x35, 0x8f, 0x3b, 0x9e, 0x5d, 0x62, 0x0f, 0x6a, - 0x2c, 0xe0, 0xfa, 0x97, 0xf8, 0x83, 0xd4, 0xdd, 0x60, 0xcf, 0xf7, 0x02, 0x46, 0x0a, 0xf8, 0x7d, - 0xba, 0xe3, 0x57, 0x39, 0x2b, 0x9b, 0x61, 0x9c, 0x4c, 0xba, 0x1b, 0x9e, 0x98, 0x44, 0x67, 0xd1, - 0xfc, 0xc9, 0xd2, 0x38, 0x6c, 0x09, 0x59, 0xb1, 0xd1, 0x54, 0xb7, 0xc1, 0xf8, 0xad, 0x1a, 0xdf, - 0xae, 0x6f, 0x37, 0x38, 0x82, 0x35, 0x32, 0x89, 0xdf, 0x15, 0x0c, 0x6f, 0x5e, 0x17, 0x2a, 0x72, - 0xa5, 0x68, 0x49, 0x26, 0xf0, 0x90, 0xe7, 0x7b, 0x16, 0x9b, 0x1c, 0x3c, 0x8b, 0xe6, 0x4f, 0x94, - 0x1a, 0x0b, 0xbd, 0x86, 0xa7, 0xd2, 0xd5, 0x01, 0xbc, 0x1f, 0xe0, 0x51, 0x5f, 0x7a, 0x2e, 0x94, - 0x8e, 0x2c, 0x5d, 0x2a, 0x74, 0xcc, 0xae, 0x82, 0xac, 0x6a, 0xf5, 0xc4, 0xf3, 0xff, 0xcc, 0x0c, - 0x94, 0x62, 0x6a, 0x74, 0x06, 0x2c, 0x8a, 0xae, 0x9b, 0xc6, 0x62, 0x1d, 0xe3, 0x56, 0x16, 0x82, - 0xcd, 0x0b, 0x85, 0x46, 0xca, 0x16, 0xc2, 0x94, 0x2d, 0x34, 0x52, 0x1d, 0x52, 0xb6, 0xb0, 0x45, - 0x6d, 0x06, 0xb2, 0x25, 0x49, 0x52, 0x7f, 0x8a, 0x80, 0x5e, 0x9b, 0x9d, 0x4c, 0x7a, 0xb9, 0x3e, - 0xd0, 0x23, 0x1b, 0x31, 0xfc, 0x83, 0x02, 0xff, 0x5c, 0x57, 0xfc, 0x0d, 0x4c, 0x31, 0x02, 0x8f, - 0x11, 0xd6, 0xd3, 0x08, 0xac, 0xee, 0xaf, 0x85, 0x48, 0x22, 0x7f, 0x4d, 0xe0, 0x21, 0x81, 0x0c, - 0x62, 0xde, 0x58, 0x24, 0xbc, 0x38, 0xd8, 0xb3, 0x17, 0xff, 0x86, 0xf0, 0x6c, 0x47, 0x10, 0x6f, - 0x89, 0x33, 0x7f, 0x82, 0xf0, 0xb9, 0x88, 0xc7, 0x4d, 0x2f, 0xcb, 0x97, 0xdf, 0xc2, 0xc3, 0x8d, - 0xf2, 0xe6, 0x94, 0xe3, 0xaf, 0x50, 0xb9, 0x6f, 0x0e, 0xfd, 0xb3, 0x14, 0xd5, 0x34, 0x20, 0xe0, - 0xcf, 0x12, 0x1e, 0x71, 0xbc, 0xa4, 0x3b, 0x2f, 0x76, 0x71, 0xa7, 0xac, 0xaf, 0xe1, 0x4d, 0x59, - 0x49, 0xff, 0x9c, 0x29, 0xbd, 0xc1, 0x92, 0xc9, 0xa0, 0xdf, 0x6f, 0xf0, 0x1f, 0xa5, 0x37, 0x38, - 0x6e, 0xe7, 0x6d, 0x70, 0xd2, 0x35, 0x3c, 0x1d, 0x55, 0xd7, 0xd0, 0xe4, 0x0d, 0x1a, 0x54, 0xb6, - 0xfd, 0x35, 0x8b, 0xd7, 0x23, 0x37, 0x69, 0x78, 0xd8, 0x81, 0x0d, 0x28, 0xf9, 0xcd, 0xb5, 0x7e, - 0x88, 0xf3, 0x59, 0xc2, 0xc0, 0xfd, 0x47, 0xf8, 0xb4, 0x13, 0xdb, 0x01, 0x47, 0x2f, 0x28, 0xd0, - 0x6f, 0x09, 0x81, 0x07, 0x12, 0xaa, 0xf4, 0x15, 0x30, 0x1f, 0x3f, 0x7c, 0x9d, 0x72, 0xaa, 0x02, - 0xfe, 0x11, 0x9e, 0xc9, 0x94, 0x06, 0xf4, 0x77, 0xf0, 0xa9, 0xb5, 0x10, 0x93, 0x48, 0xfa, 0xed, - 0x7a, 0xa0, 0x58, 0x2f, 0x64, 0x19, 0x80, 0x1e, 0xd7, 0xa3, 0xdb, 0xe0, 0x75, 0x48, 0x99, 0x76, - 0xaf, 0xf7, 0x2b, 0x39, 0x9f, 0x21, 0xf0, 0x51, 0x8a, 0xa5, 0x0e, 0x21, 0xca, 0xf5, 0x29, 0x44, - 0xfd, 0xcb, 0x53, 0x03, 0x7f, 0x33, 0x4a, 0xb5, 0x0d, 0x1a, 0x6c, 0x85, 0xed, 0x9b, 0xf4, 0x69, - 0x71, 0xbc, 0x32, 0xab, 0x43, 0x84, 0x1b, 0x0b, 0xdd, 0xc4, 0x93, 0xed, 0x02, 0x40, 0x79, 0x0d, - 0x0f, 0x47, 0xcf, 0xc0, 0xb7, 0x73, 0x5d, 0xc8, 0x36, 0x55, 0x34, 0x05, 0x75, 0x0a, 0x88, 0x8a, - 0xae, 0x9b, 0x44, 0xd4, 0xaf, 0xe8, 0xfd, 0x1a, 0x01, 0x89, 0x98, 0x8d, 0x54, 0x12, 0xb9, 0x9e, - 0x48, 0xf4, 0x2f, 0x3e, 0xcb, 0xad, 0x52, 0xb0, 0x49, 0x03, 0xbe, 0x1a, 0x76, 0xbf, 0x37, 0x44, - 0xf3, 0xdb, 0x39, 0x4c, 0x07, 0xf0, 0x16, 0xa6, 0xc9, 0x01, 0xd1, 0x1f, 0xe2, 0xb1, 0xc4, 0x16, - 0xb8, 0xb4, 0xd0, 0x85, 0x6f, 0x52, 0x61, 0x52, 0x8d, 0x5e, 0x69, 0xbd, 0x1c, 0x19, 0xa0, 0xfb, - 0x15, 0xc9, 0xbf, 0x22, 0xe0, 0x99, 0x66, 0xaa, 0x13, 0xcf, 0x5c, 0x1f, 0x78, 0xf6, 0x2f, 0xca, - 0x97, 0xf0, 0xfb, 0x51, 0xb4, 0xe4, 0x6a, 0x95, 0x1e, 0xda, 0x4d, 0xb8, 0x74, 0xc0, 0xe1, 0xd5, - 0xfd, 0xaf, 0xc2, 0x7e, 0xbe, 0xd7, 0x6b, 0x80, 0x8d, 0x27, 0xe2, 0xa6, 0xc1, 0x6b, 0xb7, 0xf0, - 0xa8, 0x5c, 0x5b, 0x15, 0xdb, 0x7f, 0x59, 0xa4, 0x14, 0x53, 0xa0, 0xff, 0x18, 0x38, 0x16, 0x5d, - 0xf7, 0x4d, 0x54, 0xe4, 0xdf, 0x22, 0x20, 0xd2, 0xd4, 0x9f, 0x49, 0x24, 0x77, 0x2c, 0x22, 0xfd, - 0x8b, 0xfa, 0x57, 0xd0, 0x48, 0x6d, 0x3a, 0x81, 0xf0, 0xfd, 0x16, 0xf3, 0xca, 0xad, 0xeb, 0x63, - 0xa7, 0x76, 0x74, 0x02, 0x0f, 0x89, 0x2b, 0xac, 0xb0, 0x7e, 0xaa, 0xd4, 0x58, 0xe8, 0x4f, 0xa2, - 0x8e, 0xa9, 0x4d, 0xe1, 0x9b, 0x72, 0x85, 0x8e, 0x47, 0xb9, 0xcf, 0xa9, 0x0b, 0x86, 0x20, 0xb3, - 0x62, 0xcf, 0xf4, 0xcf, 0xf1, 0x7c, 0x1a, 0xa8, 0x3b, 0x0e, 0xaf, 0x94, 0x28, 0x67, 0x9b, 0x21, - 0x74, 0x29, 0xe1, 0x53, 0x78, 0xbd, 0x44, 0xf8, 0x43, 0x05, 0x15, 0x40, 0xf2, 0x36, 0x3e, 0x1d, - 0x1f, 0x55, 0xf4, 0x44, 0xd3, 0x92, 0x69, 0xce, 0xe2, 0x53, 0x82, 0x92, 0xb9, 0x97, 0xcd, 0x33, - 0xbc, 0xce, 0xb7, 0x66, 0x0b, 0x26, 0xab, 0x5b, 0x8c, 0x95, 0x59, 0x79, 0x32, 0x77, 0x16, 0xcd, - 0x0f, 0x97, 0xc6, 0xab, 0x11, 0xce, 0x2f, 0x60, 0xa3, 0x39, 0x3b, 0x08, 0x8b, 0x4a, 0x78, 0xcb, - 0x8f, 0x15, 0x48, 0xfd, 0x72, 0x94, 0x1b, 0x89, 0x5d, 0x20, 0x79, 0x06, 0xbf, 0x23, 0x95, 0xec, - 0x5c, 0x09, 0x56, 0xfa, 0x36, 0x64, 0xc0, 0x9a, 0xef, 0x3d, 0x64, 0xd5, 0xf0, 0x0b, 0xbd, 0xed, - 0x87, 0xe2, 0x6d, 0xd5, 0xa1, 0x2d, 0xa5, 0x34, 0x3c, 0x6c, 0xd3, 0x60, 0xb3, 0xe9, 0xfd, 0x93, - 0xa5, 0xe6, 0x5a, 0xff, 0x25, 0x82, 0xbe, 0xaa, 0x5d, 0x2d, 0xe0, 0xf9, 0x0e, 0x1e, 0xf7, 0x6b, - 0x7c, 0xc7, 0xaf, 0x79, 0xe5, 0x0d, 0x1a, 0xdc, 0xf4, 0xc2, 0xcd, 0x68, 0x92, 0xd1, 0xb6, 0x11, - 0x9e, 0x16, 0xf3, 0x13, 0xcb, 0x77, 0xd7, 0x19, 0x83, 0xd3, 0x0d, 0xa3, 0xed, 0x1b, 0x64, 0x1e, - 0x8f, 0x85, 0xff, 0xca, 0xf5, 0x3b, 0x27, 0xfc, 0x9f, 0x7c, 0xac, 0xcf, 0xe1, 0xf3, 0x02, 0xe6, - 0x97, 0x2c, 0x08, 0xa8, 0xcd, 0xb6, 0x68, 0x10, 0x38, 0x9e, 0xbd, 0xd5, 0xd2, 0x18, 0x79, 0x77, - 0x1d, 0x5f, 0xe8, 0x76, 0x10, 0x88, 0x4d, 0xe1, 0x93, 0xf7, 0x9a, 0x10, 0x1b, 0x84, 0x5a, 0x0f, - 0xf4, 0x3c, 0xb8, 0xbb, 0x99, 0x85, 0xac, 0xba, 0xee, 0x52, 0x3b, 0xba, 0x0b, 0x85, 0x97, 0xf8, - 0xe9, 0x8c, 0x03, 0xa0, 0x9f, 0xe2, 0xf7, 0xaa, 0x89, 0x3d, 0x28, 0x82, 0x46, 0x97, 0x7c, 0x4d, - 0xaa, 0x84, 0x4e, 0xb1, 0x4d, 0xdd, 0xd2, 0x2f, 0xce, 0xe1, 0x21, 0x01, 0x82, 0x3c, 0x43, 0x78, - 0x54, 0xbe, 0x74, 0x93, 0xab, 0x5d, 0x6c, 0x74, 0x98, 0x37, 0x69, 0xd7, 0x7a, 0x92, 0x6d, 0xd0, - 0xd6, 0x3f, 0x7b, 0xfc, 0xf2, 0x7f, 0x4f, 0x06, 0xaf, 0x90, 0xcb, 0x46, 0x28, 0xba, 0x20, 0x4d, - 0x18, 0x9b, 0x63, 0xbc, 0xa6, 0x90, 0x71, 0x00, 0x5f, 0xb0, 0x43, 0xe3, 0x40, 0x7c, 0xb3, 0x0e, - 0xc9, 0x1f, 0x10, 0x1e, 0x93, 0xf5, 0x16, 0x5d, 0x57, 0x8d, 0x4b, 0xfa, 0xd4, 0x49, 0x8d, 0x4b, - 0xc6, 0x24, 0x49, 0xbf, 0x24, 0xb8, 0x9c, 0x27, 0xb3, 0x0a, 0x5c, 0xc8, 0xbf, 0x11, 0x3e, 0x93, - 0x40, 0x0e, 0x97, 0x7f, 0x52, 0xec, 0x01, 0x44, 0x7c, 0x82, 0xa1, 0xad, 0x1e, 0x47, 0x05, 0xd0, - 0xb9, 0x2a, 0xe8, 0x7c, 0x42, 0x96, 0x14, 0xe8, 0x80, 0x2c, 0x44, 0xe8, 0x90, 0xfc, 0x0b, 0xe1, - 0x6f, 0x48, 0x37, 0x6c, 0x89, 0xdc, 0xe7, 0x8a, 0xc8, 0x32, 0xa7, 0x33, 0x5a, 0xf1, 0x18, 0x1a, - 0x80, 0xda, 0x8a, 0xa0, 0xb6, 0x4c, 0x3e, 0xc9, 0xa0, 0xe6, 0x78, 0x19, 0xcc, 0x4c, 0xa7, 0x7c, - 0x48, 0x7e, 0x8f, 0xf0, 0xe9, 0x38, 0x39, 0xe5, 0x9c, 0x4b, 0x99, 0x93, 0x28, 0xe7, 0x5c, 0xda, - 0xec, 0xa3, 0x6b, 0xce, 0x49, 0x4c, 0x02, 0xf2, 0x77, 0x00, 0x2e, 0xdd, 0x1f, 0x57, 0x14, 0x5f, - 0xde, 0xd4, 0x5b, 0xb4, 0xf6, 0x59, 0x8f, 0xd2, 0x00, 0xfe, 0xbb, 0x02, 0xfc, 0x12, 0xf9, 0xa8, - 0x03, 0xf8, 0x96, 0x98, 0x71, 0x10, 0xad, 0x0f, 0xc9, 0x3f, 0x10, 0x26, 0xed, 0x73, 0x05, 0xa2, - 0x84, 0x27, 0x73, 0x9a, 0xa1, 0x7d, 0xaf, 0x57, 0x71, 0xe0, 0x53, 0x14, 0x7c, 0xae, 0x91, 0x4f, - 0x33, 0xf9, 0x24, 0xff, 0xf3, 0xc3, 0x2c, 0x53, 0x4e, 0x65, 0x62, 0x7f, 0x42, 0x78, 0x3c, 0x6e, - 0x21, 0x4c, 0xaf, 0x95, 0x23, 0xa4, 0x48, 0x8f, 0x51, 0xca, 0x9c, 0x5f, 0xe8, 0x0b, 0x82, 0xd5, - 0x1c, 0x39, 0xaf, 0x14, 0x25, 0xf2, 0x1b, 0xd4, 0xba, 0x37, 0x93, 0x65, 0xc5, 0x04, 0x49, 0x5c, - 0xf0, 0xb5, 0x2b, 0x47, 0x96, 0x03, 0xb0, 0x86, 0x00, 0xfb, 0x21, 0x99, 0xcb, 0x00, 0x6b, 0x83, - 0x40, 0xe8, 0xf3, 0x32, 0xab, 0x1f, 0x92, 0x5f, 0x21, 0x3c, 0x12, 0x69, 0x09, 0x5d, 0xbd, 0xac, - 0xe8, 0xac, 0x9e, 0x10, 0xa7, 0x8c, 0x19, 0xf4, 0x39, 0x81, 0xf8, 0x1c, 0x99, 0xe9, 0x82, 0x98, - 0x3c, 0x45, 0xf8, 0xbd, 0x64, 0xdf, 0x45, 0x94, 0x8a, 0x47, 0x46, 0x13, 0xa8, 0xad, 0xf4, 0x26, - 0xac, 0xe8, 0x6a, 0x2b, 0x89, 0xf5, 0x19, 0xc2, 0x23, 0x52, 0x6b, 0x45, 0xae, 0xab, 0x98, 0xef, - 0xd6, 0xc2, 0x69, 0x5f, 0x1c, 0x53, 0x0b, 0xb0, 0xb9, 0x28, 0xd8, 0x7c, 0x9b, 0xe8, 0x19, 0x6c, - 0xa4, 0x76, 0x94, 0x3c, 0x47, 0x6d, 0x93, 0x04, 0xa2, 0x5a, 0x0a, 0xd3, 0xe7, 0x20, 0x6a, 0xa5, - 0x27, 0x7b, 0x86, 0xa3, 0x2f, 0x0b, 0xf8, 0x1f, 0x91, 0x42, 0x06, 0x7c, 0x37, 0x2e, 0xd7, 0x4c, - 0xff, 0xbf, 0x20, 0x4c, 0x12, 0x3a, 0xc3, 0xb7, 0x40, 0xb5, 0x64, 0x1c, 0x87, 0x4d, 0xf6, 0xa4, - 0x46, 0x2f, 0x08, 0x36, 0xf3, 0xe4, 0x82, 0x1a, 0x1b, 0xf2, 0x73, 0x84, 0x4f, 0x88, 0xe2, 0xb3, - 0xa4, 0xe8, 0x46, 0xb9, 0x3c, 0x7e, 0x7c, 0x24, 0x19, 0xc5, 0xef, 0xae, 0x05, 0x1f, 0x2c, 0xe1, - 0xe4, 0xdf, 0x21, 0x3c, 0x22, 0x4d, 0x68, 0xc8, 0xa7, 0x47, 0xb0, 0x18, 0x9f, 0xea, 0xf4, 0x06, - 0xf6, 0xb2, 0x00, 0x6b, 0x90, 0x85, 0x8e, 0x60, 0xdb, 0x9a, 0xeb, 0x9f, 0x21, 0xfc, 0x6e, 0xf4, - 0x05, 0x5a, 0x52, 0x8c, 0xe8, 0x91, 0x1d, 0x9b, 0x98, 0xd2, 0xe8, 0xb3, 0x02, 0xeb, 0x34, 0xf9, - 0xa0, 0x03, 0xd6, 0xb0, 0x03, 0x1b, 0x0b, 0xa5, 0x36, 0x9d, 0x80, 0x47, 0xd7, 0x6e, 0xa5, 0x16, - 0x2c, 0x7d, 0xc2, 0xa2, 0xd6, 0x82, 0x65, 0x0c, 0x53, 0xba, 0x56, 0x0e, 0xab, 0x25, 0x43, 0xfe, - 0x8f, 0x70, 0x3e, 0x01, 0xfc, 0x8e, 0xc3, 0x2b, 0x8e, 0xd7, 0xbc, 0xc4, 0x91, 0x8d, 0x1e, 0xb0, - 0xa4, 0xcd, 0x50, 0xb4, 0x1b, 0xc7, 0x57, 0x04, 0x0c, 0xaf, 0x08, 0x86, 0x8b, 0xc4, 0xe8, 0xce, - 0x30, 0xa6, 0x40, 0x74, 0xca, 0xf1, 0x3f, 0x7a, 0x50, 0xcb, 0xfd, 0xd4, 0x3f, 0xa3, 0xd0, 0xae, - 0xf6, 0x22, 0xaa, 0xd8, 0xc4, 0x3c, 0x8a, 0xa3, 0x0c, 0x81, 0xc7, 0x27, 0x2e, 0x6a, 0xc0, 0x53, - 0x67, 0x38, 0x6a, 0xc0, 0xd3, 0x07, 0x3c, 0x5d, 0x81, 0xbb, 0x71, 0x94, 0x61, 0x93, 0x90, 0x1c, - 0x08, 0xa8, 0x35, 0x09, 0x19, 0xa3, 0x0b, 0xb5, 0x26, 0x21, 0x6b, 0xac, 0xd1, 0xb5, 0x49, 0x48, - 0x0e, 0x29, 0x56, 0xbf, 0xff, 0xfc, 0x55, 0x1e, 0xbd, 0x78, 0x95, 0x47, 0xff, 0x7d, 0x95, 0x47, - 0x3f, 0x7d, 0x9d, 0x1f, 0x78, 0xf1, 0x3a, 0x3f, 0xf0, 0xcf, 0xd7, 0xf9, 0x81, 0xbb, 0x8b, 0xb6, - 0xc3, 0x2b, 0xb5, 0x9d, 0x82, 0xe5, 0xef, 0xca, 0xca, 0x22, 0x4c, 0x46, 0x5d, 0xd6, 0xcb, 0xf7, - 0xf7, 0x58, 0xb0, 0xf3, 0x8e, 0xf8, 0x6a, 0x7f, 0xfc, 0x75, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdc, - 0x55, 0x35, 0x06, 0x22, 0x25, 0x00, 0x00, + // 1901 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5a, 0xc1, 0x6f, 0xdc, 0x4a, + 0x19, 0xcf, 0x64, 0x9b, 0xf7, 0xd2, 0x49, 0xda, 0xbc, 0xcc, 0x0b, 0x25, 0xf8, 0x25, 0x9b, 0xd6, + 0xa1, 0x4d, 0x48, 0xc8, 0xfa, 0x25, 0x7d, 0xcd, 0xa3, 0x6d, 0x1e, 0x62, 0x93, 0xbe, 0xa4, 0x81, + 0xb4, 0x4d, 0x57, 0x41, 0x45, 0x45, 0xc8, 0x9a, 0x78, 0xa7, 0x5e, 0xab, 0x8e, 0x9d, 0xae, 0xbd, + 0xd5, 0xa6, 0x51, 0x2e, 0x3d, 0x70, 0x46, 0xea, 0x81, 0x0b, 0x57, 0x44, 0x0f, 0x1c, 0x38, 0x20, + 0x38, 0x20, 0x15, 0x21, 0xa0, 0xf4, 0x58, 0x09, 0x81, 0x10, 0x48, 0x08, 0xb5, 0xfc, 0x05, 0xfc, + 0x05, 0xc8, 0xe3, 0xcf, 0xbb, 0x63, 0xaf, 0xbd, 0x3b, 0xd9, 0x6c, 0x0f, 0x3d, 0x75, 0xed, 0x99, + 0xef, 0x9b, 0xdf, 0xef, 0x9b, 0x6f, 0x3e, 0x7f, 0xf3, 0x6b, 0xf0, 0x39, 0xa3, 0xea, 0x7a, 0x9e, + 0x51, 0xa1, 0x96, 0xa3, 0x3d, 0xaa, 0xb1, 0xea, 0x41, 0x61, 0xbf, 0xea, 0xfa, 0x2e, 0x99, 0x7c, + 0xc2, 0x7c, 0xca, 0x5f, 0x17, 0xf8, 0x2f, 0xb7, 0xca, 0x0a, 0xcd, 0xa9, 0xca, 0x9c, 0xe1, 0x7a, + 0x7b, 0xae, 0xa7, 0xed, 0x52, 0x8f, 0x85, 0x76, 0xda, 0xe3, 0xc5, 0x5d, 0xe6, 0xd3, 0x45, 0x6d, + 0x9f, 0x9a, 0x96, 0x43, 0x7d, 0xcb, 0x75, 0x42, 0x57, 0xca, 0x94, 0xb0, 0x04, 0xff, 0xa9, 0xf3, + 0xdf, 0xba, 0x5f, 0x87, 0x09, 0x8a, 0x30, 0xc1, 0xa4, 0x9e, 0xbe, 0x5f, 0xb5, 0x0c, 0x06, 0x63, + 0xd3, 0xc2, 0x18, 0xb7, 0xd1, 0x2b, 0xd4, 0xab, 0xe8, 0xbe, 0xab, 0x1b, 0x46, 0xc3, 0x41, 0xbe, + 0x65, 0x92, 0x5f, 0xa5, 0xc6, 0x43, 0x56, 0x85, 0x71, 0x55, 0x18, 0xb7, 0xa9, 0xe7, 0xeb, 0xbb, + 0xb6, 0x6b, 0x3c, 0xd4, 0x2b, 0xcc, 0x32, 0x2b, 0x7e, 0x0a, 0x4a, 0xb7, 0xe6, 0xb7, 0x3a, 0x11, + 0x91, 0x54, 0xa9, 0xcf, 0x74, 0xdb, 0xda, 0xb3, 0x7c, 0x56, 0xd5, 0x1f, 0xd8, 0xd4, 0xf4, 0x60, + 0xd2, 0x98, 0xe9, 0x9a, 0x2e, 0xff, 0xa9, 0x05, 0xbf, 0xe0, 0xed, 0x84, 0xe9, 0xba, 0xa6, 0xcd, + 0x34, 0xba, 0x6f, 0x69, 0xd4, 0x71, 0x5c, 0x9f, 0x87, 0x07, 0x6c, 0xd4, 0x09, 0xac, 0xdc, 0x0d, + 0x22, 0x78, 0x9f, 0xf9, 0xb4, 0x68, 0x18, 0x6e, 0xcd, 0xf1, 0x2d, 0xc7, 0x2c, 0xb1, 0x47, 0x35, + 0xe6, 0xf9, 0xea, 0x2d, 0xfc, 0x49, 0xea, 0xa8, 0xb7, 0xef, 0x3a, 0x1e, 0x23, 0x05, 0xfc, 0x31, + 0xdd, 0x75, 0xab, 0x3e, 0x2b, 0xeb, 0xc1, 0x3e, 0xe9, 0x74, 0x2f, 0x98, 0x31, 0x8e, 0xce, 0xa3, + 0xd9, 0xd3, 0xa5, 0x51, 0x18, 0xe2, 0xb6, 0x7c, 0xa0, 0xe1, 0x6e, 0x83, 0xf9, 0x77, 0x6a, 0xfe, + 0x4e, 0x7d, 0x27, 0xe4, 0x08, 0xab, 0x91, 0x71, 0xfc, 0x21, 0x67, 0xb8, 0x79, 0x83, 0xbb, 0xc8, + 0x95, 0xa2, 0x47, 0x32, 0x86, 0x07, 0x1c, 0xd7, 0x31, 0xd8, 0x78, 0xff, 0x79, 0x34, 0x7b, 0xaa, + 0x14, 0x3e, 0xa8, 0x35, 0x3c, 0x91, 0xee, 0x0e, 0xe0, 0x7d, 0x1f, 0x0f, 0xbb, 0xc2, 0x7b, 0xee, + 0x74, 0x68, 0x69, 0xbe, 0xd0, 0x36, 0xbb, 0x0a, 0xa2, 0xab, 0xd5, 0x53, 0xaf, 0xfe, 0x3d, 0xd5, + 0x57, 0x8a, 0xb9, 0x51, 0x19, 0xb0, 0x28, 0xda, 0x76, 0x1a, 0x8b, 0x75, 0x8c, 0x9b, 0x59, 0x08, + 0x6b, 0x5e, 0x2a, 0x84, 0x29, 0x5b, 0x08, 0x52, 0xb6, 0x10, 0xa6, 0x3a, 0xa4, 0x6c, 0x61, 0x9b, + 0x9a, 0x0c, 0x6c, 0x4b, 0x82, 0xa5, 0xfa, 0x02, 0x01, 0xbd, 0x96, 0x75, 0x32, 0xe9, 0xe5, 0x7a, + 0x40, 0x8f, 0x6c, 0xc4, 0xf0, 0xf7, 0x73, 0xfc, 0x33, 0x1d, 0xf1, 0x87, 0x98, 0x62, 0x04, 0x9e, + 0x22, 0xac, 0xa6, 0x11, 0x58, 0x3d, 0x58, 0x0b, 0x90, 0x44, 0xf1, 0x1a, 0xc3, 0x03, 0x1c, 0x19, + 0xec, 0x79, 0xf8, 0x90, 0x88, 0x62, 0x7f, 0xd7, 0x51, 0xfc, 0x33, 0xc2, 0xd3, 0x6d, 0x41, 0xbc, + 0x27, 0xc1, 0xfc, 0x31, 0xc2, 0x17, 0x22, 0x1e, 0x9b, 0x4e, 0x56, 0x2c, 0xbf, 0x86, 0x07, 0xc3, + 0xf2, 0x66, 0x95, 0xe3, 0x47, 0xa8, 0xdc, 0xb3, 0x80, 0xfe, 0x41, 0xd8, 0xd5, 0x34, 0x20, 0x10, + 0xcf, 0x12, 0x1e, 0xb2, 0x9c, 0x64, 0x38, 0xe7, 0x3a, 0x84, 0x53, 0xf4, 0x17, 0x46, 0x53, 0x74, + 0xd2, 0xbb, 0x60, 0x0a, 0x27, 0x58, 0x58, 0xd2, 0xeb, 0xf5, 0x09, 0xfe, 0x9d, 0x70, 0x82, 0xe3, + 0xeb, 0xbc, 0x0f, 0x41, 0xba, 0x8e, 0x27, 0xa3, 0xea, 0x1a, 0x2c, 0x79, 0x93, 0x7a, 0x95, 0x1d, + 0x77, 0xcd, 0xf0, 0xeb, 0x51, 0x98, 0x14, 0x3c, 0x68, 0xc1, 0x00, 0x94, 0xfc, 0xc6, 0xb3, 0x7a, + 0x84, 0xf3, 0x59, 0xc6, 0xc0, 0xfd, 0x87, 0xf8, 0xac, 0x15, 0x1b, 0x81, 0x40, 0x2f, 0x48, 0xd0, + 0x6f, 0x1a, 0x41, 0x04, 0x12, 0xae, 0xd4, 0x15, 0x58, 0x3e, 0x3e, 0xf9, 0x06, 0xf5, 0xa9, 0x0c, + 0xf8, 0x27, 0x78, 0x2a, 0xd3, 0x1a, 0xd0, 0xdf, 0xc3, 0x67, 0xd6, 0x02, 0x4c, 0x3c, 0xe9, 0x77, + 0xea, 0x9e, 0x64, 0xbd, 0x10, 0x6d, 0x00, 0x7a, 0xdc, 0x8f, 0x6a, 0x42, 0xd4, 0x21, 0x65, 0x5a, + 0xa3, 0xde, 0xab, 0xe4, 0x7c, 0x89, 0x20, 0x46, 0x29, 0x2b, 0xb5, 0xd9, 0xa2, 0x5c, 0x8f, 0xb6, + 0xa8, 0x77, 0x79, 0xaa, 0xe1, 0xaf, 0x46, 0xa9, 0xb6, 0x41, 0xbd, 0xed, 0xa0, 0x7d, 0x13, 0x3e, + 0x2d, 0x96, 0x53, 0x66, 0x75, 0xd8, 0xe1, 0xf0, 0x41, 0xd5, 0xf1, 0x78, 0xab, 0x01, 0x50, 0x5e, + 0xc3, 0x83, 0xd1, 0x3b, 0x88, 0xed, 0x4c, 0x07, 0xb2, 0x0d, 0x17, 0x0d, 0x43, 0x95, 0x02, 0xa2, + 0xa2, 0x6d, 0x27, 0x11, 0xf5, 0x6a, 0xf7, 0x9e, 0x23, 0x20, 0x11, 0x5b, 0x23, 0x95, 0x44, 0xae, + 0x2b, 0x12, 0xbd, 0xdb, 0x9f, 0xe5, 0x66, 0x29, 0xd8, 0xa2, 0x9e, 0xbf, 0x1a, 0x74, 0xbf, 0x37, + 0x79, 0xf3, 0xdb, 0x7e, 0x9b, 0x0e, 0xe1, 0x14, 0xa6, 0xd9, 0x01, 0xd1, 0x1f, 0xe0, 0x91, 0xc4, + 0x10, 0x84, 0xb4, 0xd0, 0x81, 0x6f, 0xd2, 0x61, 0xd2, 0x8d, 0x5a, 0x69, 0x1e, 0x8e, 0x0c, 0xd0, + 0xbd, 0xda, 0xc9, 0x3f, 0x21, 0xe0, 0x99, 0xb6, 0x54, 0x3b, 0x9e, 0xb9, 0x1e, 0xf0, 0xec, 0xdd, + 0x2e, 0xcf, 0xe3, 0x8f, 0xa3, 0xdd, 0x12, 0xab, 0x55, 0xfa, 0xd6, 0x6e, 0xc1, 0xa5, 0x03, 0x26, + 0xaf, 0x1e, 0xdc, 0x0e, 0xfa, 0xf9, 0x6e, 0xaf, 0x01, 0x26, 0x1e, 0x8b, 0x2f, 0x0d, 0x51, 0xbb, + 0x83, 0x87, 0xc5, 0xda, 0x2a, 0xd9, 0xfe, 0x8b, 0x26, 0xa5, 0x98, 0x03, 0xf5, 0x47, 0xc0, 0xb1, + 0x68, 0xdb, 0xef, 0xa2, 0x22, 0xff, 0x0a, 0x01, 0x91, 0x86, 0xff, 0x4c, 0x22, 0xb9, 0x13, 0x11, + 0xe9, 0xdd, 0xae, 0xdf, 0x86, 0x46, 0x6a, 0xcb, 0xf2, 0xfc, 0x6d, 0xe6, 0x94, 0x2d, 0xc7, 0x14, + 0x23, 0xd3, 0xa6, 0x1d, 0x1d, 0xc3, 0x03, 0xfc, 0x0a, 0xcb, 0x57, 0x3f, 0x53, 0x0a, 0x1f, 0xd4, + 0x67, 0x51, 0xc7, 0xd4, 0xe2, 0xf0, 0x5d, 0x85, 0x42, 0xc5, 0xc3, 0xbe, 0xeb, 0x53, 0x1b, 0x16, + 0x83, 0xcc, 0x8a, 0xbd, 0x53, 0x57, 0xf1, 0x5c, 0x1a, 0xa8, 0x7b, 0x96, 0x5f, 0xb1, 0x9c, 0x12, + 0xf5, 0xd9, 0x56, 0x00, 0x5e, 0x48, 0xf9, 0x90, 0x19, 0x12, 0x99, 0xfd, 0x0d, 0xe1, 0x79, 0x29, + 0x27, 0x40, 0xf4, 0x2e, 0x3e, 0x1b, 0x97, 0x2b, 0xba, 0xa2, 0x6a, 0x88, 0x54, 0xa7, 0xf1, 0x19, + 0x4e, 0x4b, 0xdf, 0xcf, 0xe6, 0x1a, 0x5c, 0xe9, 0x9b, 0xfa, 0x82, 0xce, 0xea, 0x06, 0x63, 0x65, + 0x56, 0x1e, 0xcf, 0x9d, 0x47, 0xb3, 0x83, 0xa5, 0xd1, 0x6a, 0x84, 0xf3, 0x4b, 0x18, 0x68, 0xe8, + 0x07, 0x41, 0x61, 0x09, 0x6e, 0xfa, 0xb1, 0x22, 0xa9, 0x5e, 0x89, 0xf2, 0x23, 0x31, 0x0a, 0x24, + 0xcf, 0xe1, 0x0f, 0x84, 0xb2, 0x9d, 0x2b, 0xc1, 0x93, 0xba, 0x03, 0x59, 0xb0, 0xe6, 0x3a, 0x8f, + 0x59, 0x35, 0xf8, 0x4a, 0xef, 0xb8, 0x81, 0x79, 0x4b, 0x85, 0x68, 0x49, 0x2b, 0x05, 0x0f, 0x9a, + 0xd4, 0xdb, 0x6a, 0x64, 0xd6, 0xe9, 0x52, 0xe3, 0x59, 0xfd, 0x39, 0x82, 0xde, 0xaa, 0xd5, 0x2d, + 0xe0, 0xf9, 0x26, 0x1e, 0x75, 0x6b, 0xfe, 0xae, 0x5b, 0x73, 0xca, 0x1b, 0xd4, 0xdb, 0x74, 0x82, + 0xc1, 0x48, 0xcd, 0x68, 0x19, 0x08, 0x66, 0x73, 0x0d, 0xc5, 0x70, 0xed, 0x75, 0xc6, 0x60, 0x76, + 0xb8, 0x68, 0xeb, 0x00, 0x99, 0xc5, 0x23, 0xc1, 0xbf, 0x62, 0x0d, 0xcf, 0xf1, 0xf8, 0x27, 0x5f, + 0xab, 0x33, 0xf8, 0x22, 0x87, 0x79, 0x8b, 0x79, 0x1e, 0x35, 0xd9, 0x36, 0xf5, 0x3c, 0xcb, 0x31, + 0xb7, 0x9b, 0x1e, 0xa3, 0xe8, 0xae, 0xe3, 0x4b, 0x9d, 0x26, 0x02, 0xb1, 0x09, 0x7c, 0xfa, 0x41, + 0x03, 0x62, 0x48, 0xa8, 0xf9, 0x42, 0xcd, 0x43, 0xb8, 0x1b, 0x59, 0xc8, 0xaa, 0xeb, 0x36, 0x35, + 0xa3, 0xfb, 0x50, 0x70, 0x91, 0x9f, 0xcc, 0x98, 0x00, 0xfe, 0x29, 0xfe, 0xa8, 0x9a, 0x18, 0x83, + 0x42, 0xa8, 0x75, 0xc8, 0xd7, 0xa4, 0x4b, 0xe8, 0x16, 0x5b, 0xdc, 0x2d, 0x3d, 0xbf, 0x80, 0x07, + 0x38, 0x08, 0xf2, 0x12, 0xe1, 0x61, 0xf1, 0xe2, 0x4d, 0xae, 0x75, 0x58, 0xa3, 0x8d, 0xe6, 0xa4, + 0x5c, 0xef, 0xca, 0x36, 0xa4, 0xad, 0x7e, 0xf1, 0xf4, 0xaf, 0xff, 0x7d, 0xd6, 0xff, 0x39, 0xb9, + 0xa2, 0x05, 0xa6, 0x0b, 0x82, 0xca, 0xd8, 0x90, 0xf2, 0x1a, 0x46, 0xda, 0x21, 0x7c, 0xc5, 0x8e, + 0xb4, 0x43, 0xfe, 0xdd, 0x3a, 0x22, 0xbf, 0x45, 0x78, 0x44, 0xf4, 0x5b, 0xb4, 0x6d, 0x39, 0x2e, + 0xe9, 0xca, 0x93, 0x1c, 0x97, 0x0c, 0x35, 0x49, 0x9d, 0xe7, 0x5c, 0x2e, 0x92, 0x69, 0x09, 0x2e, + 0xe4, 0x5f, 0x08, 0x9f, 0x4b, 0x20, 0x07, 0x01, 0x80, 0x14, 0xbb, 0x00, 0x11, 0x57, 0x31, 0x94, + 0xd5, 0x93, 0xb8, 0x00, 0x3a, 0xd7, 0x38, 0x9d, 0xcf, 0xc8, 0x92, 0x04, 0x1d, 0xb0, 0x85, 0x1d, + 0x3a, 0x22, 0xff, 0x44, 0xf8, 0x2b, 0xc2, 0x2d, 0x5b, 0x20, 0xf7, 0x1d, 0x49, 0x64, 0x99, 0x0a, + 0x8d, 0x52, 0x3c, 0x81, 0x07, 0xa0, 0xb6, 0xc2, 0xa9, 0x2d, 0x93, 0xcf, 0x32, 0xa8, 0x59, 0x4e, + 0x06, 0x33, 0xdd, 0x2a, 0x1f, 0x91, 0xdf, 0x20, 0x7c, 0x36, 0x4e, 0x4e, 0x3a, 0xe7, 0x52, 0xb4, + 0x12, 0xe9, 0x9c, 0x4b, 0xd3, 0x3f, 0x3a, 0xe6, 0x9c, 0xc0, 0xc4, 0x23, 0x7f, 0x01, 0xe0, 0xc2, + 0x1d, 0x72, 0x45, 0xf2, 0xf0, 0xa6, 0xde, 0xa4, 0x95, 0x2f, 0xba, 0xb4, 0x06, 0xf0, 0xdf, 0xe2, + 0xe0, 0x97, 0xc8, 0xa7, 0x6d, 0xc0, 0x37, 0xcd, 0xb4, 0xc3, 0xe8, 0xf9, 0x88, 0xfc, 0x1d, 0x61, + 0xd2, 0xaa, 0x2d, 0x10, 0x29, 0x3c, 0x99, 0x8a, 0x86, 0xf2, 0xed, 0x6e, 0xcd, 0x81, 0x4f, 0x91, + 0xf3, 0xb9, 0x4e, 0xae, 0x66, 0xf2, 0x49, 0xfe, 0x07, 0x88, 0x5e, 0xa6, 0x3e, 0x15, 0x89, 0xfd, + 0x1e, 0xe1, 0xd1, 0xf8, 0x0a, 0x41, 0x7a, 0xad, 0x1c, 0x23, 0x45, 0xba, 0xdc, 0xa5, 0x4c, 0x0d, + 0x43, 0x5d, 0xe0, 0xac, 0x66, 0xc8, 0x45, 0xa9, 0x5d, 0x22, 0xbf, 0x44, 0xcd, 0xbb, 0x33, 0x59, + 0x96, 0x4c, 0x90, 0xc4, 0x25, 0x5f, 0xf9, 0xfc, 0xd8, 0x76, 0x00, 0x56, 0xe3, 0x60, 0xbf, 0x41, + 0x66, 0x32, 0xc0, 0x9a, 0x60, 0x10, 0xc4, 0xbc, 0xcc, 0xea, 0x47, 0xe4, 0x17, 0x08, 0x0f, 0x45, + 0x5e, 0x82, 0x50, 0x2f, 0x4b, 0x06, 0xab, 0x2b, 0xc4, 0x29, 0x52, 0x83, 0x3a, 0xc3, 0x11, 0x5f, + 0x20, 0x53, 0x1d, 0x10, 0x93, 0x17, 0x08, 0x7f, 0x94, 0xec, 0xbb, 0x88, 0x54, 0xf1, 0xc8, 0x68, + 0x02, 0x95, 0x95, 0xee, 0x8c, 0x25, 0x43, 0x6d, 0x24, 0xb1, 0xbe, 0x44, 0x78, 0x48, 0x68, 0xad, + 0xc8, 0x0d, 0x99, 0xe5, 0x3b, 0xb5, 0x70, 0xca, 0x97, 0x27, 0xf4, 0x02, 0x6c, 0xe6, 0x38, 0x9b, + 0xaf, 0x13, 0x35, 0x83, 0x8d, 0xd0, 0x8e, 0x92, 0x57, 0xa8, 0x45, 0x4d, 0x20, 0xb2, 0xa5, 0x30, + 0x5d, 0x0b, 0x91, 0x2b, 0x3d, 0xd9, 0x3a, 0x8e, 0xba, 0xcc, 0xe1, 0x7f, 0x4a, 0x0a, 0x19, 0xf0, + 0xed, 0xb8, 0x5d, 0x23, 0xfd, 0xff, 0x88, 0x30, 0x49, 0xf8, 0x0c, 0x4e, 0x81, 0x6c, 0xc9, 0x38, + 0x09, 0x9b, 0x6c, 0xb5, 0x46, 0x2d, 0x70, 0x36, 0xb3, 0xe4, 0x92, 0x1c, 0x1b, 0xf2, 0x33, 0x84, + 0x4f, 0xf1, 0xe2, 0xb3, 0x24, 0x19, 0x46, 0xb1, 0x3c, 0x5e, 0x3e, 0x96, 0x8d, 0xe4, 0x77, 0xd7, + 0x80, 0x0f, 0x16, 0x0f, 0xf2, 0xaf, 0x11, 0x1e, 0x12, 0x54, 0x1a, 0x72, 0xf5, 0x18, 0x2b, 0xc6, + 0x95, 0x9d, 0xee, 0xc0, 0x5e, 0xe1, 0x60, 0x35, 0xb2, 0xd0, 0x16, 0x6c, 0x4b, 0x73, 0xfd, 0x53, + 0x84, 0x3f, 0x8c, 0xbe, 0x40, 0x4b, 0x92, 0x3b, 0x7a, 0xec, 0xc0, 0x26, 0x94, 0x1a, 0x75, 0x9a, + 0x63, 0x9d, 0x24, 0x9f, 0xb4, 0xc1, 0x1a, 0x74, 0x60, 0x23, 0x09, 0x15, 0x40, 0xae, 0x05, 0x4b, + 0x57, 0x59, 0xe4, 0x5a, 0xb0, 0x0c, 0x41, 0xa5, 0x73, 0xe5, 0x10, 0x40, 0xfe, 0x0f, 0xe1, 0x7c, + 0x7b, 0xf9, 0x82, 0x6c, 0x76, 0x81, 0x25, 0x5d, 0x47, 0x51, 0xbe, 0xdb, 0x0b, 0x57, 0xc0, 0xf2, + 0x2a, 0x67, 0x79, 0x99, 0x2c, 0x76, 0x66, 0x99, 0x64, 0x14, 0xf4, 0xcb, 0xf1, 0x3f, 0x7f, 0x90, + 0x3b, 0x01, 0xa9, 0x7f, 0x50, 0xa1, 0x5c, 0xeb, 0xc6, 0x54, 0xb2, 0x95, 0x79, 0x12, 0x47, 0x19, + 0x00, 0x8f, 0xeb, 0x2e, 0x72, 0xc0, 0x53, 0x95, 0x1c, 0x39, 0xe0, 0xe9, 0x32, 0x4f, 0x47, 0xe0, + 0x76, 0x1c, 0x65, 0xd0, 0x2a, 0x24, 0x65, 0x01, 0xb9, 0x56, 0x21, 0x43, 0xc0, 0x90, 0x6b, 0x15, + 0xb2, 0xc4, 0x8d, 0x8e, 0xad, 0x42, 0x52, 0xaa, 0x58, 0xfd, 0xde, 0xab, 0x37, 0x79, 0xf4, 0xfa, + 0x4d, 0x1e, 0xfd, 0xe7, 0x4d, 0x1e, 0xfd, 0xe4, 0x6d, 0xbe, 0xef, 0xf5, 0xdb, 0x7c, 0xdf, 0x3f, + 0xde, 0xe6, 0xfb, 0xee, 0x2f, 0x9a, 0x96, 0x5f, 0xa9, 0xed, 0x16, 0x0c, 0x77, 0x4f, 0x74, 0x16, + 0x61, 0xd2, 0xea, 0xa2, 0x5f, 0xff, 0x60, 0x9f, 0x79, 0xbb, 0x1f, 0xf0, 0x6f, 0xf7, 0xe5, 0xff, + 0x07, 0x00, 0x00, 0xff, 0xff, 0x25, 0x12, 0xcf, 0x1a, 0x2c, 0x25, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2265,9 +2266,9 @@ type QueryClient interface { // Queries a list of send items. CctxAll(ctx context.Context, in *QueryAllCctxRequest, opts ...grpc.CallOption) (*QueryAllCctxResponse, error) // Queries a list of pending cctxs. - CctxListPending(ctx context.Context, in *QueryListCctxPendingRequest, opts ...grpc.CallOption) (*QueryListCctxPendingResponse, error) - // Queries a list of pending cctxs with rate limit. - CctxListPendingWithinRateLimit(ctx context.Context, in *QueryListCctxPendingWithRateLimitRequest, opts ...grpc.CallOption) (*QueryListCctxPendingWithRateLimitResponse, error) + ListPendingCctx(ctx context.Context, in *QueryListPendingCctxRequest, opts ...grpc.CallOption) (*QueryListPendingCctxResponse, error) + // Queries a list of pending cctxs within rate limit. + ListPendingCctxWithinRateLimit(ctx context.Context, in *QueryListPendingCctxWithinRateLimitRequest, opts ...grpc.CallOption) (*QueryListPendingCctxWithinRateLimitResponse, error) ZetaAccounting(ctx context.Context, in *QueryZetaAccountingRequest, opts ...grpc.CallOption) (*QueryZetaAccountingResponse, error) // Queries a list of lastMetaHeight items. LastZetaHeight(ctx context.Context, in *QueryLastZetaHeightRequest, opts ...grpc.CallOption) (*QueryLastZetaHeightResponse, error) @@ -2436,18 +2437,18 @@ func (c *queryClient) CctxAll(ctx context.Context, in *QueryAllCctxRequest, opts return out, nil } -func (c *queryClient) CctxListPending(ctx context.Context, in *QueryListCctxPendingRequest, opts ...grpc.CallOption) (*QueryListCctxPendingResponse, error) { - out := new(QueryListCctxPendingResponse) - err := c.cc.Invoke(ctx, "/zetachain.zetacore.crosschain.Query/CctxListPending", in, out, opts...) +func (c *queryClient) ListPendingCctx(ctx context.Context, in *QueryListPendingCctxRequest, opts ...grpc.CallOption) (*QueryListPendingCctxResponse, error) { + out := new(QueryListPendingCctxResponse) + err := c.cc.Invoke(ctx, "/zetachain.zetacore.crosschain.Query/ListPendingCctx", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *queryClient) CctxListPendingWithinRateLimit(ctx context.Context, in *QueryListCctxPendingWithRateLimitRequest, opts ...grpc.CallOption) (*QueryListCctxPendingWithRateLimitResponse, error) { - out := new(QueryListCctxPendingWithRateLimitResponse) - err := c.cc.Invoke(ctx, "/zetachain.zetacore.crosschain.Query/CctxListPendingWithinRateLimit", in, out, opts...) +func (c *queryClient) ListPendingCctxWithinRateLimit(ctx context.Context, in *QueryListPendingCctxWithinRateLimitRequest, opts ...grpc.CallOption) (*QueryListPendingCctxWithinRateLimitResponse, error) { + out := new(QueryListPendingCctxWithinRateLimitResponse) + err := c.cc.Invoke(ctx, "/zetachain.zetacore.crosschain.Query/ListPendingCctxWithinRateLimit", in, out, opts...) if err != nil { return nil, err } @@ -2513,9 +2514,9 @@ type QueryServer interface { // Queries a list of send items. CctxAll(context.Context, *QueryAllCctxRequest) (*QueryAllCctxResponse, error) // Queries a list of pending cctxs. - CctxListPending(context.Context, *QueryListCctxPendingRequest) (*QueryListCctxPendingResponse, error) - // Queries a list of pending cctxs with rate limit. - CctxListPendingWithinRateLimit(context.Context, *QueryListCctxPendingWithRateLimitRequest) (*QueryListCctxPendingWithRateLimitResponse, error) + ListPendingCctx(context.Context, *QueryListPendingCctxRequest) (*QueryListPendingCctxResponse, error) + // Queries a list of pending cctxs within rate limit. + ListPendingCctxWithinRateLimit(context.Context, *QueryListPendingCctxWithinRateLimitRequest) (*QueryListPendingCctxWithinRateLimitResponse, error) ZetaAccounting(context.Context, *QueryZetaAccountingRequest) (*QueryZetaAccountingResponse, error) // Queries a list of lastMetaHeight items. LastZetaHeight(context.Context, *QueryLastZetaHeightRequest) (*QueryLastZetaHeightResponse, error) @@ -2578,11 +2579,11 @@ func (*UnimplementedQueryServer) CctxByNonce(ctx context.Context, req *QueryGetC func (*UnimplementedQueryServer) CctxAll(ctx context.Context, req *QueryAllCctxRequest) (*QueryAllCctxResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method CctxAll not implemented") } -func (*UnimplementedQueryServer) CctxListPending(ctx context.Context, req *QueryListCctxPendingRequest) (*QueryListCctxPendingResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method CctxListPending not implemented") +func (*UnimplementedQueryServer) ListPendingCctx(ctx context.Context, req *QueryListPendingCctxRequest) (*QueryListPendingCctxResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListPendingCctx not implemented") } -func (*UnimplementedQueryServer) CctxListPendingWithinRateLimit(ctx context.Context, req *QueryListCctxPendingWithRateLimitRequest) (*QueryListCctxPendingWithRateLimitResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method CctxListPendingWithinRateLimit not implemented") +func (*UnimplementedQueryServer) ListPendingCctxWithinRateLimit(ctx context.Context, req *QueryListPendingCctxWithinRateLimitRequest) (*QueryListPendingCctxWithinRateLimitResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListPendingCctxWithinRateLimit not implemented") } func (*UnimplementedQueryServer) ZetaAccounting(ctx context.Context, req *QueryZetaAccountingRequest) (*QueryZetaAccountingResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ZetaAccounting not implemented") @@ -2904,38 +2905,38 @@ func _Query_CctxAll_Handler(srv interface{}, ctx context.Context, dec func(inter return interceptor(ctx, in, info, handler) } -func _Query_CctxListPending_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryListCctxPendingRequest) +func _Query_ListPendingCctx_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryListPendingCctxRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(QueryServer).CctxListPending(ctx, in) + return srv.(QueryServer).ListPendingCctx(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/zetachain.zetacore.crosschain.Query/CctxListPending", + FullMethod: "/zetachain.zetacore.crosschain.Query/ListPendingCctx", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).CctxListPending(ctx, req.(*QueryListCctxPendingRequest)) + return srv.(QueryServer).ListPendingCctx(ctx, req.(*QueryListPendingCctxRequest)) } return interceptor(ctx, in, info, handler) } -func _Query_CctxListPendingWithinRateLimit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryListCctxPendingWithRateLimitRequest) +func _Query_ListPendingCctxWithinRateLimit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryListPendingCctxWithinRateLimitRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(QueryServer).CctxListPendingWithinRateLimit(ctx, in) + return srv.(QueryServer).ListPendingCctxWithinRateLimit(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/zetachain.zetacore.crosschain.Query/CctxListPendingWithinRateLimit", + FullMethod: "/zetachain.zetacore.crosschain.Query/ListPendingCctxWithinRateLimit", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).CctxListPendingWithinRateLimit(ctx, req.(*QueryListCctxPendingWithRateLimitRequest)) + return srv.(QueryServer).ListPendingCctxWithinRateLimit(ctx, req.(*QueryListPendingCctxWithinRateLimitRequest)) } return interceptor(ctx, in, info, handler) } @@ -3067,12 +3068,12 @@ var _Query_serviceDesc = grpc.ServiceDesc{ Handler: _Query_CctxAll_Handler, }, { - MethodName: "CctxListPending", - Handler: _Query_CctxListPending_Handler, + MethodName: "ListPendingCctx", + Handler: _Query_ListPendingCctx_Handler, }, { - MethodName: "CctxListPendingWithinRateLimit", - Handler: _Query_CctxListPendingWithinRateLimit_Handler, + MethodName: "ListPendingCctxWithinRateLimit", + Handler: _Query_ListPendingCctxWithinRateLimit_Handler, }, { MethodName: "ZetaAccounting", @@ -4250,7 +4251,7 @@ func (m *QueryAllCctxResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *QueryListCctxPendingRequest) Marshal() (dAtA []byte, err error) { +func (m *QueryListPendingCctxRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -4260,12 +4261,12 @@ func (m *QueryListCctxPendingRequest) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryListCctxPendingRequest) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryListPendingCctxRequest) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryListCctxPendingRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryListPendingCctxRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -4283,7 +4284,7 @@ func (m *QueryListCctxPendingRequest) MarshalToSizedBuffer(dAtA []byte) (int, er return len(dAtA) - i, nil } -func (m *QueryListCctxPendingResponse) Marshal() (dAtA []byte, err error) { +func (m *QueryListPendingCctxResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -4293,12 +4294,12 @@ func (m *QueryListCctxPendingResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *QueryListCctxPendingResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryListPendingCctxResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryListCctxPendingResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryListPendingCctxResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -4325,7 +4326,7 @@ func (m *QueryListCctxPendingResponse) MarshalToSizedBuffer(dAtA []byte) (int, e return len(dAtA) - i, nil } -func (m *QueryListCctxPendingWithRateLimitRequest) Marshal() (dAtA []byte, err error) { +func (m *QueryListPendingCctxWithinRateLimitRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -4335,12 +4336,12 @@ func (m *QueryListCctxPendingWithRateLimitRequest) Marshal() (dAtA []byte, err e return dAtA[:n], nil } -func (m *QueryListCctxPendingWithRateLimitRequest) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryListPendingCctxWithinRateLimitRequest) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryListCctxPendingWithRateLimitRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryListPendingCctxWithinRateLimitRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -4348,12 +4349,12 @@ func (m *QueryListCctxPendingWithRateLimitRequest) MarshalToSizedBuffer(dAtA []b if m.Limit != 0 { i = encodeVarintQuery(dAtA, i, uint64(m.Limit)) i-- - dAtA[i] = 0x10 + dAtA[i] = 0x8 } return len(dAtA) - i, nil } -func (m *QueryListCctxPendingWithRateLimitResponse) Marshal() (dAtA []byte, err error) { +func (m *QueryListPendingCctxWithinRateLimitResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -4363,12 +4364,12 @@ func (m *QueryListCctxPendingWithRateLimitResponse) Marshal() (dAtA []byte, err return dAtA[:n], nil } -func (m *QueryListCctxPendingWithRateLimitResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryListPendingCctxWithinRateLimitResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryListCctxPendingWithRateLimitResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryListPendingCctxWithinRateLimitResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -5108,7 +5109,7 @@ func (m *QueryAllCctxResponse) Size() (n int) { return n } -func (m *QueryListCctxPendingRequest) Size() (n int) { +func (m *QueryListPendingCctxRequest) Size() (n int) { if m == nil { return 0 } @@ -5123,7 +5124,7 @@ func (m *QueryListCctxPendingRequest) Size() (n int) { return n } -func (m *QueryListCctxPendingResponse) Size() (n int) { +func (m *QueryListPendingCctxResponse) Size() (n int) { if m == nil { return 0 } @@ -5141,7 +5142,7 @@ func (m *QueryListCctxPendingResponse) Size() (n int) { return n } -func (m *QueryListCctxPendingWithRateLimitRequest) Size() (n int) { +func (m *QueryListPendingCctxWithinRateLimitRequest) Size() (n int) { if m == nil { return 0 } @@ -5153,7 +5154,7 @@ func (m *QueryListCctxPendingWithRateLimitRequest) Size() (n int) { return n } -func (m *QueryListCctxPendingWithRateLimitResponse) Size() (n int) { +func (m *QueryListPendingCctxWithinRateLimitResponse) Size() (n int) { if m == nil { return 0 } @@ -8191,7 +8192,7 @@ func (m *QueryAllCctxResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryListCctxPendingRequest) Unmarshal(dAtA []byte) error { +func (m *QueryListPendingCctxRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -8214,10 +8215,10 @@ func (m *QueryListCctxPendingRequest) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryListCctxPendingRequest: wiretype end group for non-group") + return fmt.Errorf("proto: QueryListPendingCctxRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryListCctxPendingRequest: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryListPendingCctxRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -8279,7 +8280,7 @@ func (m *QueryListCctxPendingRequest) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryListCctxPendingResponse) Unmarshal(dAtA []byte) error { +func (m *QueryListPendingCctxResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -8302,10 +8303,10 @@ func (m *QueryListCctxPendingResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryListCctxPendingResponse: wiretype end group for non-group") + return fmt.Errorf("proto: QueryListPendingCctxResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryListCctxPendingResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryListPendingCctxResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -8382,7 +8383,7 @@ func (m *QueryListCctxPendingResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryListCctxPendingWithRateLimitRequest) Unmarshal(dAtA []byte) error { +func (m *QueryListPendingCctxWithinRateLimitRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -8405,13 +8406,13 @@ func (m *QueryListCctxPendingWithRateLimitRequest) Unmarshal(dAtA []byte) error fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryListCctxPendingWithRateLimitRequest: wiretype end group for non-group") + return fmt.Errorf("proto: QueryListPendingCctxWithinRateLimitRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryListCctxPendingWithRateLimitRequest: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryListPendingCctxWithinRateLimitRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { - case 2: + case 1: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) } @@ -8451,7 +8452,7 @@ func (m *QueryListCctxPendingWithRateLimitRequest) Unmarshal(dAtA []byte) error } return nil } -func (m *QueryListCctxPendingWithRateLimitResponse) Unmarshal(dAtA []byte) error { +func (m *QueryListPendingCctxWithinRateLimitResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -8474,10 +8475,10 @@ func (m *QueryListCctxPendingWithRateLimitResponse) Unmarshal(dAtA []byte) error fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryListCctxPendingWithRateLimitResponse: wiretype end group for non-group") + return fmt.Errorf("proto: QueryListPendingCctxWithinRateLimitResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryListCctxPendingWithRateLimitResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryListPendingCctxWithinRateLimitResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: diff --git a/x/crosschain/types/query.pb.gw.go b/x/crosschain/types/query.pb.gw.go index c4b3a02e5d..6a4aa48cdd 100644 --- a/x/crosschain/types/query.pb.gw.go +++ b/x/crosschain/types/query.pb.gw.go @@ -870,73 +870,73 @@ func local_request_Query_CctxAll_0(ctx context.Context, marshaler runtime.Marsha } var ( - filter_Query_CctxListPending_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} + filter_Query_ListPendingCctx_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} ) -func request_Query_CctxListPending_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryListCctxPendingRequest +func request_Query_ListPendingCctx_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryListPendingCctxRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_CctxListPending_0); err != nil { + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_ListPendingCctx_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := client.CctxListPending(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + msg, err := client.ListPendingCctx(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } -func local_request_Query_CctxListPending_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryListCctxPendingRequest +func local_request_Query_ListPendingCctx_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryListPendingCctxRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_CctxListPending_0); err != nil { + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_ListPendingCctx_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := server.CctxListPending(ctx, &protoReq) + msg, err := server.ListPendingCctx(ctx, &protoReq) return msg, metadata, err } var ( - filter_Query_CctxListPendingWithinRateLimit_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} + filter_Query_ListPendingCctxWithinRateLimit_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} ) -func request_Query_CctxListPendingWithinRateLimit_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryListCctxPendingWithRateLimitRequest +func request_Query_ListPendingCctxWithinRateLimit_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryListPendingCctxWithinRateLimitRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_CctxListPendingWithinRateLimit_0); err != nil { + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_ListPendingCctxWithinRateLimit_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := client.CctxListPendingWithinRateLimit(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + msg, err := client.ListPendingCctxWithinRateLimit(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } -func local_request_Query_CctxListPendingWithinRateLimit_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryListCctxPendingWithRateLimitRequest +func local_request_Query_ListPendingCctxWithinRateLimit_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryListPendingCctxWithinRateLimitRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_CctxListPendingWithinRateLimit_0); err != nil { + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_ListPendingCctxWithinRateLimit_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := server.CctxListPendingWithinRateLimit(ctx, &protoReq) + msg, err := server.ListPendingCctxWithinRateLimit(ctx, &protoReq) return msg, metadata, err } @@ -1392,7 +1392,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) - mux.Handle("GET", pattern_Query_CctxListPending_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_ListPendingCctx_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -1403,7 +1403,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Query_CctxListPending_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Query_ListPendingCctx_0(rctx, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { @@ -1411,11 +1411,11 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv return } - forward_Query_CctxListPending_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_ListPendingCctx_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle("GET", pattern_Query_CctxListPendingWithinRateLimit_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_ListPendingCctxWithinRateLimit_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -1426,7 +1426,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Query_CctxListPendingWithinRateLimit_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Query_ListPendingCctxWithinRateLimit_0(rctx, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { @@ -1434,7 +1434,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv return } - forward_Query_CctxListPendingWithinRateLimit_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_ListPendingCctxWithinRateLimit_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -1888,7 +1888,7 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) - mux.Handle("GET", pattern_Query_CctxListPending_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_ListPendingCctx_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) @@ -1897,18 +1897,18 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Query_CctxListPending_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Query_ListPendingCctx_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_Query_CctxListPending_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_ListPendingCctx_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) - mux.Handle("GET", pattern_Query_CctxListPendingWithinRateLimit_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_ListPendingCctxWithinRateLimit_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) @@ -1917,14 +1917,14 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Query_CctxListPendingWithinRateLimit_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Query_ListPendingCctxWithinRateLimit_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_Query_CctxListPendingWithinRateLimit_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_ListPendingCctxWithinRateLimit_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -2026,9 +2026,9 @@ var ( pattern_Query_CctxAll_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"zeta-chain", "crosschain", "cctx"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_CctxListPending_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"zeta-chain", "crosschain", "cctxPending"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_ListPendingCctx_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"zeta-chain", "crosschain", "pendingCctx"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_CctxListPendingWithinRateLimit_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"zeta-chain", "crosschain", "cctxPendingWithRateLimit"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_ListPendingCctxWithinRateLimit_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"zeta-chain", "crosschain", "pendingCctxWithinRateLimit"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_ZetaAccounting_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"zeta-chain", "crosschain", "zetaAccounting"}, "", runtime.AssumeColonVerbOpt(false))) @@ -2072,9 +2072,9 @@ var ( forward_Query_CctxAll_0 = runtime.ForwardResponseMessage - forward_Query_CctxListPending_0 = runtime.ForwardResponseMessage + forward_Query_ListPendingCctx_0 = runtime.ForwardResponseMessage - forward_Query_CctxListPendingWithinRateLimit_0 = runtime.ForwardResponseMessage + forward_Query_ListPendingCctxWithinRateLimit_0 = runtime.ForwardResponseMessage forward_Query_ZetaAccounting_0 = runtime.ForwardResponseMessage diff --git a/zetaclient/interfaces/interfaces.go b/zetaclient/interfaces/interfaces.go index 0c803c3497..0fbaba26b3 100644 --- a/zetaclient/interfaces/interfaces.go +++ b/zetaclient/interfaces/interfaces.go @@ -98,7 +98,7 @@ type ZetaCoreBridger interface { GetZetaBlockHeight() (int64, error) GetLastBlockHeightByChain(chain chains.Chain) (*crosschaintypes.LastBlockHeight, error) ListPendingCctx(chainID int64) ([]*crosschaintypes.CrossChainTx, uint64, error) - ListPendingCctxWithRatelimit() ([]*crosschaintypes.CrossChainTx, uint64, bool, error) + ListPendingCctxWithinRatelimit() ([]*crosschaintypes.CrossChainTx, uint64, bool, error) GetPendingNoncesByChain(chainID int64) (observertypes.PendingNonces, error) GetCctxByNonce(chainID int64, nonce uint64) (*crosschaintypes.CrossChainTx, error) GetOutTxTracker(chain chains.Chain, nonce uint64) (*crosschaintypes.OutTxTracker, error) diff --git a/zetaclient/testutils/stub/core_bridge.go b/zetaclient/testutils/stub/core_bridge.go index 51c2afb7ef..e66c309cc6 100644 --- a/zetaclient/testutils/stub/core_bridge.go +++ b/zetaclient/testutils/stub/core_bridge.go @@ -121,7 +121,7 @@ func (z *MockZetaCoreBridge) ListPendingCctx(_ int64) ([]*cctxtypes.CrossChainTx return []*cctxtypes.CrossChainTx{}, 0, nil } -func (z *MockZetaCoreBridge) ListPendingCctxWithRatelimit() ([]*cctxtypes.CrossChainTx, uint64, bool, error) { +func (z *MockZetaCoreBridge) ListPendingCctxWithinRatelimit() ([]*cctxtypes.CrossChainTx, uint64, bool, error) { if z.paused { return nil, 0, false, errors.New(ErrMsgPaused) } diff --git a/zetaclient/zetabridge/query.go b/zetaclient/zetabridge/query.go index fab225c571..09d3b20e82 100644 --- a/zetaclient/zetabridge/query.go +++ b/zetaclient/zetabridge/query.go @@ -125,9 +125,9 @@ func (b *ZetaCoreBridge) GetObserverList() ([]string, error) { func (b *ZetaCoreBridge) ListPendingCctx(chainID int64) ([]*types.CrossChainTx, uint64, error) { client := types.NewQueryClient(b.grpcConn) maxSizeOption := grpc.MaxCallRecvMsgSize(32 * 1024 * 1024) - resp, err := client.CctxListPending( + resp, err := client.ListPendingCctx( context.Background(), - &types.QueryListCctxPendingRequest{ChainId: chainID}, + &types.QueryListPendingCctxRequest{ChainId: chainID}, maxSizeOption, ) if err != nil { @@ -136,15 +136,15 @@ func (b *ZetaCoreBridge) ListPendingCctx(chainID int64) ([]*types.CrossChainTx, return resp.CrossChainTx, resp.TotalPending, nil } -// ListPendingCctxWithRatelimit returns a list of pending cctxs that do not exceed the outbound rate limit +// ListPendingCctxWithinRatelimit returns a list of pending cctxs that do not exceed the outbound rate limit // - The max size of the list is crosschainkeeper.MaxPendingCctxs // - The returned `rateLimitExceeded` flag indicates if the rate limit is exceeded or not -func (b *ZetaCoreBridge) ListPendingCctxWithRatelimit() ([]*types.CrossChainTx, uint64, bool, error) { +func (b *ZetaCoreBridge) ListPendingCctxWithinRatelimit() ([]*types.CrossChainTx, uint64, bool, error) { client := types.NewQueryClient(b.grpcConn) maxSizeOption := grpc.MaxCallRecvMsgSize(32 * 1024 * 1024) - resp, err := client.CctxListPendingWithinRateLimit( + resp, err := client.ListPendingCctxWithinRateLimit( context.Background(), - &types.QueryListCctxPendingWithRateLimitRequest{}, + &types.QueryListPendingCctxWithinRateLimitRequest{}, maxSizeOption, ) if err != nil { diff --git a/zetaclient/zetacore_observer.go b/zetaclient/zetacore_observer.go index a40b7f22b8..c66f15f50a 100644 --- a/zetaclient/zetacore_observer.go +++ b/zetaclient/zetacore_observer.go @@ -191,7 +191,7 @@ func (co *CoreObserver) startCctxScheduler(appContext *appcontext.AppContext) { // getAllPendingCctxWithRatelimit get pending cctxs across all foreign chains with rate limit func (co *CoreObserver) getAllPendingCctxWithRatelimit() (map[int64][]*types.CrossChainTx, error) { - cctxList, totalPending, rateLimitExceeded, err := co.bridge.ListPendingCctxWithRatelimit() + cctxList, totalPending, rateLimitExceeded, err := co.bridge.ListPendingCctxWithinRatelimit() if err != nil { return nil, err } From 0eb3b8a2e7fb864f0ceb09e1b2a90c5e7ddeec7b Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Fri, 19 Apr 2024 15:23:45 -0500 Subject: [PATCH 11/33] fixed unit test compile --- zetaclient/zetabridge/query_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zetaclient/zetabridge/query_test.go b/zetaclient/zetabridge/query_test.go index 3844482dd3..ea76fa78fd 100644 --- a/zetaclient/zetabridge/query_test.go +++ b/zetaclient/zetabridge/query_test.go @@ -267,7 +267,7 @@ func TestZetaCoreBridge_GetObserverList(t *testing.T) { } func TestZetaCoreBridge_ListPendingCctx(t *testing.T) { - expectedOutput := crosschainTypes.QueryListCctxPendingResponse{ + expectedOutput := crosschainTypes.QueryListPendingCctxResponse{ CrossChainTx: []*crosschainTypes.CrossChainTx{ { Index: "cross-chain4456", @@ -275,8 +275,8 @@ func TestZetaCoreBridge_ListPendingCctx(t *testing.T) { }, TotalPending: 1, } - input := crosschainTypes.QueryListCctxPendingRequest{ChainId: 7000} - method := "/zetachain.zetacore.crosschain.Query/CctxListPending" + input := crosschainTypes.QueryListPendingCctxRequest{ChainId: 7000} + method := "/zetachain.zetacore.crosschain.Query/ListPendingCctx" server := setupMockServer(t, crosschainTypes.RegisterQueryServer, method, input, expectedOutput) server.Serve() defer closeMockServer(t, server) From 60e5dcc5408777b9e0e746b9999316954003a444 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Fri, 19 Apr 2024 19:45:12 -0500 Subject: [PATCH 12/33] added unit test for fallback query --- testutil/sample/fungible.go | 30 ++++ x/crosschain/keeper/cctx_utils_test.go | 8 +- x/crosschain/keeper/evm_deposit_test.go | 22 +-- x/crosschain/keeper/gas_payment_test.go | 28 +-- .../keeper/grpc_query_cctx_rate_limit_test.go | 168 +++++++++++++++++- x/crosschain/keeper/grpc_query_cctx_test.go | 14 +- .../msg_server_add_to_intx_tracker_test.go | 16 +- .../msg_server_migrate_tss_funds_test.go | 28 +-- .../msg_server_refund_aborted_tx_test.go | 26 +-- .../keeper/msg_server_vote_inbound_tx_test.go | 4 +- .../msg_server_vote_outbound_tx_test.go | 12 +- .../keeper/msg_server_whitelist_erc20_test.go | 10 +- x/crosschain/keeper/process_inbound_test.go | 20 +-- x/crosschain/keeper/process_outbound_test.go | 16 +- x/crosschain/keeper/refund_test.go | 32 ++-- x/crosschain/keeper/utils_test.go | 6 +- 16 files changed, 318 insertions(+), 122 deletions(-) diff --git a/testutil/sample/fungible.go b/testutil/sample/fungible.go index 73fdc2b2e3..3be91d06a3 100644 --- a/testutil/sample/fungible.go +++ b/testutil/sample/fungible.go @@ -3,6 +3,7 @@ package sample import ( "testing" + "github.com/zeta-chain/zetacore/pkg/chains" "github.com/zeta-chain/zetacore/pkg/coin" "github.com/zeta-chain/zetacore/x/fungible/types" ) @@ -22,6 +23,35 @@ func ForeignCoins(t *testing.T, address string) types.ForeignCoins { } } +func ForeignCoinList(t *testing.T, zrc20ETH, zrc20BTC, zrc20ERC20, erc20Asset string) []types.ForeignCoins { + // eth and btc chain id + ethChainID := chains.GoerliLocalnetChain().ChainId + btcChainID := chains.BtcRegtestChain().ChainId + + // add zrc20 ETH + fcGas := ForeignCoins(t, zrc20ETH) + fcGas.Asset = "" + fcGas.ForeignChainId = ethChainID + fcGas.Decimals = 18 + fcGas.CoinType = coin.CoinType_Gas + + // add zrc20 BTC + fcBTC := ForeignCoins(t, zrc20BTC) + fcBTC.Asset = "" + fcBTC.ForeignChainId = btcChainID + fcBTC.Decimals = 8 + fcBTC.CoinType = coin.CoinType_Gas + + // add zrc20 ERC20 + fcERC20 := ForeignCoins(t, zrc20ERC20) + fcERC20.Asset = erc20Asset + fcERC20.ForeignChainId = ethChainID + fcERC20.Decimals = 6 + fcERC20.CoinType = coin.CoinType_ERC20 + + return []types.ForeignCoins{fcGas, fcBTC, fcERC20} +} + func SystemContract() *types.SystemContract { return &types.SystemContract{ SystemContract: EthAddress().String(), diff --git a/x/crosschain/keeper/cctx_utils_test.go b/x/crosschain/keeper/cctx_utils_test.go index e0dedbb41d..af6445744c 100644 --- a/x/crosschain/keeper/cctx_utils_test.go +++ b/x/crosschain/keeper/cctx_utils_test.go @@ -42,7 +42,7 @@ func TestGetRevertGasLimit(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) gas := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foo", "FOO") @@ -63,7 +63,7 @@ func TestGetRevertGasLimit(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) asset := sample.EthAddress().String() zrc20Addr := deployZRC20( @@ -107,7 +107,7 @@ func TestGetRevertGasLimit(t *testing.T) { k, ctx, _, zk := keepertest.CrosschainKeeper(t) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() zk.FungibleKeeper.SetForeignCoins(ctx, fungibletypes.ForeignCoins{ Zrc20ContractAddress: sample.EthAddress().String(), @@ -141,7 +141,7 @@ func TestGetRevertGasLimit(t *testing.T) { k, ctx, _, zk := keepertest.CrosschainKeeper(t) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() asset := sample.EthAddress().String() zk.FungibleKeeper.SetForeignCoins(ctx, fungibletypes.ForeignCoins{ diff --git a/x/crosschain/keeper/evm_deposit_test.go b/x/crosschain/keeper/evm_deposit_test.go index 1f6cd4fad4..d30424697c 100644 --- a/x/crosschain/keeper/evm_deposit_test.go +++ b/x/crosschain/keeper/evm_deposit_test.go @@ -84,7 +84,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { UseFungibleMock: true, }) - senderChain := getValidEthChainID(t) + senderChain := getValidEthChainID() fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() @@ -127,7 +127,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { UseFungibleMock: true, }) - senderChain := getValidEthChainID(t) + senderChain := getValidEthChainID() fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() @@ -186,7 +186,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { UseFungibleMock: true, }) - senderChain := getValidEthChainID(t) + senderChain := getValidEthChainID() fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() @@ -273,7 +273,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { UseFungibleMock: true, }) - senderChain := getValidEthChainID(t) + senderChain := getValidEthChainID() fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() @@ -317,7 +317,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { UseFungibleMock: true, }) - senderChain := getValidEthChainID(t) + senderChain := getValidEthChainID() fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() @@ -361,7 +361,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { UseFungibleMock: true, }) - senderChain := getValidEthChainID(t) + senderChain := getValidEthChainID() fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() @@ -404,7 +404,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { UseFungibleMock: true, }) - senderChain := getValidEthChainID(t) + senderChain := getValidEthChainID() fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() @@ -447,7 +447,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { UseFungibleMock: true, }) - senderChain := getValidEthChainID(t) + senderChain := getValidEthChainID() fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() @@ -487,7 +487,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ UseFungibleMock: true, }) - senderChain := getValidEthChainID(t) + senderChain := getValidEthChainID() cctx := sample.CrossChainTx(t, "foo") cctx.GetCurrentOutTxParam().Receiver = sample.EthAddress().String() @@ -509,7 +509,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { UseFungibleMock: true, }) - senderChain := getValidEthChainID(t) + senderChain := getValidEthChainID() fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() @@ -555,7 +555,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { UseFungibleMock: true, }) - senderChain := getValidEthChainID(t) + senderChain := getValidEthChainID() fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() diff --git a/x/crosschain/keeper/gas_payment_test.go b/x/crosschain/keeper/gas_payment_test.go index 569a360327..8079c3c67a 100644 --- a/x/crosschain/keeper/gas_payment_test.go +++ b/x/crosschain/keeper/gas_payment_test.go @@ -30,7 +30,7 @@ func TestKeeper_PayGasNativeAndUpdateCctx(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) // deploy gas coin and set fee params - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() setSupportedChain(ctx, zk, chainID) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) @@ -72,7 +72,7 @@ func TestKeeper_PayGasNativeAndUpdateCctx(t *testing.T) { t.Run("should fail if not coin type gas", func(t *testing.T) { k, ctx, _, _ := testkeeper.CrosschainKeeper(t) - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() cctx := types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: coin.CoinType_Zeta, @@ -98,7 +98,7 @@ func TestKeeper_PayGasNativeAndUpdateCctx(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) // deploy gas coin and set fee params - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() setSupportedChain(ctx, zk, chainID) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "foobar") @@ -127,7 +127,7 @@ func TestKeeper_PayGasNativeAndUpdateCctx(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) // deploy gas coin and set fee params - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() setSupportedChain(ctx, zk, chainID) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "foobar") @@ -170,7 +170,7 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) // deploy gas coin, erc20 and set fee params - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() setSupportedChain(ctx, zk, chainID) assetAddress := sample.EthAddress().String() deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) @@ -236,7 +236,7 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { t.Run("should fail if not coin type erc20", func(t *testing.T) { k, ctx, _, _ := testkeeper.CrosschainKeeper(t) - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() cctx := types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: coin.CoinType_Gas, @@ -262,7 +262,7 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) // deploy gas coin and set fee params - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() setSupportedChain(ctx, zk, chainID) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "foobar") @@ -291,7 +291,7 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) // deploy gas coin, erc20 and set fee params - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() setSupportedChain(ctx, zk, chainID) assetAddress := sample.EthAddress().String() deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) @@ -333,7 +333,7 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) // deploy gas coin, erc20 and set fee params - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() setSupportedChain(ctx, zk, chainID) assetAddress := sample.EthAddress().String() deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) @@ -385,7 +385,7 @@ func TestKeeper_PayGasInERC20AndUpdateCctx(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) // deploy gas coin, erc20 and set fee params - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() setSupportedChain(ctx, zk, chainID) assetAddress := sample.EthAddress().String() deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) @@ -453,7 +453,7 @@ func TestKeeper_PayGasInZetaAndUpdateCctx(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) // deploy gas coin and set fee params - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() setSupportedChain(ctx, zk, chainID) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "foobar") @@ -514,7 +514,7 @@ func TestKeeper_PayGasInZetaAndUpdateCctx(t *testing.T) { t.Run("should fail if pay gas in zeta with coin type other than zeta", func(t *testing.T) { k, ctx, _, _ := testkeeper.CrosschainKeeper(t) - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() cctx := types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: coin.CoinType_Gas, @@ -540,7 +540,7 @@ func TestKeeper_PayGasInZetaAndUpdateCctx(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) // deploy gas coin and set fee params - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() setSupportedChain(ctx, zk, chainID) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "foobar") @@ -571,7 +571,7 @@ func TestKeeper_PayGasInZetaAndUpdateCctx(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) // deploy gas coin and set fee params - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() setSupportedChain(ctx, zk, chainID) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "foobar") diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go index 5c2eee4066..31939862b5 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go @@ -1,16 +1,182 @@ package keeper_test import ( + "fmt" + "sort" "testing" + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/pkg/coin" 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" ) -func TestKeeper_CctxListPendingWithRateLimit(t *testing.T) { +// createTestRateLimiterFlags creates a custom rate limiter flags +func createTestRateLimiterFlags( + zrc20ETH string, + zrc20BTC string, + zrc20USDT string, + ethRate string, + btcRate string, + usdtRate string, +) types.RateLimiterFlags { + var rateLimiterFlags = types.RateLimiterFlags{ + Enabled: true, + Window: 100, // 100 zeta blocks, 10 minutes + Rate: math.NewUint(1000), // 1000 ZETA + Conversions: []types.Conversion{ + // ETH + { + Zrc20: zrc20ETH, + Rate: sdk.MustNewDecFromStr(ethRate), + }, + // BTC + { + Zrc20: zrc20BTC, + Rate: sdk.MustNewDecFromStr(btcRate), + }, + // USDT + { + Zrc20: zrc20USDT, + Rate: sdk.MustNewDecFromStr(usdtRate), + }, + }, + } + return rateLimiterFlags +} + +// createCctxWithCopyTypeAndBlockRange +// - create 1 cctx per block from lowBlock to highBlock (inclusive) +// +// return created cctxs +func createCctxWithCopyTypeAndHeightRange( + t *testing.T, + ctx sdk.Context, + k keeper.Keeper, + zk keepertest.ZetaKeepers, + tss observertypes.TSS, + lowBlock uint64, + highBlock uint64, + chainID int64, + coinType coin.CoinType, + asset string, + amount uint64, + status types.CctxStatus, +) (cctxs []*types.CrossChainTx) { + // create 1 pending cctxs per block + for i := lowBlock; i <= highBlock; i++ { + nonce := i - 1 + cctx := sample.CrossChainTx(t, fmt.Sprintf("%d-%d", chainID, nonce)) + cctx.CctxStatus.Status = status + cctx.InboundTxParams.SenderChainId = chainID + cctx.InboundTxParams.CoinType = coinType + cctx.InboundTxParams.Asset = asset + cctx.InboundTxParams.InboundTxObservedExternalHeight = i + cctx.GetCurrentOutTxParam().Amount = sdk.NewUint(amount) + cctx.GetCurrentOutTxParam().OutboundTxTssNonce = nonce + k.SetCrossChainTx(ctx, *cctx) + zk.ObserverKeeper.SetNonceToCctx(ctx, observertypes.NonceToCctx{ + ChainId: chainID, + // #nosec G701 always in range for tests + Nonce: int64(nonce), + CctxIndex: cctx.Index, + Tss: tss.TssPubkey, + }) + cctxs = append(cctxs, cctx) + } + return cctxs +} + +// setPendingNonces sets the pending nonces for the given chainID +func setPendingNonces( + ctx sdk.Context, + zk keepertest.ZetaKeepers, + chainID int64, + nonceLow int64, + nonceHigh int64, + tssPubKey string, +) { + zk.ObserverKeeper.SetPendingNonces(ctx, observertypes.PendingNonces{ + ChainId: chainID, + NonceLow: nonceLow, + NonceHigh: nonceHigh, + Tss: tssPubKey, + }) +} + +// setupForeignCoins adds ETH, BTC, USDT to the foreign coins store +func setupForeignCoins( + t *testing.T, + ctx sdk.Context, + zk keepertest.ZetaKeepers, + zrc20ETH, zrc20BTC, zrc20USDT, assetUSDT string, +) { + // set foreign coins + fCoins := sample.ForeignCoinList(t, zrc20ETH, zrc20BTC, zrc20USDT, assetUSDT) + for _, fc := range fCoins { + zk.FungibleKeeper.SetForeignCoins(ctx, fc) + } +} + +func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { + // chain IDs + ethChainID := getValidEthChainID() + + // define cctx status + statusPending := types.CctxStatus_PendingOutbound + statusMined := types.CctxStatus_OutboundMined + t.Run("should fail for empty req", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) _, err := k.ListPendingCctxWithinRateLimit(ctx, nil) require.ErrorContains(t, err, "invalid request") }) + t.Run("should use fallback query", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + + // Set TSS + tss := sample.Tss() + zk.ObserverKeeper.SetTSS(ctx, tss) + + // Set rate limiter flags as disabled + rateLimiterFlags := sample.RateLimiterFlags() + rateLimiterFlags.Enabled = false + k.SetRateLimiterFlags(ctx, rateLimiterFlags) + + // Create cctxs [0~999] and [1000~1199] for Eth chain, 0.001 ETH per cctx + _ = createCctxWithCopyTypeAndHeightRange(t, ctx, *k, zk, tss, 1, 1000, ethChainID, coin.CoinType_Gas, "", uint64(1e15), statusMined) + cctxETH := createCctxWithCopyTypeAndHeightRange(t, ctx, *k, zk, tss, 1001, 1200, ethChainID, coin.CoinType_Gas, "", uint64(1e15), statusPending) + + // Set Eth chain pending nonces which contains 100 missing cctxs + setPendingNonces(ctx, zk, ethChainID, 1100, 1200, tss.TssPubkey) + + // Query pending cctxs use small limit + res, err := k.ListPendingCctxWithinRateLimit(ctx, &types.QueryListPendingCctxWithinRateLimitRequest{Limit: 100}) + require.NoError(t, err) + require.Equal(t, 100, len(res.CrossChainTx)) + + // sort res.CrossChainTx by outbound nonce ascending so that we can compare with cctxETH + sort.Slice(res.CrossChainTx, func(i, j int) bool { + return res.CrossChainTx[i].GetCurrentOutTxParam().OutboundTxTssNonce < res.CrossChainTx[j].GetCurrentOutTxParam().OutboundTxTssNonce + }) + require.EqualValues(t, cctxETH[:100], res.CrossChainTx) + require.EqualValues(t, uint64(200), res.TotalPending) + + // Query pending cctxs use max limit + res, err = k.ListPendingCctxWithinRateLimit(ctx, &types.QueryListPendingCctxWithinRateLimitRequest{Limit: keeper.MaxPendingCctxs}) + require.NoError(t, err) + require.Equal(t, 200, len(res.CrossChainTx)) + + // sort res.CrossChainTx by outbound nonce ascending so that we can compare with cctxETH + sort.Slice(res.CrossChainTx, func(i, j int) bool { + return res.CrossChainTx[i].GetCurrentOutTxParam().OutboundTxTssNonce < res.CrossChainTx[j].GetCurrentOutTxParam().OutboundTxTssNonce + }) + require.EqualValues(t, cctxETH, res.CrossChainTx) + require.EqualValues(t, uint64(200), res.TotalPending) + }) } diff --git a/x/crosschain/keeper/grpc_query_cctx_test.go b/x/crosschain/keeper/grpc_query_cctx_test.go index 240d0bfe92..f530ef305b 100644 --- a/x/crosschain/keeper/grpc_query_cctx_test.go +++ b/x/crosschain/keeper/grpc_query_cctx_test.go @@ -94,7 +94,7 @@ func TestKeeper_CctxListPending(t *testing.T) { t.Run("can retrieve pending cctx in range", func(t *testing.T) { k, ctx, _, zk := keepertest.CrosschainKeeper(t) - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() tss := sample.Tss() zk.ObserverKeeper.SetTSS(ctx, tss) cctxs := createCctxWithNonceRange(t, ctx, *k, 1000, 2000, chainID, tss, zk) @@ -114,7 +114,7 @@ func TestKeeper_CctxListPending(t *testing.T) { t.Run("can retrieve pending cctx with range smaller than max", func(t *testing.T) { k, ctx, _, zk := keepertest.CrosschainKeeper(t) - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() tss := sample.Tss() zk.ObserverKeeper.SetTSS(ctx, tss) cctxs := createCctxWithNonceRange(t, ctx, *k, 1000, 1100, chainID, tss, zk) @@ -128,7 +128,7 @@ func TestKeeper_CctxListPending(t *testing.T) { t.Run("can retrieve pending cctx with pending cctx below nonce low", func(t *testing.T) { k, ctx, _, zk := keepertest.CrosschainKeeper(t) - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() tss := sample.Tss() zk.ObserverKeeper.SetTSS(ctx, tss) cctxs := createCctxWithNonceRange(t, ctx, *k, 1000, 2000, chainID, tss, zk) @@ -157,7 +157,7 @@ func TestKeeper_CctxListPending(t *testing.T) { t.Run("error if some before low nonce are missing", func(t *testing.T) { k, ctx, _, zk := keepertest.CrosschainKeeper(t) - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() tss := sample.Tss() zk.ObserverKeeper.SetTSS(ctx, tss) cctxs := createCctxWithNonceRange(t, ctx, *k, 1000, 2000, chainID, tss, zk) @@ -226,7 +226,7 @@ func TestKeeper_CctxByNonce(t *testing.T) { t.Run("should error if nonce to cctx not found", func(t *testing.T) { k, ctx, _, zk := keepertest.CrosschainKeeper(t) - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() tss := sample.Tss() zk.ObserverKeeper.SetTSS(ctx, tss) @@ -239,7 +239,7 @@ func TestKeeper_CctxByNonce(t *testing.T) { t.Run("should error if crosschain tx not found", func(t *testing.T) { k, ctx, _, zk := keepertest.CrosschainKeeper(t) - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() tss := sample.Tss() zk.ObserverKeeper.SetTSS(ctx, tss) nonce := 1000 @@ -262,7 +262,7 @@ func TestKeeper_CctxByNonce(t *testing.T) { t.Run("should return if crosschain tx found", func(t *testing.T) { k, ctx, _, zk := keepertest.CrosschainKeeper(t) - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() tss := sample.Tss() zk.ObserverKeeper.SetTSS(ctx, tss) nonce := 1000 diff --git a/x/crosschain/keeper/msg_server_add_to_intx_tracker_test.go b/x/crosschain/keeper/msg_server_add_to_intx_tracker_test.go index a18d7e737a..9c0547e9fb 100644 --- a/x/crosschain/keeper/msg_server_add_to_intx_tracker_test.go +++ b/x/crosschain/keeper/msg_server_add_to_intx_tracker_test.go @@ -36,7 +36,7 @@ func TestMsgServer_AddToInTxTracker(t *testing.T) { observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) txHash := "string" - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() _, err := msgServer.AddToInTxTracker(ctx, &types.MsgAddToInTxTracker{ Creator: nonAdmin, @@ -63,7 +63,7 @@ func TestMsgServer_AddToInTxTracker(t *testing.T) { observerMock.On("GetSupportedChainFromChainID", mock.Anything, mock.Anything).Return(nil) txHash := "string" - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() _, err := msgServer.AddToInTxTracker(ctx, &types.MsgAddToInTxTracker{ Creator: sample.AccAddress(), @@ -95,7 +95,7 @@ func TestMsgServer_AddToInTxTracker(t *testing.T) { observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(false) txHash := "string" - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() setSupportedChain(ctx, zk, chainID) _, err := msgServer.AddToInTxTracker(ctx, &types.MsgAddToInTxTracker{ @@ -128,7 +128,7 @@ func TestMsgServer_AddToInTxTracker(t *testing.T) { observerMock.On("IsNonTombstonedObserver", mock.Anything, mock.Anything).Return(true) txHash := "string" - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() _, err := msgServer.AddToInTxTracker(ctx, &types.MsgAddToInTxTracker{ Creator: admin, @@ -163,7 +163,7 @@ func TestMsgServer_AddToInTxTracker(t *testing.T) { lightclientMock.On("VerifyProof", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("error")) txHash := "string" - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() _, err := msgServer.AddToInTxTracker(ctx, &types.MsgAddToInTxTracker{ Creator: admin, @@ -197,7 +197,7 @@ func TestMsgServer_AddToInTxTracker(t *testing.T) { observerMock.On("GetChainParamsByChainID", mock.Anything, mock.Anything).Return(nil, false) txHash := "string" - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() _, err := msgServer.AddToInTxTracker(ctx, &types.MsgAddToInTxTracker{ Creator: admin, @@ -232,7 +232,7 @@ func TestMsgServer_AddToInTxTracker(t *testing.T) { observerMock.On("GetTssAddress", mock.Anything, mock.Anything).Return(nil, errors.New("error")) txHash := "string" - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() setSupportedChain(ctx, zk, chainID) _, err := msgServer.AddToInTxTracker(ctx, &types.MsgAddToInTxTracker{ @@ -272,7 +272,7 @@ func TestMsgServer_AddToInTxTracker(t *testing.T) { lightclientMock.On("VerifyProof", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]byte("invalid"), nil) txHash := "string" - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() setSupportedChain(ctx, zk, chainID) _, err := msgServer.AddToInTxTracker(ctx, &types.MsgAddToInTxTracker{ diff --git a/x/crosschain/keeper/msg_server_migrate_tss_funds_test.go b/x/crosschain/keeper/msg_server_migrate_tss_funds_test.go index f13a0065ae..5865c6ccca 100644 --- a/x/crosschain/keeper/msg_server_migrate_tss_funds_test.go +++ b/x/crosschain/keeper/msg_server_migrate_tss_funds_test.go @@ -89,7 +89,7 @@ func TestKeeper_MigrateTSSFundsForChain(t *testing.T) { keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupAdmin, true) msgServer := keeper.NewMsgServerImpl(*k) - chain := getValidEthChain(t) + chain := getValidEthChain() amount := sdkmath.NewUintFromString("10000000000000000000") indexString, _ := setupTssMigrationParams(zk, k, ctx, *chain, amount, true, true) gp, found := k.GetMedianGasPriceInUint(ctx, chain.ChainId) @@ -149,7 +149,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupAdmin, false) msgServer := keeper.NewMsgServerImpl(*k) - chain := getValidEthChain(t) + chain := getValidEthChain() amount := sdkmath.NewUintFromString("10000000000000000000") _, err := msgServer.MigrateTssFunds(ctx, &crosschaintypes.MsgMigrateTssFunds{ Creator: admin, @@ -172,7 +172,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) observerMock.On("IsInboundEnabled", mock.Anything).Return(true) msgServer := keeper.NewMsgServerImpl(*k) - chain := getValidEthChain(t) + chain := getValidEthChain() amount := sdkmath.NewUintFromString("10000000000000000000") _, err := msgServer.MigrateTssFunds(ctx, &crosschaintypes.MsgMigrateTssFunds{ Creator: admin, @@ -197,7 +197,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { observerMock.On("GetTSS", mock.Anything).Return(observertypes.TSS{}, false) msgServer := keeper.NewMsgServerImpl(*k) - chain := getValidEthChain(t) + chain := getValidEthChain() amount := sdkmath.NewUintFromString("10000000000000000000") _, err := msgServer.MigrateTssFunds(ctx, &crosschaintypes.MsgMigrateTssFunds{ Creator: admin, @@ -223,7 +223,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { observerMock.On("GetAllTSS", mock.Anything).Return([]observertypes.TSS{}) msgServer := keeper.NewMsgServerImpl(*k) - chain := getValidEthChain(t) + chain := getValidEthChain() amount := sdkmath.NewUintFromString("10000000000000000000") _, err := msgServer.MigrateTssFunds(ctx, &crosschaintypes.MsgMigrateTssFunds{ Creator: admin, @@ -250,7 +250,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { observerMock.On("GetAllTSS", mock.Anything).Return([]observertypes.TSS{tss}) msgServer := keeper.NewMsgServerImpl(*k) - chain := getValidEthChain(t) + chain := getValidEthChain() amount := sdkmath.NewUintFromString("10000000000000000000") _, err := msgServer.MigrateTssFunds(ctx, &crosschaintypes.MsgMigrateTssFunds{ Creator: admin, @@ -280,7 +280,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { observerMock.On("GetAllTSS", mock.Anything).Return([]observertypes.TSS{tss2}) msgServer := keeper.NewMsgServerImpl(*k) - chain := getValidEthChain(t) + chain := getValidEthChain() amount := sdkmath.NewUintFromString("10000000000000000000") _, err := msgServer.MigrateTssFunds(ctx, &crosschaintypes.MsgMigrateTssFunds{ Creator: admin, @@ -311,7 +311,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { observerMock.On("GetPendingNonces", mock.Anything, mock.Anything, mock.Anything).Return(observertypes.PendingNonces{}, false) msgServer := keeper.NewMsgServerImpl(*k) - chain := getValidEthChain(t) + chain := getValidEthChain() amount := sdkmath.NewUintFromString("10000000000000000000") _, err := msgServer.MigrateTssFunds(ctx, &crosschaintypes.MsgMigrateTssFunds{ Creator: admin, @@ -331,7 +331,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupAdmin, true) msgServer := keeper.NewMsgServerImpl(*k) - chain := getValidEthChain(t) + chain := getValidEthChain() amount := sdkmath.NewUintFromString("10000000000000000000") indexString, _ := setupTssMigrationParams(zk, k, ctx, *chain, amount, true, true) _, err := msgServer.MigrateTssFunds(ctx, &crosschaintypes.MsgMigrateTssFunds{ @@ -359,7 +359,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupAdmin, true) msgServer := keeper.NewMsgServerImpl(*k) - chain := getValidEthChain(t) + chain := getValidEthChain() amount := sdkmath.NewUintFromString("100") indexString, _ := setupTssMigrationParams(zk, k, ctx, *chain, amount, true, true) _, err := msgServer.MigrateTssFunds(ctx, &crosschaintypes.MsgMigrateTssFunds{ @@ -384,7 +384,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupAdmin, true) msgServer := keeper.NewMsgServerImpl(*k) - chain := getValidEthChain(t) + chain := getValidEthChain() amount := sdkmath.NewUintFromString("10000000000000000000") indexString, _ := setupTssMigrationParams(zk, k, ctx, *chain, amount, false, true) _, err := msgServer.MigrateTssFunds(ctx, &crosschaintypes.MsgMigrateTssFunds{ @@ -409,7 +409,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupAdmin, true) msgServer := keeper.NewMsgServerImpl(*k) - chain := getValidEthChain(t) + chain := getValidEthChain() amount := sdkmath.NewUintFromString("10000000000000000000") indexString, tssPubkey := setupTssMigrationParams(zk, k, ctx, *chain, amount, true, true) k.GetObserverKeeper().SetPendingNonces(ctx, observertypes.PendingNonces{ @@ -441,7 +441,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupAdmin, true) msgServer := keeper.NewMsgServerImpl(*k) - chain := getValidEthChain(t) + chain := getValidEthChain() amount := sdkmath.NewUintFromString("10000000000000000000") indexString, tssPubkey := setupTssMigrationParams(zk, k, ctx, *chain, amount, true, true) k.GetObserverKeeper().SetPendingNonces(ctx, observertypes.PendingNonces{ @@ -482,7 +482,7 @@ func TestMsgServer_MigrateTssFunds(t *testing.T) { keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupAdmin, true) msgServer := keeper.NewMsgServerImpl(*k) - chain := getValidEthChain(t) + chain := getValidEthChain() amount := sdkmath.NewUintFromString("10000000000000000000") indexString, _ := setupTssMigrationParams(zk, k, ctx, *chain, amount, false, false) currentTss, found := k.GetObserverKeeper().GetTSS(ctx) diff --git a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go index f5615c8963..0b54a93c69 100644 --- a/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go +++ b/x/crosschain/keeper/msg_server_refund_aborted_tx_test.go @@ -42,7 +42,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) admin := sample.AccAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupOperational, true) @@ -81,7 +81,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) admin := sample.AccAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupOperational, true) @@ -120,7 +120,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) admin := sample.AccAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupOperational, true) @@ -160,7 +160,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) admin := sample.AccAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupOperational, true) @@ -192,7 +192,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) admin := sample.AccAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupOperational, true) @@ -224,7 +224,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) admin := sample.AccAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupOperational, true) @@ -263,7 +263,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) admin := sample.AccAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() asset := sample.EthAddress().String() authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupOperational, true) @@ -352,7 +352,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) admin := sample.AccAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupOperational, true) @@ -383,7 +383,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) admin := sample.AccAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupOperational, true) @@ -414,7 +414,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) admin := sample.AccAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupOperational, true) @@ -447,7 +447,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) admin := sample.AccAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupOperational, true) @@ -507,7 +507,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) admin := sample.AccAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupOperational, true) @@ -537,7 +537,7 @@ func TestMsgServer_RefundAbortedCCTX(t *testing.T) { }) admin := sample.AccAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupOperational, false) 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 f8d6a4bcb8..379f24741b 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go @@ -312,7 +312,7 @@ func TestKeeper_SaveInbound(t *testing.T) { zk.ObserverKeeper.SetTSS(ctx, sample.Tss()) receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() cctx := GetERC20Cctx(t, receiver, *senderChain, "", amount) eventIndex := sample.Uint64InRange(1, 100) k.SaveInbound(ctx, cctx, eventIndex) @@ -326,7 +326,7 @@ func TestKeeper_SaveInbound(t *testing.T) { k, ctx, _, zk := keepertest.CrosschainKeeper(t) receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() cctx := GetERC20Cctx(t, receiver, *senderChain, "", amount) hash := sample.Hash() cctx.InboundTxParams.InboundTxObservedHash = hash.String() diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go b/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go index fa9884f25a..11ea50a514 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx_test.go @@ -129,7 +129,7 @@ func TestKeeper_VoteOnObservedOutboundTx(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() asset := "" observer := sample.AccAddress() tss := sample.Tss() @@ -180,7 +180,7 @@ func TestKeeper_VoteOnObservedOutboundTx(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() asset := "" observer := sample.AccAddress() tss := sample.Tss() @@ -239,7 +239,7 @@ func TestKeeper_VoteOnObservedOutboundTx(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() asset := "" observer := sample.AccAddress() tss := sample.Tss() @@ -302,7 +302,7 @@ func TestKeeper_VoteOnObservedOutboundTx(t *testing.T) { fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() asset := "" observer := sample.AccAddress() tss := sample.Tss() @@ -354,7 +354,7 @@ func TestKeeper_VoteOnObservedOutboundTx(t *testing.T) { // Setup mock data receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() asset := "" r := rand.New(rand.NewSource(42)) validator := sample.Validator(t, r) @@ -401,7 +401,7 @@ func TestKeeper_VoteOnObservedOutboundTx(t *testing.T) { // Setup mock data receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() asset := "" r := rand.New(rand.NewSource(42)) validator := sample.Validator(t, r) diff --git a/x/crosschain/keeper/msg_server_whitelist_erc20_test.go b/x/crosschain/keeper/msg_server_whitelist_erc20_test.go index 2d193e8f5b..6db8243405 100644 --- a/x/crosschain/keeper/msg_server_whitelist_erc20_test.go +++ b/x/crosschain/keeper/msg_server_whitelist_erc20_test.go @@ -26,7 +26,7 @@ func TestKeeper_WhitelistERC20(t *testing.T) { msgServer := crosschainkeeper.NewMsgServerImpl(*k) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() setSupportedChain(ctx, zk, chainID) admin := sample.AccAddress() @@ -104,7 +104,7 @@ func TestKeeper_WhitelistERC20(t *testing.T) { _, err := msgServer.WhitelistERC20(ctx, &types.MsgWhitelistERC20{ Creator: admin, Erc20Address: sample.EthAddress().Hex(), - ChainId: getValidEthChainID(t), + ChainId: getValidEthChainID(), Name: "foo", Symbol: "FOO", Decimals: 18, @@ -128,7 +128,7 @@ func TestKeeper_WhitelistERC20(t *testing.T) { _, err := msgServer.WhitelistERC20(ctx, &types.MsgWhitelistERC20{ Creator: admin, Erc20Address: "invalid", - ChainId: getValidEthChainID(t), + ChainId: getValidEthChainID(), Name: "foo", Symbol: "FOO", Decimals: 18, @@ -149,7 +149,7 @@ func TestKeeper_WhitelistERC20(t *testing.T) { authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupOperational, true) - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() asset := sample.EthAddress().Hex() fc := sample.ForeignCoins(t, sample.EthAddress().Hex()) fc.Asset = asset @@ -176,7 +176,7 @@ func TestKeeper_WhitelistERC20(t *testing.T) { msgServer := crosschainkeeper.NewMsgServerImpl(*k) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() admin := sample.AccAddress() authorityMock := keepertest.GetCrosschainAuthorityMock(t, k) keepertest.MockIsAuthorized(&authorityMock.Mock, admin, authoritytypes.PolicyType_groupOperational, true) diff --git a/x/crosschain/keeper/process_inbound_test.go b/x/crosschain/keeper/process_inbound_test.go index ec3bcaea94..3e86cd68c5 100644 --- a/x/crosschain/keeper/process_inbound_test.go +++ b/x/crosschain/keeper/process_inbound_test.go @@ -83,7 +83,7 @@ func TestKeeper_ProcessInboundZEVMDeposit(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() errDeposit := fmt.Errorf("deposit failed") // Setup expected calls @@ -113,7 +113,7 @@ func TestKeeper_ProcessInboundZEVMDeposit(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() asset := "" errDeposit := fmt.Errorf("deposit failed") @@ -145,7 +145,7 @@ func TestKeeper_ProcessInboundZEVMDeposit(t *testing.T) { fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() asset := "" // Setup expected calls @@ -182,7 +182,7 @@ func TestKeeper_ProcessInboundZEVMDeposit(t *testing.T) { fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() asset := "" // Setup expected calls @@ -220,7 +220,7 @@ func TestKeeper_ProcessInboundZEVMDeposit(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() asset := "" errDeposit := fmt.Errorf("deposit failed") @@ -260,7 +260,7 @@ func TestKeeper_ProcessInboundZEVMDeposit(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() asset := "" errDeposit := fmt.Errorf("deposit failed") @@ -299,7 +299,7 @@ func TestKeeper_ProcessInboundZEVMDeposit(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() asset := "" errDeposit := fmt.Errorf("deposit failed") @@ -335,7 +335,7 @@ func TestKeeper_ProcessInboundProcessCrosschainMsgPassing(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - receiverChain := getValidEthChain(t) + receiverChain := getValidEthChain() // mock successful PayGasAndUpdateCctx keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *receiverChain, "") @@ -360,7 +360,7 @@ func TestKeeper_ProcessInboundProcessCrosschainMsgPassing(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - receiverChain := getValidEthChain(t) + receiverChain := getValidEthChain() // mock unsuccessful PayGasAndUpdateCctx observerMock.On("GetSupportedChainFromChainID", mock.Anything, receiverChain.ChainId). @@ -384,7 +384,7 @@ func TestKeeper_ProcessInboundProcessCrosschainMsgPassing(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - receiverChain := getValidEthChain(t) + receiverChain := getValidEthChain() // mock successful PayGasAndUpdateCctx keepertest.MockPayGasAndUpdateCCTX(fungibleMock, observerMock, ctx, *k, *receiverChain, "") diff --git a/x/crosschain/keeper/process_outbound_test.go b/x/crosschain/keeper/process_outbound_test.go index 2bd17818c6..b4dbbef200 100644 --- a/x/crosschain/keeper/process_outbound_test.go +++ b/x/crosschain/keeper/process_outbound_test.go @@ -137,7 +137,7 @@ func TestKeeper_ProcessFailedOutbound(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() asset := "" // mock successful GetRevertGasLimit for ERC20 @@ -169,7 +169,7 @@ func TestKeeper_ProcessFailedOutbound(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() asset := "" // mock successful GetRevertGasLimit for ERC20 @@ -201,7 +201,7 @@ func TestKeeper_ProcessFailedOutbound(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() asset := "" // mock successful GetRevertGasLimit for ERC20 @@ -232,7 +232,7 @@ func TestKeeper_ProcessFailedOutbound(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() asset := "" // mock successful GetRevertGasLimit for ERC20 @@ -258,7 +258,7 @@ func TestKeeper_ProcessFailedOutbound(t *testing.T) { fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() asset := "" // mock failed GetRevertGasLimit for ERC20 @@ -324,7 +324,7 @@ func TestKeeper_ProcessOutbound(t *testing.T) { fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() asset := "" cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) @@ -353,7 +353,7 @@ func TestKeeper_ProcessOutbound(t *testing.T) { fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() asset := "" cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) @@ -381,7 +381,7 @@ func TestKeeper_ProcessOutbound(t *testing.T) { observerMock := keepertest.GetCrosschainObserverMock(t, k) receiver := sample.EthAddress() amount := big.NewInt(42) - senderChain := getValidEthChain(t) + senderChain := getValidEthChain() asset := "" cctx := GetERC20Cctx(t, receiver, *senderChain, asset, amount) diff --git a/x/crosschain/keeper/refund_test.go b/x/crosschain/keeper/refund_test.go index 09732bd23a..5f00310be3 100644 --- a/x/crosschain/keeper/refund_test.go +++ b/x/crosschain/keeper/refund_test.go @@ -23,7 +23,7 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) sender := sample.EthAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "foobar") @@ -54,7 +54,7 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) sender := sample.EthAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() fungibleMock.On("GetGasCoinForForeignCoin", mock.Anything, mock.Anything).Return(fungibletypes.ForeignCoins{ Zrc20ContractAddress: "0x", @@ -84,7 +84,7 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) sender := sample.EthAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() fungibleMock.On("GetGasCoinForForeignCoin", mock.Anything, mock.Anything).Return(fungibletypes.ForeignCoins{ Zrc20ContractAddress: sample.EthAddress().Hex(), @@ -113,7 +113,7 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) sender := sample.EthAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "foobar") @@ -137,7 +137,7 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) sender := sample.EthAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) err := k.RefundAmountOnZetaChainGas(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ @@ -160,7 +160,7 @@ func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) sender := sample.EthAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) _ = setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "foobar") @@ -188,7 +188,7 @@ func TestKeeper_RefundAmountOnZetaChainZeta(t *testing.T) { k, ctx, sdkk, _ := keepertest.CrosschainKeeper(t) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) sender := sample.EthAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() err := k.RefundAmountOnZetaChainZeta(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ @@ -240,7 +240,7 @@ func TestKeeper_RefundAmountOnZetaChainZeta(t *testing.T) { fungibleMock.On("DepositCoinZeta", mock.Anything, mock.Anything, mock.Anything).Return(errors.New("err")) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) sender := sample.EthAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() err := k.RefundAmountOnZetaChainZeta(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ @@ -263,7 +263,7 @@ func TestKeeper_RefundAmountOnZetaChainZeta(t *testing.T) { k, ctx, sdkk, _ := keepertest.CrosschainKeeper(t) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) sender := sample.EthAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() err := k.RefundAmountOnZetaChainZeta(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ @@ -284,7 +284,7 @@ func TestKeeper_RefundAmountOnZetaChainZeta(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) sender := sample.EthAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() err := k.RefundAmountOnZetaChainZeta(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ @@ -310,7 +310,7 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) asset := sample.EthAddress().String() sender := sample.EthAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() // deploy zrc20 deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) @@ -376,7 +376,7 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) asset := sample.EthAddress().String() sender := sample.EthAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() err := k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ @@ -403,7 +403,7 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) asset := sample.EthAddress().String() sender := sample.EthAddress() - chainID := getValidEthChainID(t) + chainID := getValidEthChainID() fungibleMock.On("GetForeignCoinFromAsset", mock.Anything, mock.Anything, mock.Anything).Return(fungibletypes.ForeignCoins{ Zrc20ContractAddress: sample.EthAddress().Hex(), @@ -462,7 +462,7 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: coin.CoinType_ERC20, - SenderChainId: getValidEthChainID(t), + SenderChainId: getValidEthChainID(), Sender: sample.EthAddress().String(), Amount: math.Uint{}, }}, @@ -473,7 +473,7 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: coin.CoinType_ERC20, - SenderChainId: getValidEthChainID(t), + SenderChainId: getValidEthChainID(), Sender: sample.EthAddress().String(), Amount: math.ZeroUint(), }}, @@ -485,7 +485,7 @@ func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ InboundTxParams: &types.InboundTxParams{ CoinType: coin.CoinType_ERC20, - SenderChainId: getValidEthChainID(t), + SenderChainId: getValidEthChainID(), Sender: sample.EthAddress().String(), Asset: sample.EthAddress().String(), Amount: math.NewUint(42), diff --git a/x/crosschain/keeper/utils_test.go b/x/crosschain/keeper/utils_test.go index 732ec5d0bd..3b3ab6967c 100644 --- a/x/crosschain/keeper/utils_test.go +++ b/x/crosschain/keeper/utils_test.go @@ -22,12 +22,12 @@ import ( ) // getValidEthChainID get a valid eth chain id -func getValidEthChainID(t *testing.T) int64 { - return getValidEthChain(t).ChainId +func getValidEthChainID() int64 { + return getValidEthChain().ChainId } // getValidEthChain get a valid eth chain -func getValidEthChain(_ *testing.T) *chains.Chain { +func getValidEthChain() *chains.Chain { goerli := chains.GoerliLocalnetChain() return &goerli } From 101457c9c0287ef1d74e135ea84aea33fde87654 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Sat, 20 Apr 2024 00:47:43 -0500 Subject: [PATCH 13/33] added unit tests for cctx value conversion --- testutil/keeper/mocks/crosschain/fungible.go | 6 +- .../keeper/grpc_query_cctx_rate_limit.go | 55 ++++--- .../keeper/grpc_query_cctx_rate_limit_test.go | 141 ++++++++++++++++++ x/crosschain/types/expected_keepers.go | 2 +- x/fungible/keeper/foreign_coins.go | 16 +- 5 files changed, 179 insertions(+), 41 deletions(-) diff --git a/testutil/keeper/mocks/crosschain/fungible.go b/testutil/keeper/mocks/crosschain/fungible.go index 587c1676a6..a695f0d35d 100644 --- a/testutil/keeper/mocks/crosschain/fungible.go +++ b/testutil/keeper/mocks/crosschain/fungible.go @@ -254,12 +254,12 @@ func (_m *CrosschainFungibleKeeper) GetAllForeignCoinsForChain(ctx types.Context return r0 } -// GetAllForeignERC20CoinMap provides a mock function with given fields: ctx -func (_m *CrosschainFungibleKeeper) GetAllForeignERC20CoinMap(ctx types.Context) map[int64]map[string]fungibletypes.ForeignCoins { +// GetAllForeignCoinMap provides a mock function with given fields: ctx +func (_m *CrosschainFungibleKeeper) GetAllForeignCoinMap(ctx types.Context) map[int64]map[string]fungibletypes.ForeignCoins { ret := _m.Called(ctx) if len(ret) == 0 { - panic("no return value specified for GetAllForeignERC20CoinMap") + panic("no return value specified for GetAllForeignCoinMap") } var r0 map[int64]map[string]fungibletypes.ForeignCoins diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go index b3b30ca939..eafd1364b5 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go @@ -76,11 +76,11 @@ func (k Keeper) ListPendingCctxWithinRateLimit(c context.Context, req *types.Que // get the conversion rates for all foreign coins var gasCoinRates map[int64]sdk.Dec var erc20CoinRates map[int64]map[string]sdk.Dec - var erc20Coins map[int64]map[string]fungibletypes.ForeignCoins + var foreignCoinMap map[int64]map[string]fungibletypes.ForeignCoins var rateLimitInZeta sdk.Dec if applyLimit { gasCoinRates, erc20CoinRates = k.GetRateLimiterRates(ctx) - erc20Coins = k.fungibleKeeper.GetAllForeignERC20CoinMap(ctx) + foreignCoinMap = k.fungibleKeeper.GetAllForeignCoinMap(ctx) rateLimitInZeta = sdk.NewDecFromBigInt(rateLimitFlags.Rate.BigInt()) } @@ -130,7 +130,7 @@ LoopBackwards: break } // criteria #2: we should finish the RPC call if the rate limit is exceeded - if rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, erc20Coins, &totalCctxValueInZeta, rateLimitInZeta) { + if rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap, &totalCctxValueInZeta, rateLimitInZeta) { limitExceeded = true break LoopBackwards } @@ -167,7 +167,7 @@ LoopForwards: break LoopForwards } // criteria #2: we should finish the RPC call if the rate limit is exceeded - if rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, erc20Coins, &totalCctxValueInZeta, rateLimitInZeta) { + if rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap, &totalCctxValueInZeta, rateLimitInZeta) { limitExceeded = true break LoopForwards } @@ -182,39 +182,26 @@ LoopForwards: }, nil } -// convertCctxValue converts the value of the cctx in ZETA using given conversion rates -func convertCctxValue( +// ConvertCctxValue converts the value of the cctx in ZETA using given conversion rates +func ConvertCctxValue( chainID int64, cctx *types.CrossChainTx, gasCoinRates map[int64]sdk.Dec, erc20CoinRates map[int64]map[string]sdk.Dec, - erc20Coins map[int64]map[string]fungibletypes.ForeignCoins, + foreignCoinMap map[int64]map[string]fungibletypes.ForeignCoins, ) sdk.Dec { var rate sdk.Dec var decimals uint64 switch cctx.InboundTxParams.CoinType { case coin.CoinType_Zeta: // no conversion needed for ZETA - rate = sdk.NewDec(1) + amountCctx := sdk.NewDecFromBigInt(cctx.GetCurrentOutTxParam().Amount.BigInt()) + return amountCctx.Quo(sdk.NewDec(10).Power(18)) case coin.CoinType_Gas: rate = gasCoinRates[chainID] case coin.CoinType_ERC20: - // get the ERC20 coin decimals - _, found := erc20Coins[chainID] - if !found { - // skip if no coin found for this chainID - return sdk.NewDec(0) - } - fCoin, found := erc20Coins[chainID][strings.ToLower(cctx.InboundTxParams.Asset)] - if !found { - // skip if no coin found for this Asset - return sdk.NewDec(0) - } - // #nosec G701 always in range - decimals = uint64(fCoin.Decimals) - // get the ERC20 coin rate - _, found = erc20CoinRates[chainID] + _, found := erc20CoinRates[chainID] if !found { // skip if no rate found for this chainID return sdk.NewDec(0) @@ -224,16 +211,28 @@ func convertCctxValue( // skip CoinType_Cmd return sdk.NewDec(0) } - // should not happen, return 0 to skip if it happens - if rate.LTE(sdk.NewDec(0)) { + if rate.IsNil() || rate.LTE(sdk.NewDec(0)) { + return sdk.NewDec(0) + } + + // get foreign coin decimals + _, found := foreignCoinMap[chainID] + if !found { + // skip if no coin found for this chainID + return sdk.NewDec(0) + } + fCoin, found := foreignCoinMap[chainID][strings.ToLower(cctx.InboundTxParams.Asset)] + if !found { + // skip if no coin found for this Asset return sdk.NewDec(0) } + decimals = uint64(fCoin.Decimals) // the reciprocal of `rate` is the amount of zrc20 needed to buy 1 ZETA // for example, given rate = 0.8, the reciprocal is 1.25, which means 1.25 ZRC20 can buy 1 ZETA // given decimals = 6, the `oneZeta` amount will be 1.25 * 10^6 = 1250000 - oneZrc20 := sdk.NewDec(1).Power(decimals) + oneZrc20 := sdk.NewDec(10).Power(decimals) oneZeta := oneZrc20.Quo(rate) // convert asset amount into ZETA @@ -249,11 +248,11 @@ func rateLimitExceeded( cctx *types.CrossChainTx, gasCoinRates map[int64]sdk.Dec, erc20CoinRates map[int64]map[string]sdk.Dec, - erc20Coins map[int64]map[string]fungibletypes.ForeignCoins, + foreignCoinMap map[int64]map[string]fungibletypes.ForeignCoins, currentCctxValue *sdk.Dec, rateLimitValue sdk.Dec, ) bool { - amountZeta := convertCctxValue(chainID, cctx, gasCoinRates, erc20CoinRates, erc20Coins) + amountZeta := ConvertCctxValue(chainID, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap) *currentCctxValue = currentCctxValue.Add(amountZeta) return currentCctxValue.GT(rateLimitValue) } diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go index 31939862b5..dfe37ea4b3 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go @@ -3,6 +3,7 @@ package keeper_test import ( "fmt" "sort" + "strings" "testing" "cosmossdk.io/math" @@ -123,6 +124,146 @@ func setupForeignCoins( } } +func Test_ConvertCctxValue(t *testing.T) { + // chain IDs + ethChainID := getValidEthChainID() + btcChainID := getValidBtcChainID() + + // zrc20 addresses for ETH, BTC, USDT and asset for USDT + zrc20ETH := sample.EthAddress().Hex() + zrc20BTC := sample.EthAddress().Hex() + zrc20USDT := sample.EthAddress().Hex() + assetUSDT := sample.EthAddress().Hex() + + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + + // Set TSS + tss := sample.Tss() + zk.ObserverKeeper.SetTSS(ctx, tss) + + // Set foreign coins + setupForeignCoins(t, ctx, zk, zrc20ETH, zrc20BTC, zrc20USDT, assetUSDT) + + // Set rate limiter flags + rateLimiterFlags := createTestRateLimiterFlags(zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8") + k.SetRateLimiterFlags(ctx, rateLimiterFlags) + + // get rate limiter rates + gasCoinRates, erc20CoinRates := k.GetRateLimiterRates(ctx) + foreignCoinMap := zk.FungibleKeeper.GetAllForeignCoinMap(ctx) + + t.Run("should convert cctx ZETA value correctly", func(t *testing.T) { + // create cctx with 0.3 ZETA + cctx := sample.CrossChainTx(t, fmt.Sprintf("%d-%d", ethChainID, 1)) + cctx.InboundTxParams.CoinType = coin.CoinType_Zeta + cctx.InboundTxParams.Asset = "" + cctx.GetCurrentOutTxParam().Amount = sdk.NewUint(3e17) // 0.3 ZETA + + // convert cctx value + value := keeper.ConvertCctxValue(ethChainID, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap) + require.Equal(t, sdk.MustNewDecFromStr("0.3"), value) + }) + t.Run("should convert cctx ETH value correctly", func(t *testing.T) { + // create cctx with 0.003 ETH + cctx := sample.CrossChainTx(t, fmt.Sprintf("%d-%d", ethChainID, 1)) + cctx.InboundTxParams.CoinType = coin.CoinType_Gas + cctx.InboundTxParams.Asset = "" + cctx.GetCurrentOutTxParam().Amount = sdk.NewUint(3e15) // 0.003 ETH + + // convert cctx value + value := keeper.ConvertCctxValue(ethChainID, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap) + require.Equal(t, sdk.MustNewDecFromStr("7.5"), value) + }) + t.Run("should convert cctx BTC value correctly", func(t *testing.T) { + // create cctx with 0.0007 BTC + cctx := sample.CrossChainTx(t, fmt.Sprintf("%d-%d", btcChainID, 1)) + cctx.InboundTxParams.CoinType = coin.CoinType_Gas + cctx.InboundTxParams.Asset = "" + cctx.GetCurrentOutTxParam().Amount = sdk.NewUint(70000) // 0.0007 BTC + + // convert cctx value + value := keeper.ConvertCctxValue(btcChainID, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap) + require.Equal(t, sdk.MustNewDecFromStr("35.0"), value) + }) + t.Run("should convert cctx USDT value correctly", func(t *testing.T) { + // create cctx with 3 USDT + cctx := sample.CrossChainTx(t, fmt.Sprintf("%d-%d", ethChainID, 1)) + cctx.InboundTxParams.CoinType = coin.CoinType_ERC20 + cctx.InboundTxParams.Asset = assetUSDT + cctx.GetCurrentOutTxParam().Amount = sdk.NewUint(3e6) // 3 USDT + + // convert cctx value + value := keeper.ConvertCctxValue(ethChainID, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap) + require.Equal(t, sdk.MustNewDecFromStr("2.4"), value) + }) + t.Run("should return 0 if no rate found for chainID", func(t *testing.T) { + cctx := sample.CrossChainTx(t, fmt.Sprintf("%d-%d", ethChainID, 1)) + cctx.InboundTxParams.CoinType = coin.CoinType_ERC20 + cctx.GetCurrentOutTxParam().Amount = sdk.NewUint(100) + + // use nil erc20CoinRates map to convert cctx value + value := keeper.ConvertCctxValue(ethChainID, cctx, gasCoinRates, nil, foreignCoinMap) + require.Equal(t, sdk.NewDec(0), value) + }) + t.Run("should return 0 if coinType is CoinType_Cmd", func(t *testing.T) { + cctx := sample.CrossChainTx(t, fmt.Sprintf("%d-%d", ethChainID, 1)) + cctx.InboundTxParams.CoinType = coin.CoinType_Cmd + cctx.GetCurrentOutTxParam().Amount = sdk.NewUint(100) + + // convert cctx value + value := keeper.ConvertCctxValue(ethChainID, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap) + require.Equal(t, sdk.NewDec(0), value) + }) + t.Run("should return 0 on nil rate or rate <= 0", func(t *testing.T) { + cctx := sample.CrossChainTx(t, fmt.Sprintf("%d-%d", ethChainID, 1)) + cctx.InboundTxParams.CoinType = coin.CoinType_Gas + cctx.GetCurrentOutTxParam().Amount = sdk.NewUint(100) + + // use nil gasCoinRates map to convert cctx value + value := keeper.ConvertCctxValue(ethChainID, cctx, nil, erc20CoinRates, foreignCoinMap) + require.Equal(t, sdk.NewDec(0), value) + + // set rate to 0 + zeroCoinRates, _ := k.GetRateLimiterRates(ctx) + zeroCoinRates[ethChainID] = sdk.NewDec(0) + + // convert cctx value + value = keeper.ConvertCctxValue(ethChainID, cctx, zeroCoinRates, erc20CoinRates, foreignCoinMap) + require.Equal(t, sdk.NewDec(0), value) + + // set rate to -1 + negativeCoinRates, _ := k.GetRateLimiterRates(ctx) + negativeCoinRates[ethChainID] = sdk.NewDec(-1) + + // convert cctx value + value = keeper.ConvertCctxValue(ethChainID, cctx, negativeCoinRates, erc20CoinRates, foreignCoinMap) + require.Equal(t, sdk.NewDec(0), value) + }) + t.Run("should return 0 if no coin found for chainID", func(t *testing.T) { + cctx := sample.CrossChainTx(t, fmt.Sprintf("%d-%d", ethChainID, 1)) + cctx.InboundTxParams.CoinType = coin.CoinType_Gas + cctx.GetCurrentOutTxParam().Amount = sdk.NewUint(100) + + // use empty foreignCoinMap to convert cctx value + value := keeper.ConvertCctxValue(ethChainID, cctx, gasCoinRates, erc20CoinRates, nil) + require.Equal(t, sdk.NewDec(0), value) + }) + t.Run("should return 0 if no coin found for asset", func(t *testing.T) { + cctx := sample.CrossChainTx(t, fmt.Sprintf("%d-%d", ethChainID, 1)) + cctx.InboundTxParams.CoinType = coin.CoinType_ERC20 + cctx.InboundTxParams.Asset = assetUSDT + cctx.GetCurrentOutTxParam().Amount = sdk.NewUint(100) + + // delete assetUSDT from foreignCoinMap for ethChainID + tempCoinMap := zk.FungibleKeeper.GetAllForeignCoinMap(ctx) + delete(tempCoinMap[ethChainID], strings.ToLower(assetUSDT)) + + // convert cctx value + value := keeper.ConvertCctxValue(ethChainID, cctx, gasCoinRates, erc20CoinRates, tempCoinMap) + require.Equal(t, sdk.NewDec(0), value) + }) +} + func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { // chain IDs ethChainID := getValidEthChainID() diff --git a/x/crosschain/types/expected_keepers.go b/x/crosschain/types/expected_keepers.go index af4f580794..fb03a86281 100644 --- a/x/crosschain/types/expected_keepers.go +++ b/x/crosschain/types/expected_keepers.go @@ -96,7 +96,7 @@ type ObserverKeeper interface { type FungibleKeeper interface { GetForeignCoins(ctx sdk.Context, zrc20Addr string) (val fungibletypes.ForeignCoins, found bool) GetAllForeignCoins(ctx sdk.Context) (list []fungibletypes.ForeignCoins) - GetAllForeignERC20CoinMap(ctx sdk.Context) map[int64]map[string]fungibletypes.ForeignCoins + GetAllForeignCoinMap(ctx sdk.Context) map[int64]map[string]fungibletypes.ForeignCoins SetForeignCoins(ctx sdk.Context, foreignCoins fungibletypes.ForeignCoins) GetAllForeignCoinsForChain(ctx sdk.Context, foreignChainID int64) (list []fungibletypes.ForeignCoins) GetForeignCoinFromAsset(ctx sdk.Context, asset string, chainID int64) (fungibletypes.ForeignCoins, bool) diff --git a/x/fungible/keeper/foreign_coins.go b/x/fungible/keeper/foreign_coins.go index 5f0a31da4a..2f3eaf7918 100644 --- a/x/fungible/keeper/foreign_coins.go +++ b/x/fungible/keeper/foreign_coins.go @@ -81,20 +81,18 @@ func (k Keeper) GetAllForeignCoins(ctx sdk.Context) (list []types.ForeignCoins) return } -// GetAllForeignERC20CoinMap returns all foreign ERC20 coins in a map of chainID -> asset -> coin -func (k Keeper) GetAllForeignERC20CoinMap(ctx sdk.Context) map[int64]map[string]types.ForeignCoins { +// GetAllForeignCoinMap returns all foreign ERC20 coins in a map of chainID -> asset -> coin +func (k Keeper) GetAllForeignCoinMap(ctx sdk.Context) map[int64]map[string]types.ForeignCoins { allForeignCoins := k.GetAllForeignCoins(ctx) - erc20CoinMap := make(map[int64]map[string]types.ForeignCoins) + fCoinMap := make(map[int64]map[string]types.ForeignCoins) for _, c := range allForeignCoins { - if c.CoinType == coin.CoinType_ERC20 { - if _, found := erc20CoinMap[c.ForeignChainId]; !found { - erc20CoinMap[c.ForeignChainId] = make(map[string]types.ForeignCoins) - } - erc20CoinMap[c.ForeignChainId][strings.ToLower(c.Asset)] = c + if _, found := fCoinMap[c.ForeignChainId]; !found { + fCoinMap[c.ForeignChainId] = make(map[string]types.ForeignCoins) } + fCoinMap[c.ForeignChainId][strings.ToLower(c.Asset)] = c } - return erc20CoinMap + return fCoinMap } // GetGasCoinForForeignCoin returns the gas coin for a given chain From 874d5f3dc705c3df5c1a33bd2c319e2ee2ac03d1 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Sat, 20 Apr 2024 00:59:31 -0500 Subject: [PATCH 14/33] add changelog entry --- changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.md b/changelog.md index ede402b460..23074d6e1f 100644 --- a/changelog.md +++ b/changelog.md @@ -81,6 +81,7 @@ * [1985](https://github.com/zeta-chain/node/pull/1985) - improve fungible module coverage * [1992](https://github.com/zeta-chain/node/pull/1992) - remove setupKeeper from crosschain module * [2008](https://github.com/zeta-chain/node/pull/2008) - add test for connector bytecode update +* [2060](https://github.com/zeta-chain/node/pull/2060) - add unit test for rate limiter query ### Fixes From 16955b899c64b29890145c8156d90a975d1e6bd3 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Sat, 20 Apr 2024 13:35:44 -0500 Subject: [PATCH 15/33] added unit tests for query pending cctxs within rate limit --- .../keeper/grpc_query_cctx_rate_limit.go | 48 +++-- .../keeper/grpc_query_cctx_rate_limit_test.go | 197 +++++++++++++++--- 2 files changed, 203 insertions(+), 42 deletions(-) diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go index eafd1364b5..41ebd2aa65 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go @@ -2,6 +2,7 @@ package keeper import ( "context" + "sort" "strings" sdk "github.com/cosmos/cosmos-sdk/types" @@ -90,6 +91,12 @@ func (k Keeper) ListPendingCctxWithinRateLimit(c context.Context, req *types.Que return uint32(len(cctxs)) >= limit } + // if a cctx falls within the rate limiter window + isCctxInWindow := func(cctx *types.CrossChainTx) bool { + // #nosec G701 checked positive + return cctx.InboundTxParams.InboundTxObservedExternalHeight >= uint64(leftWindowBoundary) + } + // query pending nonces for each foreign chain // Note: The pending nonces could change during the RPC call, so query them beforehand pendingNoncesMap := make(map[int64]*observertypes.PendingNonces) @@ -114,23 +121,29 @@ LoopBackwards: endNonce = 0 } + // add the pending nonces to the total pending + // Note: the `totalPending` may not be accurate only if the rate limiter triggers early exit + // `totalPending` is now used for metrics only and it's okay to trade off accuracy for performance + // #nosec G701 always in range + totalPending += uint64(pendingNonces.NonceHigh - pendingNonces.NonceLow) + // query cctx by nonce backwards to the left boundary of the rate limit sliding window for nonce := startNonce; nonce >= 0; nonce-- { cctx, err := getCctxByChainIDAndNonce(k, ctx, tss.TssPubkey, chain.ChainId, nonce) if err != nil { return nil, err } + inWindow := isCctxInWindow(cctx) // We should at least go backwards by 1000 nonces to pick up missed pending cctxs // We might go even further back if rate limiter is enabled and the endNonce hasn't hit the left window boundary yet // There are two criteria to stop scanning backwards: // criteria #1: we'll stop at the left window boundary if the `endNonce` hasn't hit it yet - // #nosec G701 always positive - if nonce < endNonce && cctx.InboundTxParams.InboundTxObservedExternalHeight < uint64(leftWindowBoundary) { + if nonce < endNonce && !inWindow { break } // criteria #2: we should finish the RPC call if the rate limit is exceeded - if rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap, &totalCctxValueInZeta, rateLimitInZeta) { + if inWindow && rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap, &totalCctxValueInZeta, rateLimitInZeta) { limitExceeded = true break LoopBackwards } @@ -143,12 +156,6 @@ LoopBackwards: } } } - - // add the pending nonces to the total pending - // Note: the `totalPending` may not be accurate only if the rate limiter triggers early exit - // `totalPending` is now used for metrics only and it's okay to trade off accuracy for performance - // #nosec G701 always in range - totalPending += uint64(pendingNonces.NonceHigh - pendingNonces.NonceLow) } // query forwards for pending cctxs for each foreign chain @@ -161,13 +168,14 @@ LoopForwards: if err != nil { return nil, err } + inWindow := isCctxInWindow(cctx) // only take a `limit` number of pending cctxs as result if maxCCTXsReached() { break LoopForwards } // criteria #2: we should finish the RPC call if the rate limit is exceeded - if rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap, &totalCctxValueInZeta, rateLimitInZeta) { + if inWindow && rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap, &totalCctxValueInZeta, rateLimitInZeta) { limitExceeded = true break LoopForwards } @@ -175,6 +183,14 @@ LoopForwards: } } + // sort the cctxs by chain ID and nonce (lower nonce holds higher priority for scheduling) + sort.Slice(cctxs, func(i, j int) bool { + if cctxs[i].GetCurrentOutTxParam().ReceiverChainId == cctxs[j].GetCurrentOutTxParam().ReceiverChainId { + return cctxs[i].GetCurrentOutTxParam().OutboundTxTssNonce < cctxs[j].GetCurrentOutTxParam().OutboundTxTssNonce + } + return cctxs[i].GetCurrentOutTxParam().ReceiverChainId < cctxs[j].GetCurrentOutTxParam().ReceiverChainId + }) + return &types.QueryListPendingCctxWithinRateLimitResponse{ CrossChainTx: cctxs, TotalPending: totalPending, @@ -229,15 +245,17 @@ func ConvertCctxValue( } decimals = uint64(fCoin.Decimals) - // the reciprocal of `rate` is the amount of zrc20 needed to buy 1 ZETA - // for example, given rate = 0.8, the reciprocal is 1.25, which means 1.25 ZRC20 can buy 1 ZETA - // given decimals = 6, the `oneZeta` amount will be 1.25 * 10^6 = 1250000 + // given decimals = 6, the `oneZrc20` amount will be 10^6 = 1000000 oneZrc20 := sdk.NewDec(10).Power(decimals) - oneZeta := oneZrc20.Quo(rate) // convert asset amount into ZETA + // step 1: convert the amount into ZRC20 integer amount + // step 2: convert the ZRC20 integer amount into decimal amount + // given amountCctx = 2000000, rate = 0.8, decimals = 6 + // the amountZrc20 = 2000000 * 0.8 = 1600000, the amountZeta = 1600000 / 1000000 = 1.6 amountCctx := sdk.NewDecFromBigInt(cctx.GetCurrentOutTxParam().Amount.BigInt()) - amountZeta := amountCctx.Quo(oneZeta) + amountZrc20 := amountCctx.Mul(rate) + amountZeta := amountZrc20.Quo(oneZrc20) return amountZeta } diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go index dfe37ea4b3..4e6b142329 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go @@ -2,7 +2,6 @@ package keeper_test import ( "fmt" - "sort" "strings" "testing" @@ -28,8 +27,8 @@ func createTestRateLimiterFlags( ) types.RateLimiterFlags { var rateLimiterFlags = types.RateLimiterFlags{ Enabled: true, - Window: 100, // 100 zeta blocks, 10 minutes - Rate: math.NewUint(1000), // 1000 ZETA + Window: 500, // 500 zeta blocks, 50 minutes + Rate: math.NewUint(5000), // 5000 ZETA Conversions: []types.Conversion{ // ETH { @@ -51,11 +50,11 @@ func createTestRateLimiterFlags( return rateLimiterFlags } -// createCctxWithCopyTypeAndBlockRange +// createCctxsWithCoinTypeAndHeightRange // - create 1 cctx per block from lowBlock to highBlock (inclusive) // // return created cctxs -func createCctxWithCopyTypeAndHeightRange( +func createCctxsWithCoinTypeAndHeightRange( t *testing.T, ctx sdk.Context, k keeper.Keeper, @@ -78,6 +77,7 @@ func createCctxWithCopyTypeAndHeightRange( cctx.InboundTxParams.CoinType = coinType cctx.InboundTxParams.Asset = asset cctx.InboundTxParams.InboundTxObservedExternalHeight = i + cctx.GetCurrentOutTxParam().ReceiverChainId = chainID cctx.GetCurrentOutTxParam().Amount = sdk.NewUint(amount) cctx.GetCurrentOutTxParam().OutboundTxTssNonce = nonce k.SetCrossChainTx(ctx, *cctx) @@ -124,6 +124,59 @@ func setupForeignCoins( } } +// createKeeperForRateLimiterTest creates a keeper filled with cctxs for rate limiter test +func createKeeperForRateLimiterTest(t *testing.T) (k *keeper.Keeper, ctx sdk.Context, cctxsETH, cctxsBTC []*types.CrossChainTx, rateLimiterFlags types.RateLimiterFlags) { + // chain IDs + ethChainID := getValidEthChainID() + btcChainID := getValidBtcChainID() + + // zrc20 addresses for ETH, BTC, USDT and asset for USDT + zrc20ETH := sample.EthAddress().Hex() + zrc20BTC := sample.EthAddress().Hex() + zrc20USDT := sample.EthAddress().Hex() + assetUSDT := sample.EthAddress().Hex() + + // create test rate limiter flags + rateLimiterFlags = createTestRateLimiterFlags(zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8") + + // define cctx status + statusPending := types.CctxStatus_PendingOutbound + statusMined := types.CctxStatus_OutboundMined + + // create test keepers + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + + // Set TSS + tss := sample.Tss() + zk.ObserverKeeper.SetTSS(ctx, tss) + + // Set foreign coins + setupForeignCoins(t, ctx, zk, zrc20ETH, zrc20BTC, zrc20USDT, assetUSDT) + + // Set rate limiter flags + k.SetRateLimiterFlags(ctx, rateLimiterFlags) + + // Create cctxs [0~999] and [1000~1199] for Eth chain, 0.001 ETH (2.5 ZETA) per cctx + createCctxsWithCoinTypeAndHeightRange(t, ctx, *k, zk, tss, 1, 1000, ethChainID, coin.CoinType_Gas, "", uint64(1e15), statusMined) + cctxsETH = createCctxsWithCoinTypeAndHeightRange(t, ctx, *k, zk, tss, 1001, 1200, ethChainID, coin.CoinType_Gas, "", uint64(1e15), statusPending) + + // Set Eth chain pending nonces, [1000~1099] are missed cctxs + setPendingNonces(ctx, zk, ethChainID, 1100, 1200, tss.TssPubkey) + + // Create cctxs [0~999] and [1000~1199] for Btc chain, 0.00001 BTC (0.5 ZETA) per cctx + createCctxsWithCoinTypeAndHeightRange(t, ctx, *k, zk, tss, 1, 1000, btcChainID, coin.CoinType_Gas, "", 1000, statusMined) + cctxsBTC = createCctxsWithCoinTypeAndHeightRange(t, ctx, *k, zk, tss, 1001, 1200, btcChainID, coin.CoinType_Gas, "", 1000, statusPending) + require.NotNil(t, cctxsBTC) + + // Set Btc chain pending nonces, [1000~1099] are missed cctxs + setPendingNonces(ctx, zk, btcChainID, 1100, 1200, tss.TssPubkey) + + // Set current block height to 1201, the window is now [701, 1201], the nonces [700~1200] fall into the window + ctx = ctx.WithBlockHeight(1201) + + return k, ctx, cctxsETH, cctxsBTC, rateLimiterFlags +} + func Test_ConvertCctxValue(t *testing.T) { // chain IDs ethChainID := getValidEthChainID() @@ -265,18 +318,46 @@ func Test_ConvertCctxValue(t *testing.T) { } func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { - // chain IDs - ethChainID := getValidEthChainID() - - // define cctx status - statusPending := types.CctxStatus_PendingOutbound - statusMined := types.CctxStatus_OutboundMined - t.Run("should fail for empty req", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) _, err := k.ListPendingCctxWithinRateLimit(ctx, nil) require.ErrorContains(t, err, "invalid request") }) + t.Run("height out of range", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + + // Set rate limiter flags as disabled + rFlags := sample.RateLimiterFlags() + k.SetRateLimiterFlags(ctx, rFlags) + + ctx = ctx.WithBlockHeight(0) + _, err := k.ListPendingCctxWithinRateLimit(ctx, &types.QueryListPendingCctxWithinRateLimitRequest{}) + require.ErrorContains(t, err, "height out of range") + }) + t.Run("tss not found", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + + // Set rate limiter flags as disabled + rFlags := sample.RateLimiterFlags() + k.SetRateLimiterFlags(ctx, rFlags) + + _, err := k.ListPendingCctxWithinRateLimit(ctx, &types.QueryListPendingCctxWithinRateLimitRequest{}) + require.ErrorContains(t, err, "tss not found") + }) + t.Run("pending nonces not found", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + + // Set rate limiter flags as disabled + rFlags := sample.RateLimiterFlags() + k.SetRateLimiterFlags(ctx, rFlags) + + // Set TSS + tss := sample.Tss() + zk.ObserverKeeper.SetTSS(ctx, tss) + + _, err := k.ListPendingCctxWithinRateLimit(ctx, &types.QueryListPendingCctxWithinRateLimitRequest{}) + require.ErrorContains(t, err, "pending nonces not found") + }) t.Run("should use fallback query", func(t *testing.T) { k, ctx, _, zk := keepertest.CrosschainKeeper(t) @@ -285,13 +366,14 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { zk.ObserverKeeper.SetTSS(ctx, tss) // Set rate limiter flags as disabled - rateLimiterFlags := sample.RateLimiterFlags() - rateLimiterFlags.Enabled = false - k.SetRateLimiterFlags(ctx, rateLimiterFlags) + rFlags := sample.RateLimiterFlags() + rFlags.Enabled = false + k.SetRateLimiterFlags(ctx, rFlags) // Create cctxs [0~999] and [1000~1199] for Eth chain, 0.001 ETH per cctx - _ = createCctxWithCopyTypeAndHeightRange(t, ctx, *k, zk, tss, 1, 1000, ethChainID, coin.CoinType_Gas, "", uint64(1e15), statusMined) - cctxETH := createCctxWithCopyTypeAndHeightRange(t, ctx, *k, zk, tss, 1001, 1200, ethChainID, coin.CoinType_Gas, "", uint64(1e15), statusPending) + ethChainID := getValidEthChainID() + _ = createCctxsWithCoinTypeAndHeightRange(t, ctx, *k, zk, tss, 1, 1000, ethChainID, coin.CoinType_Gas, "", uint64(1e15), types.CctxStatus_OutboundMined) + cctxsETH := createCctxsWithCoinTypeAndHeightRange(t, ctx, *k, zk, tss, 1001, 1200, ethChainID, coin.CoinType_Gas, "", uint64(1e15), types.CctxStatus_PendingOutbound) // Set Eth chain pending nonces which contains 100 missing cctxs setPendingNonces(ctx, zk, ethChainID, 1100, 1200, tss.TssPubkey) @@ -301,11 +383,8 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { require.NoError(t, err) require.Equal(t, 100, len(res.CrossChainTx)) - // sort res.CrossChainTx by outbound nonce ascending so that we can compare with cctxETH - sort.Slice(res.CrossChainTx, func(i, j int) bool { - return res.CrossChainTx[i].GetCurrentOutTxParam().OutboundTxTssNonce < res.CrossChainTx[j].GetCurrentOutTxParam().OutboundTxTssNonce - }) - require.EqualValues(t, cctxETH[:100], res.CrossChainTx) + // check response + require.EqualValues(t, cctxsETH[:100], res.CrossChainTx) require.EqualValues(t, uint64(200), res.TotalPending) // Query pending cctxs use max limit @@ -313,11 +392,75 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { require.NoError(t, err) require.Equal(t, 200, len(res.CrossChainTx)) - // sort res.CrossChainTx by outbound nonce ascending so that we can compare with cctxETH - sort.Slice(res.CrossChainTx, func(i, j int) bool { - return res.CrossChainTx[i].GetCurrentOutTxParam().OutboundTxTssNonce < res.CrossChainTx[j].GetCurrentOutTxParam().OutboundTxTssNonce - }) - require.EqualValues(t, cctxETH, res.CrossChainTx) + // check response + require.EqualValues(t, cctxsETH, res.CrossChainTx) require.EqualValues(t, uint64(200), res.TotalPending) }) + t.Run("can retrieve pending cctx in range without exceeding rate limit", func(t *testing.T) { + k, ctx, cctxsETH, cctxsBTC, _ := createKeeperForRateLimiterTest(t) + + res, err := k.ListPendingCctxWithinRateLimit(ctx, &types.QueryListPendingCctxWithinRateLimitRequest{}) + require.NoError(t, err) + require.Equal(t, 400, len(res.CrossChainTx)) + require.EqualValues(t, cctxsETH, res.CrossChainTx[0:200]) + require.EqualValues(t, cctxsBTC, res.CrossChainTx[200:400]) + require.EqualValues(t, uint64(400), res.TotalPending) + require.False(t, res.RateLimitExceeded) + }) + t.Run("Set rate to a lower value (< 1200) to early break the LoopBackwards with criteria #2", func(t *testing.T) { + k, ctx, cctxsETH, cctxsBTC, rlFlags := createKeeperForRateLimiterTest(t) + + rlFlags.Rate = math.NewUint(1000) // 1000 ZETA + k.SetRateLimiterFlags(ctx, rlFlags) + + res, err := k.ListPendingCctxWithinRateLimit(ctx, &types.QueryListPendingCctxWithinRateLimitRequest{}) + require.NoError(t, err) + require.Equal(t, 200, len(res.CrossChainTx)) + require.EqualValues(t, cctxsETH[:100], res.CrossChainTx[0:100]) + require.EqualValues(t, cctxsBTC[:100], res.CrossChainTx[100:200]) + require.EqualValues(t, uint64(400), res.TotalPending) + require.True(t, res.RateLimitExceeded) + }) + t.Run("Set high rate and big window to early to break inner loop with the criteria #1", func(t *testing.T) { + k, ctx, cctxsETH, cctxsBTC, rlFlags := createKeeperForRateLimiterTest(t) + + // The left boundary will be 51 (1201-1150), less than the endNonce 100 (1100 - 10000) + rlFlags.Rate = math.NewUint(10000) + rlFlags.Window = 1150 + k.SetRateLimiterFlags(ctx, rlFlags) + + res, err := k.ListPendingCctxWithinRateLimit(ctx, &types.QueryListPendingCctxWithinRateLimitRequest{}) + require.NoError(t, err) + require.Equal(t, 400, len(res.CrossChainTx)) + require.EqualValues(t, cctxsETH, res.CrossChainTx[0:200]) + require.EqualValues(t, cctxsBTC, res.CrossChainTx[200:400]) + require.EqualValues(t, uint64(400), res.TotalPending) + require.False(t, res.RateLimitExceeded) + }) + t.Run("Set lower request limit to early break the LoopForwards loop", func(t *testing.T) { + k, ctx, cctxsETH, cctxsBTC, _ := createKeeperForRateLimiterTest(t) + + res, err := k.ListPendingCctxWithinRateLimit(ctx, &types.QueryListPendingCctxWithinRateLimitRequest{Limit: 300}) + require.NoError(t, err) + require.Equal(t, 300, len(res.CrossChainTx)) + require.EqualValues(t, cctxsETH[:100], res.CrossChainTx[0:100]) + require.EqualValues(t, cctxsBTC, res.CrossChainTx[100:300]) + require.EqualValues(t, uint64(400), res.TotalPending) + require.False(t, res.RateLimitExceeded) + }) + t.Run("Set rate to middle value (1200 < rate < 1500) to early break the LoopForwards loop with criteria #2", func(t *testing.T) { + k, ctx, cctxsETH, cctxsBTC, rlFlags := createKeeperForRateLimiterTest(t) + + rlFlags.Window = 500 + rlFlags.Rate = math.NewUint(1300) // 1300 ZETA + k.SetRateLimiterFlags(ctx, rlFlags) + + res, err := k.ListPendingCctxWithinRateLimit(ctx, &types.QueryListPendingCctxWithinRateLimitRequest{}) + require.NoError(t, err) + require.Equal(t, 320, len(res.CrossChainTx)) // 120 ETH cctx + 200 BTC cctx + require.EqualValues(t, cctxsETH[:120], res.CrossChainTx[0:120]) + require.EqualValues(t, cctxsBTC, res.CrossChainTx[120:320]) + require.EqualValues(t, uint64(400), res.TotalPending) + require.True(t, res.RateLimitExceeded) + }) } From 249bcaa3ebed890cfb87804a9872bb5f839ab654 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Sat, 20 Apr 2024 14:24:29 -0500 Subject: [PATCH 16/33] added total value in rate limiter window for monitoring purpose --- docs/openapi/openapi.swagger.yaml | 3 + proto/crosschain/query.proto | 3 +- typescript/crosschain/query_pb.d.ts | 7 +- .../keeper/grpc_query_cctx_rate_limit.go | 1 + .../keeper/grpc_query_cctx_rate_limit_test.go | 8 +- x/crosschain/types/query.pb.go | 279 ++++++++++-------- zetaclient/interfaces/interfaces.go | 2 +- zetaclient/testutils/stub/core_bridge.go | 6 +- zetaclient/zetabridge/query.go | 6 +- zetaclient/zetacore_observer.go | 14 +- 10 files changed, 193 insertions(+), 136 deletions(-) diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index 1eb8fe4593..139ee8110a 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -54013,6 +54013,9 @@ definitions: total_pending: type: string format: uint64 + value_within_window: + type: string + format: uint64 rate_limit_exceeded: type: boolean crosschainQueryMessagePassingProtocolFeeResponse: diff --git a/proto/crosschain/query.proto b/proto/crosschain/query.proto index b017e2c523..1ecd041c48 100644 --- a/proto/crosschain/query.proto +++ b/proto/crosschain/query.proto @@ -270,7 +270,8 @@ message QueryListPendingCctxWithinRateLimitRequest { message QueryListPendingCctxWithinRateLimitResponse { repeated CrossChainTx cross_chain_tx = 1; uint64 total_pending = 2; - bool rate_limit_exceeded = 3; + uint64 value_within_window = 3; + bool rate_limit_exceeded = 4; } message QueryLastZetaHeightRequest {} diff --git a/typescript/crosschain/query_pb.d.ts b/typescript/crosschain/query_pb.d.ts index 34b4a44f38..62e8fdfe3a 100644 --- a/typescript/crosschain/query_pb.d.ts +++ b/typescript/crosschain/query_pb.d.ts @@ -910,7 +910,12 @@ export declare class QueryListPendingCctxWithinRateLimitResponse extends Message totalPending: bigint; /** - * @generated from field: bool rate_limit_exceeded = 3; + * @generated from field: uint64 value_within_window = 3; + */ + valueWithinWindow: bigint; + + /** + * @generated from field: bool rate_limit_exceeded = 4; */ rateLimitExceeded: boolean; diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go index 41ebd2aa65..287ebe1147 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go @@ -194,6 +194,7 @@ LoopForwards: return &types.QueryListPendingCctxWithinRateLimitResponse{ CrossChainTx: cctxs, TotalPending: totalPending, + ValueWithinWindow: totalCctxValueInZeta.TruncateInt().Uint64(), RateLimitExceeded: limitExceeded, }, nil } diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go index 4e6b142329..8b53958ad3 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go @@ -406,11 +406,13 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { require.EqualValues(t, cctxsBTC, res.CrossChainTx[200:400]) require.EqualValues(t, uint64(400), res.TotalPending) require.False(t, res.RateLimitExceeded) + require.Equal(t, uint64(1500), res.ValueWithinWindow) // 500 * (2.5 + 0.5) }) t.Run("Set rate to a lower value (< 1200) to early break the LoopBackwards with criteria #2", func(t *testing.T) { k, ctx, cctxsETH, cctxsBTC, rlFlags := createKeeperForRateLimiterTest(t) - rlFlags.Rate = math.NewUint(1000) // 1000 ZETA + rate := uint64(1000) // 1000 ZETA + rlFlags.Rate = math.NewUint(rate) k.SetRateLimiterFlags(ctx, rlFlags) res, err := k.ListPendingCctxWithinRateLimit(ctx, &types.QueryListPendingCctxWithinRateLimitRequest{}) @@ -420,6 +422,7 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { require.EqualValues(t, cctxsBTC[:100], res.CrossChainTx[100:200]) require.EqualValues(t, uint64(400), res.TotalPending) require.True(t, res.RateLimitExceeded) + require.True(t, res.ValueWithinWindow >= rate) }) t.Run("Set high rate and big window to early to break inner loop with the criteria #1", func(t *testing.T) { k, ctx, cctxsETH, cctxsBTC, rlFlags := createKeeperForRateLimiterTest(t) @@ -436,6 +439,7 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { require.EqualValues(t, cctxsBTC, res.CrossChainTx[200:400]) require.EqualValues(t, uint64(400), res.TotalPending) require.False(t, res.RateLimitExceeded) + require.EqualValues(t, uint64(3450), res.ValueWithinWindow) // 1150 * (2.5 + 0.5) }) t.Run("Set lower request limit to early break the LoopForwards loop", func(t *testing.T) { k, ctx, cctxsETH, cctxsBTC, _ := createKeeperForRateLimiterTest(t) @@ -447,6 +451,7 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { require.EqualValues(t, cctxsBTC, res.CrossChainTx[100:300]) require.EqualValues(t, uint64(400), res.TotalPending) require.False(t, res.RateLimitExceeded) + require.EqualValues(t, uint64(1250), res.ValueWithinWindow) // 500 * 0.5 + 400 * 2.5 }) t.Run("Set rate to middle value (1200 < rate < 1500) to early break the LoopForwards loop with criteria #2", func(t *testing.T) { k, ctx, cctxsETH, cctxsBTC, rlFlags := createKeeperForRateLimiterTest(t) @@ -462,5 +467,6 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { require.EqualValues(t, cctxsBTC, res.CrossChainTx[120:320]) require.EqualValues(t, uint64(400), res.TotalPending) require.True(t, res.RateLimitExceeded) + require.True(t, res.ValueWithinWindow >= 1300) }) } diff --git a/x/crosschain/types/query.pb.go b/x/crosschain/types/query.pb.go index 879dcce901..4d7c826736 100644 --- a/x/crosschain/types/query.pb.go +++ b/x/crosschain/types/query.pb.go @@ -1638,7 +1638,8 @@ func (m *QueryListPendingCctxWithinRateLimitRequest) GetLimit() uint32 { type QueryListPendingCctxWithinRateLimitResponse struct { CrossChainTx []*CrossChainTx `protobuf:"bytes,1,rep,name=cross_chain_tx,json=crossChainTx,proto3" json:"cross_chain_tx,omitempty"` TotalPending uint64 `protobuf:"varint,2,opt,name=total_pending,json=totalPending,proto3" json:"total_pending,omitempty"` - RateLimitExceeded bool `protobuf:"varint,3,opt,name=rate_limit_exceeded,json=rateLimitExceeded,proto3" json:"rate_limit_exceeded,omitempty"` + ValueWithinWindow uint64 `protobuf:"varint,3,opt,name=value_within_window,json=valueWithinWindow,proto3" json:"value_within_window,omitempty"` + RateLimitExceeded bool `protobuf:"varint,4,opt,name=rate_limit_exceeded,json=rateLimitExceeded,proto3" json:"rate_limit_exceeded,omitempty"` } func (m *QueryListPendingCctxWithinRateLimitResponse) Reset() { @@ -1692,6 +1693,13 @@ func (m *QueryListPendingCctxWithinRateLimitResponse) GetTotalPending() uint64 { return 0 } +func (m *QueryListPendingCctxWithinRateLimitResponse) GetValueWithinWindow() uint64 { + if m != nil { + return m.ValueWithinWindow + } + return 0 +} + func (m *QueryListPendingCctxWithinRateLimitResponse) GetRateLimitExceeded() bool { if m != nil { return m.RateLimitExceeded @@ -2102,126 +2110,128 @@ func init() { func init() { proto.RegisterFile("crosschain/query.proto", fileDescriptor_65a992045e92a606) } var fileDescriptor_65a992045e92a606 = []byte{ - // 1901 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5a, 0xc1, 0x6f, 0xdc, 0x4a, - 0x19, 0xcf, 0x64, 0x9b, 0xf7, 0xd2, 0x49, 0xda, 0xbc, 0xcc, 0x0b, 0x25, 0xf8, 0x25, 0x9b, 0xd6, - 0xa1, 0x4d, 0x48, 0xc8, 0xfa, 0x25, 0x7d, 0xcd, 0xa3, 0x6d, 0x1e, 0x62, 0x93, 0xbe, 0xa4, 0x81, - 0xb4, 0x4d, 0x57, 0x41, 0x45, 0x45, 0xc8, 0x9a, 0x78, 0xa7, 0x5e, 0xab, 0x8e, 0x9d, 0xae, 0xbd, - 0xd5, 0xa6, 0x51, 0x2e, 0x3d, 0x70, 0x46, 0xea, 0x81, 0x0b, 0x57, 0x44, 0x0f, 0x1c, 0x38, 0x20, - 0x38, 0x20, 0x15, 0x21, 0xa0, 0xf4, 0x58, 0x09, 0x81, 0x10, 0x48, 0x08, 0xb5, 0xfc, 0x05, 0xfc, - 0x05, 0xc8, 0xe3, 0xcf, 0xbb, 0x63, 0xaf, 0xbd, 0x3b, 0xd9, 0x6c, 0x0f, 0x3d, 0x75, 0xed, 0x99, - 0xef, 0x9b, 0xdf, 0xef, 0x9b, 0x6f, 0x3e, 0x7f, 0xf3, 0x6b, 0xf0, 0x39, 0xa3, 0xea, 0x7a, 0x9e, - 0x51, 0xa1, 0x96, 0xa3, 0x3d, 0xaa, 0xb1, 0xea, 0x41, 0x61, 0xbf, 0xea, 0xfa, 0x2e, 0x99, 0x7c, - 0xc2, 0x7c, 0xca, 0x5f, 0x17, 0xf8, 0x2f, 0xb7, 0xca, 0x0a, 0xcd, 0xa9, 0xca, 0x9c, 0xe1, 0x7a, - 0x7b, 0xae, 0xa7, 0xed, 0x52, 0x8f, 0x85, 0x76, 0xda, 0xe3, 0xc5, 0x5d, 0xe6, 0xd3, 0x45, 0x6d, - 0x9f, 0x9a, 0x96, 0x43, 0x7d, 0xcb, 0x75, 0x42, 0x57, 0xca, 0x94, 0xb0, 0x04, 0xff, 0xa9, 0xf3, - 0xdf, 0xba, 0x5f, 0x87, 0x09, 0x8a, 0x30, 0xc1, 0xa4, 0x9e, 0xbe, 0x5f, 0xb5, 0x0c, 0x06, 0x63, - 0xd3, 0xc2, 0x18, 0xb7, 0xd1, 0x2b, 0xd4, 0xab, 0xe8, 0xbe, 0xab, 0x1b, 0x46, 0xc3, 0x41, 0xbe, - 0x65, 0x92, 0x5f, 0xa5, 0xc6, 0x43, 0x56, 0x85, 0x71, 0x55, 0x18, 0xb7, 0xa9, 0xe7, 0xeb, 0xbb, - 0xb6, 0x6b, 0x3c, 0xd4, 0x2b, 0xcc, 0x32, 0x2b, 0x7e, 0x0a, 0x4a, 0xb7, 0xe6, 0xb7, 0x3a, 0x11, - 0x91, 0x54, 0xa9, 0xcf, 0x74, 0xdb, 0xda, 0xb3, 0x7c, 0x56, 0xd5, 0x1f, 0xd8, 0xd4, 0xf4, 0x60, - 0xd2, 0x98, 0xe9, 0x9a, 0x2e, 0xff, 0xa9, 0x05, 0xbf, 0xe0, 0xed, 0x84, 0xe9, 0xba, 0xa6, 0xcd, - 0x34, 0xba, 0x6f, 0x69, 0xd4, 0x71, 0x5c, 0x9f, 0x87, 0x07, 0x6c, 0xd4, 0x09, 0xac, 0xdc, 0x0d, - 0x22, 0x78, 0x9f, 0xf9, 0xb4, 0x68, 0x18, 0x6e, 0xcd, 0xf1, 0x2d, 0xc7, 0x2c, 0xb1, 0x47, 0x35, - 0xe6, 0xf9, 0xea, 0x2d, 0xfc, 0x49, 0xea, 0xa8, 0xb7, 0xef, 0x3a, 0x1e, 0x23, 0x05, 0xfc, 0x31, - 0xdd, 0x75, 0xab, 0x3e, 0x2b, 0xeb, 0xc1, 0x3e, 0xe9, 0x74, 0x2f, 0x98, 0x31, 0x8e, 0xce, 0xa3, - 0xd9, 0xd3, 0xa5, 0x51, 0x18, 0xe2, 0xb6, 0x7c, 0xa0, 0xe1, 0x6e, 0x83, 0xf9, 0x77, 0x6a, 0xfe, - 0x4e, 0x7d, 0x27, 0xe4, 0x08, 0xab, 0x91, 0x71, 0xfc, 0x21, 0x67, 0xb8, 0x79, 0x83, 0xbb, 0xc8, - 0x95, 0xa2, 0x47, 0x32, 0x86, 0x07, 0x1c, 0xd7, 0x31, 0xd8, 0x78, 0xff, 0x79, 0x34, 0x7b, 0xaa, - 0x14, 0x3e, 0xa8, 0x35, 0x3c, 0x91, 0xee, 0x0e, 0xe0, 0x7d, 0x1f, 0x0f, 0xbb, 0xc2, 0x7b, 0xee, - 0x74, 0x68, 0x69, 0xbe, 0xd0, 0x36, 0xbb, 0x0a, 0xa2, 0xab, 0xd5, 0x53, 0xaf, 0xfe, 0x3d, 0xd5, - 0x57, 0x8a, 0xb9, 0x51, 0x19, 0xb0, 0x28, 0xda, 0x76, 0x1a, 0x8b, 0x75, 0x8c, 0x9b, 0x59, 0x08, - 0x6b, 0x5e, 0x2a, 0x84, 0x29, 0x5b, 0x08, 0x52, 0xb6, 0x10, 0xa6, 0x3a, 0xa4, 0x6c, 0x61, 0x9b, - 0x9a, 0x0c, 0x6c, 0x4b, 0x82, 0xa5, 0xfa, 0x02, 0x01, 0xbd, 0x96, 0x75, 0x32, 0xe9, 0xe5, 0x7a, - 0x40, 0x8f, 0x6c, 0xc4, 0xf0, 0xf7, 0x73, 0xfc, 0x33, 0x1d, 0xf1, 0x87, 0x98, 0x62, 0x04, 0x9e, - 0x22, 0xac, 0xa6, 0x11, 0x58, 0x3d, 0x58, 0x0b, 0x90, 0x44, 0xf1, 0x1a, 0xc3, 0x03, 0x1c, 0x19, - 0xec, 0x79, 0xf8, 0x90, 0x88, 0x62, 0x7f, 0xd7, 0x51, 0xfc, 0x33, 0xc2, 0xd3, 0x6d, 0x41, 0xbc, - 0x27, 0xc1, 0xfc, 0x31, 0xc2, 0x17, 0x22, 0x1e, 0x9b, 0x4e, 0x56, 0x2c, 0xbf, 0x86, 0x07, 0xc3, - 0xf2, 0x66, 0x95, 0xe3, 0x47, 0xa8, 0xdc, 0xb3, 0x80, 0xfe, 0x41, 0xd8, 0xd5, 0x34, 0x20, 0x10, - 0xcf, 0x12, 0x1e, 0xb2, 0x9c, 0x64, 0x38, 0xe7, 0x3a, 0x84, 0x53, 0xf4, 0x17, 0x46, 0x53, 0x74, - 0xd2, 0xbb, 0x60, 0x0a, 0x27, 0x58, 0x58, 0xd2, 0xeb, 0xf5, 0x09, 0xfe, 0x9d, 0x70, 0x82, 0xe3, - 0xeb, 0xbc, 0x0f, 0x41, 0xba, 0x8e, 0x27, 0xa3, 0xea, 0x1a, 0x2c, 0x79, 0x93, 0x7a, 0x95, 0x1d, - 0x77, 0xcd, 0xf0, 0xeb, 0x51, 0x98, 0x14, 0x3c, 0x68, 0xc1, 0x00, 0x94, 0xfc, 0xc6, 0xb3, 0x7a, - 0x84, 0xf3, 0x59, 0xc6, 0xc0, 0xfd, 0x87, 0xf8, 0xac, 0x15, 0x1b, 0x81, 0x40, 0x2f, 0x48, 0xd0, - 0x6f, 0x1a, 0x41, 0x04, 0x12, 0xae, 0xd4, 0x15, 0x58, 0x3e, 0x3e, 0xf9, 0x06, 0xf5, 0xa9, 0x0c, - 0xf8, 0x27, 0x78, 0x2a, 0xd3, 0x1a, 0xd0, 0xdf, 0xc3, 0x67, 0xd6, 0x02, 0x4c, 0x3c, 0xe9, 0x77, - 0xea, 0x9e, 0x64, 0xbd, 0x10, 0x6d, 0x00, 0x7a, 0xdc, 0x8f, 0x6a, 0x42, 0xd4, 0x21, 0x65, 0x5a, - 0xa3, 0xde, 0xab, 0xe4, 0x7c, 0x89, 0x20, 0x46, 0x29, 0x2b, 0xb5, 0xd9, 0xa2, 0x5c, 0x8f, 0xb6, - 0xa8, 0x77, 0x79, 0xaa, 0xe1, 0xaf, 0x46, 0xa9, 0xb6, 0x41, 0xbd, 0xed, 0xa0, 0x7d, 0x13, 0x3e, - 0x2d, 0x96, 0x53, 0x66, 0x75, 0xd8, 0xe1, 0xf0, 0x41, 0xd5, 0xf1, 0x78, 0xab, 0x01, 0x50, 0x5e, - 0xc3, 0x83, 0xd1, 0x3b, 0x88, 0xed, 0x4c, 0x07, 0xb2, 0x0d, 0x17, 0x0d, 0x43, 0x95, 0x02, 0xa2, - 0xa2, 0x6d, 0x27, 0x11, 0xf5, 0x6a, 0xf7, 0x9e, 0x23, 0x20, 0x11, 0x5b, 0x23, 0x95, 0x44, 0xae, - 0x2b, 0x12, 0xbd, 0xdb, 0x9f, 0xe5, 0x66, 0x29, 0xd8, 0xa2, 0x9e, 0xbf, 0x1a, 0x74, 0xbf, 0x37, - 0x79, 0xf3, 0xdb, 0x7e, 0x9b, 0x0e, 0xe1, 0x14, 0xa6, 0xd9, 0x01, 0xd1, 0x1f, 0xe0, 0x91, 0xc4, - 0x10, 0x84, 0xb4, 0xd0, 0x81, 0x6f, 0xd2, 0x61, 0xd2, 0x8d, 0x5a, 0x69, 0x1e, 0x8e, 0x0c, 0xd0, - 0xbd, 0xda, 0xc9, 0x3f, 0x21, 0xe0, 0x99, 0xb6, 0x54, 0x3b, 0x9e, 0xb9, 0x1e, 0xf0, 0xec, 0xdd, - 0x2e, 0xcf, 0xe3, 0x8f, 0xa3, 0xdd, 0x12, 0xab, 0x55, 0xfa, 0xd6, 0x6e, 0xc1, 0xa5, 0x03, 0x26, - 0xaf, 0x1e, 0xdc, 0x0e, 0xfa, 0xf9, 0x6e, 0xaf, 0x01, 0x26, 0x1e, 0x8b, 0x2f, 0x0d, 0x51, 0xbb, - 0x83, 0x87, 0xc5, 0xda, 0x2a, 0xd9, 0xfe, 0x8b, 0x26, 0xa5, 0x98, 0x03, 0xf5, 0x47, 0xc0, 0xb1, - 0x68, 0xdb, 0xef, 0xa2, 0x22, 0xff, 0x0a, 0x01, 0x91, 0x86, 0xff, 0x4c, 0x22, 0xb9, 0x13, 0x11, - 0xe9, 0xdd, 0xae, 0xdf, 0x86, 0x46, 0x6a, 0xcb, 0xf2, 0xfc, 0x6d, 0xe6, 0x94, 0x2d, 0xc7, 0x14, - 0x23, 0xd3, 0xa6, 0x1d, 0x1d, 0xc3, 0x03, 0xfc, 0x0a, 0xcb, 0x57, 0x3f, 0x53, 0x0a, 0x1f, 0xd4, - 0x67, 0x51, 0xc7, 0xd4, 0xe2, 0xf0, 0x5d, 0x85, 0x42, 0xc5, 0xc3, 0xbe, 0xeb, 0x53, 0x1b, 0x16, - 0x83, 0xcc, 0x8a, 0xbd, 0x53, 0x57, 0xf1, 0x5c, 0x1a, 0xa8, 0x7b, 0x96, 0x5f, 0xb1, 0x9c, 0x12, - 0xf5, 0xd9, 0x56, 0x00, 0x5e, 0x48, 0xf9, 0x90, 0x19, 0x12, 0x99, 0xfd, 0x0d, 0xe1, 0x79, 0x29, - 0x27, 0x40, 0xf4, 0x2e, 0x3e, 0x1b, 0x97, 0x2b, 0xba, 0xa2, 0x6a, 0x88, 0x54, 0xa7, 0xf1, 0x19, - 0x4e, 0x4b, 0xdf, 0xcf, 0xe6, 0x1a, 0x5c, 0xe9, 0x9b, 0xfa, 0x82, 0xce, 0xea, 0x06, 0x63, 0x65, - 0x56, 0x1e, 0xcf, 0x9d, 0x47, 0xb3, 0x83, 0xa5, 0xd1, 0x6a, 0x84, 0xf3, 0x4b, 0x18, 0x68, 0xe8, - 0x07, 0x41, 0x61, 0x09, 0x6e, 0xfa, 0xb1, 0x22, 0xa9, 0x5e, 0x89, 0xf2, 0x23, 0x31, 0x0a, 0x24, - 0xcf, 0xe1, 0x0f, 0x84, 0xb2, 0x9d, 0x2b, 0xc1, 0x93, 0xba, 0x03, 0x59, 0xb0, 0xe6, 0x3a, 0x8f, - 0x59, 0x35, 0xf8, 0x4a, 0xef, 0xb8, 0x81, 0x79, 0x4b, 0x85, 0x68, 0x49, 0x2b, 0x05, 0x0f, 0x9a, - 0xd4, 0xdb, 0x6a, 0x64, 0xd6, 0xe9, 0x52, 0xe3, 0x59, 0xfd, 0x39, 0x82, 0xde, 0xaa, 0xd5, 0x2d, - 0xe0, 0xf9, 0x26, 0x1e, 0x75, 0x6b, 0xfe, 0xae, 0x5b, 0x73, 0xca, 0x1b, 0xd4, 0xdb, 0x74, 0x82, - 0xc1, 0x48, 0xcd, 0x68, 0x19, 0x08, 0x66, 0x73, 0x0d, 0xc5, 0x70, 0xed, 0x75, 0xc6, 0x60, 0x76, - 0xb8, 0x68, 0xeb, 0x00, 0x99, 0xc5, 0x23, 0xc1, 0xbf, 0x62, 0x0d, 0xcf, 0xf1, 0xf8, 0x27, 0x5f, - 0xab, 0x33, 0xf8, 0x22, 0x87, 0x79, 0x8b, 0x79, 0x1e, 0x35, 0xd9, 0x36, 0xf5, 0x3c, 0xcb, 0x31, - 0xb7, 0x9b, 0x1e, 0xa3, 0xe8, 0xae, 0xe3, 0x4b, 0x9d, 0x26, 0x02, 0xb1, 0x09, 0x7c, 0xfa, 0x41, - 0x03, 0x62, 0x48, 0xa8, 0xf9, 0x42, 0xcd, 0x43, 0xb8, 0x1b, 0x59, 0xc8, 0xaa, 0xeb, 0x36, 0x35, - 0xa3, 0xfb, 0x50, 0x70, 0x91, 0x9f, 0xcc, 0x98, 0x00, 0xfe, 0x29, 0xfe, 0xa8, 0x9a, 0x18, 0x83, - 0x42, 0xa8, 0x75, 0xc8, 0xd7, 0xa4, 0x4b, 0xe8, 0x16, 0x5b, 0xdc, 0x2d, 0x3d, 0xbf, 0x80, 0x07, - 0x38, 0x08, 0xf2, 0x12, 0xe1, 0x61, 0xf1, 0xe2, 0x4d, 0xae, 0x75, 0x58, 0xa3, 0x8d, 0xe6, 0xa4, - 0x5c, 0xef, 0xca, 0x36, 0xa4, 0xad, 0x7e, 0xf1, 0xf4, 0xaf, 0xff, 0x7d, 0xd6, 0xff, 0x39, 0xb9, - 0xa2, 0x05, 0xa6, 0x0b, 0x82, 0xca, 0xd8, 0x90, 0xf2, 0x1a, 0x46, 0xda, 0x21, 0x7c, 0xc5, 0x8e, - 0xb4, 0x43, 0xfe, 0xdd, 0x3a, 0x22, 0xbf, 0x45, 0x78, 0x44, 0xf4, 0x5b, 0xb4, 0x6d, 0x39, 0x2e, - 0xe9, 0xca, 0x93, 0x1c, 0x97, 0x0c, 0x35, 0x49, 0x9d, 0xe7, 0x5c, 0x2e, 0x92, 0x69, 0x09, 0x2e, - 0xe4, 0x5f, 0x08, 0x9f, 0x4b, 0x20, 0x07, 0x01, 0x80, 0x14, 0xbb, 0x00, 0x11, 0x57, 0x31, 0x94, - 0xd5, 0x93, 0xb8, 0x00, 0x3a, 0xd7, 0x38, 0x9d, 0xcf, 0xc8, 0x92, 0x04, 0x1d, 0xb0, 0x85, 0x1d, - 0x3a, 0x22, 0xff, 0x44, 0xf8, 0x2b, 0xc2, 0x2d, 0x5b, 0x20, 0xf7, 0x1d, 0x49, 0x64, 0x99, 0x0a, - 0x8d, 0x52, 0x3c, 0x81, 0x07, 0xa0, 0xb6, 0xc2, 0xa9, 0x2d, 0x93, 0xcf, 0x32, 0xa8, 0x59, 0x4e, - 0x06, 0x33, 0xdd, 0x2a, 0x1f, 0x91, 0xdf, 0x20, 0x7c, 0x36, 0x4e, 0x4e, 0x3a, 0xe7, 0x52, 0xb4, - 0x12, 0xe9, 0x9c, 0x4b, 0xd3, 0x3f, 0x3a, 0xe6, 0x9c, 0xc0, 0xc4, 0x23, 0x7f, 0x01, 0xe0, 0xc2, - 0x1d, 0x72, 0x45, 0xf2, 0xf0, 0xa6, 0xde, 0xa4, 0x95, 0x2f, 0xba, 0xb4, 0x06, 0xf0, 0xdf, 0xe2, - 0xe0, 0x97, 0xc8, 0xa7, 0x6d, 0xc0, 0x37, 0xcd, 0xb4, 0xc3, 0xe8, 0xf9, 0x88, 0xfc, 0x1d, 0x61, - 0xd2, 0xaa, 0x2d, 0x10, 0x29, 0x3c, 0x99, 0x8a, 0x86, 0xf2, 0xed, 0x6e, 0xcd, 0x81, 0x4f, 0x91, - 0xf3, 0xb9, 0x4e, 0xae, 0x66, 0xf2, 0x49, 0xfe, 0x07, 0x88, 0x5e, 0xa6, 0x3e, 0x15, 0x89, 0xfd, - 0x1e, 0xe1, 0xd1, 0xf8, 0x0a, 0x41, 0x7a, 0xad, 0x1c, 0x23, 0x45, 0xba, 0xdc, 0xa5, 0x4c, 0x0d, - 0x43, 0x5d, 0xe0, 0xac, 0x66, 0xc8, 0x45, 0xa9, 0x5d, 0x22, 0xbf, 0x44, 0xcd, 0xbb, 0x33, 0x59, - 0x96, 0x4c, 0x90, 0xc4, 0x25, 0x5f, 0xf9, 0xfc, 0xd8, 0x76, 0x00, 0x56, 0xe3, 0x60, 0xbf, 0x41, - 0x66, 0x32, 0xc0, 0x9a, 0x60, 0x10, 0xc4, 0xbc, 0xcc, 0xea, 0x47, 0xe4, 0x17, 0x08, 0x0f, 0x45, - 0x5e, 0x82, 0x50, 0x2f, 0x4b, 0x06, 0xab, 0x2b, 0xc4, 0x29, 0x52, 0x83, 0x3a, 0xc3, 0x11, 0x5f, - 0x20, 0x53, 0x1d, 0x10, 0x93, 0x17, 0x08, 0x7f, 0x94, 0xec, 0xbb, 0x88, 0x54, 0xf1, 0xc8, 0x68, - 0x02, 0x95, 0x95, 0xee, 0x8c, 0x25, 0x43, 0x6d, 0x24, 0xb1, 0xbe, 0x44, 0x78, 0x48, 0x68, 0xad, - 0xc8, 0x0d, 0x99, 0xe5, 0x3b, 0xb5, 0x70, 0xca, 0x97, 0x27, 0xf4, 0x02, 0x6c, 0xe6, 0x38, 0x9b, - 0xaf, 0x13, 0x35, 0x83, 0x8d, 0xd0, 0x8e, 0x92, 0x57, 0xa8, 0x45, 0x4d, 0x20, 0xb2, 0xa5, 0x30, - 0x5d, 0x0b, 0x91, 0x2b, 0x3d, 0xd9, 0x3a, 0x8e, 0xba, 0xcc, 0xe1, 0x7f, 0x4a, 0x0a, 0x19, 0xf0, - 0xed, 0xb8, 0x5d, 0x23, 0xfd, 0xff, 0x88, 0x30, 0x49, 0xf8, 0x0c, 0x4e, 0x81, 0x6c, 0xc9, 0x38, - 0x09, 0x9b, 0x6c, 0xb5, 0x46, 0x2d, 0x70, 0x36, 0xb3, 0xe4, 0x92, 0x1c, 0x1b, 0xf2, 0x33, 0x84, - 0x4f, 0xf1, 0xe2, 0xb3, 0x24, 0x19, 0x46, 0xb1, 0x3c, 0x5e, 0x3e, 0x96, 0x8d, 0xe4, 0x77, 0xd7, - 0x80, 0x0f, 0x16, 0x0f, 0xf2, 0xaf, 0x11, 0x1e, 0x12, 0x54, 0x1a, 0x72, 0xf5, 0x18, 0x2b, 0xc6, - 0x95, 0x9d, 0xee, 0xc0, 0x5e, 0xe1, 0x60, 0x35, 0xb2, 0xd0, 0x16, 0x6c, 0x4b, 0x73, 0xfd, 0x53, - 0x84, 0x3f, 0x8c, 0xbe, 0x40, 0x4b, 0x92, 0x3b, 0x7a, 0xec, 0xc0, 0x26, 0x94, 0x1a, 0x75, 0x9a, - 0x63, 0x9d, 0x24, 0x9f, 0xb4, 0xc1, 0x1a, 0x74, 0x60, 0x23, 0x09, 0x15, 0x40, 0xae, 0x05, 0x4b, - 0x57, 0x59, 0xe4, 0x5a, 0xb0, 0x0c, 0x41, 0xa5, 0x73, 0xe5, 0x10, 0x40, 0xfe, 0x0f, 0xe1, 0x7c, - 0x7b, 0xf9, 0x82, 0x6c, 0x76, 0x81, 0x25, 0x5d, 0x47, 0x51, 0xbe, 0xdb, 0x0b, 0x57, 0xc0, 0xf2, - 0x2a, 0x67, 0x79, 0x99, 0x2c, 0x76, 0x66, 0x99, 0x64, 0x14, 0xf4, 0xcb, 0xf1, 0x3f, 0x7f, 0x90, - 0x3b, 0x01, 0xa9, 0x7f, 0x50, 0xa1, 0x5c, 0xeb, 0xc6, 0x54, 0xb2, 0x95, 0x79, 0x12, 0x47, 0x19, - 0x00, 0x8f, 0xeb, 0x2e, 0x72, 0xc0, 0x53, 0x95, 0x1c, 0x39, 0xe0, 0xe9, 0x32, 0x4f, 0x47, 0xe0, - 0x76, 0x1c, 0x65, 0xd0, 0x2a, 0x24, 0x65, 0x01, 0xb9, 0x56, 0x21, 0x43, 0xc0, 0x90, 0x6b, 0x15, - 0xb2, 0xc4, 0x8d, 0x8e, 0xad, 0x42, 0x52, 0xaa, 0x58, 0xfd, 0xde, 0xab, 0x37, 0x79, 0xf4, 0xfa, - 0x4d, 0x1e, 0xfd, 0xe7, 0x4d, 0x1e, 0xfd, 0xe4, 0x6d, 0xbe, 0xef, 0xf5, 0xdb, 0x7c, 0xdf, 0x3f, - 0xde, 0xe6, 0xfb, 0xee, 0x2f, 0x9a, 0x96, 0x5f, 0xa9, 0xed, 0x16, 0x0c, 0x77, 0x4f, 0x74, 0x16, - 0x61, 0xd2, 0xea, 0xa2, 0x5f, 0xff, 0x60, 0x9f, 0x79, 0xbb, 0x1f, 0xf0, 0x6f, 0xf7, 0xe5, 0xff, - 0x07, 0x00, 0x00, 0xff, 0xff, 0x25, 0x12, 0xcf, 0x1a, 0x2c, 0x25, 0x00, 0x00, + // 1931 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5a, 0x41, 0x6f, 0xdc, 0xc6, + 0x15, 0xf6, 0x68, 0xed, 0x44, 0x1e, 0xc9, 0x56, 0x34, 0x51, 0x5d, 0x95, 0x91, 0x56, 0x36, 0x55, + 0x5b, 0xaa, 0x54, 0x2d, 0x23, 0x39, 0x56, 0x6a, 0x5b, 0x29, 0xba, 0x92, 0x23, 0x45, 0xad, 0x92, + 0x28, 0x0b, 0x15, 0x2e, 0x5c, 0x14, 0xc4, 0x88, 0x3b, 0xe1, 0x12, 0xa1, 0x48, 0x65, 0x39, 0x6b, + 0xaf, 0x2c, 0xe8, 0x12, 0xa0, 0x3d, 0x17, 0xc8, 0xa1, 0x97, 0x5e, 0x8b, 0xe6, 0xd0, 0x43, 0x0f, + 0x45, 0x7b, 0x28, 0x90, 0xa2, 0x68, 0xeb, 0xfa, 0x18, 0xa0, 0x40, 0x51, 0xb4, 0x40, 0x51, 0xd8, + 0xfd, 0x05, 0xfd, 0x05, 0x05, 0x87, 0x8f, 0xbb, 0x43, 0x2e, 0xb9, 0x3b, 0x5a, 0x6d, 0x0e, 0x3e, + 0x79, 0xc9, 0x99, 0xf7, 0xe6, 0xfb, 0xde, 0xbc, 0x79, 0x7c, 0xf3, 0x59, 0xf8, 0x8a, 0x55, 0xf7, + 0x83, 0xc0, 0xaa, 0x51, 0xc7, 0x33, 0x3e, 0x6e, 0xb0, 0xfa, 0x51, 0xe9, 0xb0, 0xee, 0x73, 0x9f, + 0x4c, 0x3f, 0x66, 0x9c, 0x8a, 0xd7, 0x25, 0xf1, 0xcb, 0xaf, 0xb3, 0x52, 0x7b, 0xaa, 0xb6, 0x60, + 0xf9, 0xc1, 0x81, 0x1f, 0x18, 0xfb, 0x34, 0x60, 0x91, 0x9d, 0xf1, 0x70, 0x79, 0x9f, 0x71, 0xba, + 0x6c, 0x1c, 0x52, 0xdb, 0xf1, 0x28, 0x77, 0x7c, 0x2f, 0x72, 0xa5, 0xcd, 0x48, 0x4b, 0x88, 0x9f, + 0xa6, 0xf8, 0x6d, 0xf2, 0x26, 0x4c, 0xd0, 0xa4, 0x09, 0x36, 0x0d, 0xcc, 0xc3, 0xba, 0x63, 0x31, + 0x18, 0x9b, 0x95, 0xc6, 0x84, 0x8d, 0x59, 0xa3, 0x41, 0xcd, 0xe4, 0xbe, 0x69, 0x59, 0x2d, 0x07, + 0xc5, 0x8e, 0x49, 0xbc, 0x4e, 0xad, 0x8f, 0x58, 0x1d, 0xc6, 0x75, 0x69, 0xdc, 0xa5, 0x01, 0x37, + 0xf7, 0x5d, 0xdf, 0xfa, 0xc8, 0xac, 0x31, 0xc7, 0xae, 0xf1, 0x0c, 0x94, 0x7e, 0x83, 0x77, 0x3a, + 0x91, 0x91, 0xd4, 0x29, 0x67, 0xa6, 0xeb, 0x1c, 0x38, 0x9c, 0xd5, 0xcd, 0x0f, 0x5d, 0x6a, 0x07, + 0x30, 0x69, 0xc2, 0xf6, 0x6d, 0x5f, 0xfc, 0x34, 0xc2, 0x5f, 0xf0, 0x76, 0xca, 0xf6, 0x7d, 0xdb, + 0x65, 0x06, 0x3d, 0x74, 0x0c, 0xea, 0x79, 0x3e, 0x17, 0xe1, 0x01, 0x1b, 0x7d, 0x0a, 0x6b, 0x1f, + 0x84, 0x11, 0x7c, 0xc0, 0x38, 0x2d, 0x5b, 0x96, 0xdf, 0xf0, 0xb8, 0xe3, 0xd9, 0x15, 0xf6, 0x71, + 0x83, 0x05, 0x5c, 0x7f, 0x17, 0xbf, 0x96, 0x39, 0x1a, 0x1c, 0xfa, 0x5e, 0xc0, 0x48, 0x09, 0xbf, + 0x4a, 0xf7, 0xfd, 0x3a, 0x67, 0x55, 0x33, 0xdc, 0x27, 0x93, 0x1e, 0x84, 0x33, 0x26, 0xd1, 0x55, + 0x34, 0x7f, 0xb1, 0x32, 0x0e, 0x43, 0xc2, 0x56, 0x0c, 0xb4, 0xdc, 0x6d, 0x31, 0xfe, 0x7e, 0x83, + 0xef, 0x35, 0xf7, 0x22, 0x8e, 0xb0, 0x1a, 0x99, 0xc4, 0x2f, 0x0b, 0x86, 0xdb, 0xf7, 0x84, 0x8b, + 0x42, 0x25, 0x7e, 0x24, 0x13, 0xf8, 0x82, 0xe7, 0x7b, 0x16, 0x9b, 0x1c, 0xba, 0x8a, 0xe6, 0xcf, + 0x57, 0xa2, 0x07, 0xbd, 0x81, 0xa7, 0xb2, 0xdd, 0x01, 0xbc, 0xef, 0xe3, 0x51, 0x5f, 0x7a, 0x2f, + 0x9c, 0x8e, 0xac, 0x2c, 0x96, 0xba, 0x66, 0x57, 0x49, 0x76, 0xb5, 0x7e, 0xfe, 0xe9, 0xbf, 0x67, + 0xce, 0x55, 0x12, 0x6e, 0x74, 0x06, 0x2c, 0xca, 0xae, 0x9b, 0xc5, 0x62, 0x13, 0xe3, 0x76, 0x16, + 0xc2, 0x9a, 0x37, 0x4a, 0x51, 0xca, 0x96, 0xc2, 0x94, 0x2d, 0x45, 0xa9, 0x0e, 0x29, 0x5b, 0xda, + 0xa5, 0x36, 0x03, 0xdb, 0x8a, 0x64, 0xa9, 0x7f, 0x8e, 0x80, 0x5e, 0xc7, 0x3a, 0xb9, 0xf4, 0x0a, + 0x03, 0xa0, 0x47, 0xb6, 0x12, 0xf8, 0x87, 0x04, 0xfe, 0xb9, 0x9e, 0xf8, 0x23, 0x4c, 0x09, 0x02, + 0x9f, 0x20, 0xac, 0x67, 0x11, 0x58, 0x3f, 0xda, 0x08, 0x91, 0xc4, 0xf1, 0x9a, 0xc0, 0x17, 0x04, + 0x32, 0xd8, 0xf3, 0xe8, 0x21, 0x15, 0xc5, 0xa1, 0xbe, 0xa3, 0xf8, 0x17, 0x84, 0x67, 0xbb, 0x82, + 0x78, 0x41, 0x82, 0xf9, 0x13, 0x84, 0xaf, 0xc5, 0x3c, 0xb6, 0xbd, 0xbc, 0x58, 0x7e, 0x0d, 0x0f, + 0x47, 0xe5, 0xcd, 0xa9, 0x26, 0x8f, 0x50, 0x75, 0x60, 0x01, 0xfd, 0xa3, 0xb4, 0xab, 0x59, 0x40, + 0x20, 0x9e, 0x15, 0x3c, 0xe2, 0x78, 0xe9, 0x70, 0x2e, 0xf4, 0x08, 0xa7, 0xec, 0x2f, 0x8a, 0xa6, + 0xec, 0x64, 0x70, 0xc1, 0x94, 0x4e, 0xb0, 0xb4, 0x64, 0x30, 0xe8, 0x13, 0xfc, 0x7b, 0xe9, 0x04, + 0x27, 0xd7, 0x79, 0x11, 0x82, 0x74, 0x17, 0x4f, 0xc7, 0xd5, 0x35, 0x5c, 0xf2, 0x1d, 0x1a, 0xd4, + 0xf6, 0xfc, 0x0d, 0x8b, 0x37, 0xe3, 0x30, 0x69, 0x78, 0xd8, 0x81, 0x01, 0x28, 0xf9, 0xad, 0x67, + 0xfd, 0x04, 0x17, 0xf3, 0x8c, 0x81, 0xfb, 0x0f, 0xf1, 0x65, 0x27, 0x31, 0x02, 0x81, 0x5e, 0x52, + 0xa0, 0xdf, 0x36, 0x82, 0x08, 0xa4, 0x5c, 0xe9, 0x6b, 0xb0, 0x7c, 0x72, 0xf2, 0x3d, 0xca, 0xa9, + 0x0a, 0xf8, 0xc7, 0x78, 0x26, 0xd7, 0x1a, 0xd0, 0xdf, 0xc7, 0x97, 0x36, 0x42, 0x4c, 0x22, 0xe9, + 0xf7, 0x9a, 0x81, 0x62, 0xbd, 0x90, 0x6d, 0x00, 0x7a, 0xd2, 0x8f, 0x6e, 0x43, 0xd4, 0x21, 0x65, + 0x3a, 0xa3, 0x3e, 0xa8, 0xe4, 0x7c, 0x82, 0x20, 0x46, 0x19, 0x2b, 0x75, 0xd9, 0xa2, 0xc2, 0x80, + 0xb6, 0x68, 0x70, 0x79, 0x6a, 0xe0, 0xaf, 0xc6, 0xa9, 0xb6, 0x45, 0x83, 0xdd, 0xb0, 0x7d, 0x93, + 0x3e, 0x2d, 0x8e, 0x57, 0x65, 0x4d, 0xd8, 0xe1, 0xe8, 0x41, 0x37, 0xf1, 0x64, 0xa7, 0x01, 0x50, + 0xde, 0xc0, 0xc3, 0xf1, 0x3b, 0x88, 0xed, 0x5c, 0x0f, 0xb2, 0x2d, 0x17, 0x2d, 0x43, 0x9d, 0x02, + 0xa2, 0xb2, 0xeb, 0xa6, 0x11, 0x0d, 0x6a, 0xf7, 0x3e, 0x43, 0x40, 0x22, 0xb1, 0x46, 0x26, 0x89, + 0x42, 0x5f, 0x24, 0x06, 0xb7, 0x3f, 0xab, 0xed, 0x52, 0xb0, 0x43, 0x03, 0xbe, 0x1e, 0x76, 0xbf, + 0xef, 0x88, 0xe6, 0xb7, 0xfb, 0x36, 0x1d, 0xc3, 0x29, 0xcc, 0xb2, 0x03, 0xa2, 0x3f, 0xc0, 0x63, + 0xa9, 0x21, 0x08, 0x69, 0xa9, 0x07, 0xdf, 0xb4, 0xc3, 0xb4, 0x1b, 0xbd, 0xd6, 0x3e, 0x1c, 0x39, + 0xa0, 0x07, 0xb5, 0x93, 0x7f, 0x46, 0xc0, 0x33, 0x6b, 0xa9, 0x6e, 0x3c, 0x0b, 0x03, 0xe0, 0x39, + 0xb8, 0x5d, 0x5e, 0xc4, 0xaf, 0xc6, 0xbb, 0x25, 0x57, 0xab, 0xec, 0xad, 0xdd, 0x81, 0x4b, 0x07, + 0x4c, 0x5e, 0x3f, 0x7a, 0x2f, 0xec, 0xe7, 0xfb, 0xbd, 0x06, 0xd8, 0x78, 0x22, 0xb9, 0x34, 0x44, + 0xed, 0x7d, 0x3c, 0x2a, 0xd7, 0x56, 0xc5, 0xf6, 0x5f, 0x36, 0xa9, 0x24, 0x1c, 0xe8, 0x3f, 0x02, + 0x8e, 0x65, 0xd7, 0xfd, 0x32, 0x2a, 0xf2, 0xaf, 0x11, 0x10, 0x69, 0xf9, 0xcf, 0x25, 0x52, 0x38, + 0x13, 0x91, 0xc1, 0xed, 0xfa, 0x7b, 0xd0, 0x48, 0xed, 0x38, 0x01, 0xdf, 0x65, 0x5e, 0xd5, 0xf1, + 0x6c, 0x39, 0x32, 0x5d, 0xda, 0xd1, 0x09, 0x7c, 0x41, 0x5c, 0x61, 0xc5, 0xea, 0x97, 0x2a, 0xd1, + 0x83, 0xfe, 0x69, 0xdc, 0x31, 0x75, 0x38, 0xfc, 0xb2, 0x42, 0xa1, 0xe3, 0x51, 0xee, 0x73, 0xea, + 0xc2, 0x62, 0x90, 0x59, 0x89, 0x77, 0xfa, 0x3a, 0x5e, 0xc8, 0x02, 0x75, 0xdf, 0xe1, 0x35, 0xc7, + 0xab, 0x50, 0xce, 0x76, 0x42, 0xf0, 0x52, 0xca, 0x47, 0xcc, 0x90, 0xcc, 0xec, 0xc7, 0x43, 0x78, + 0x51, 0xc9, 0x09, 0x10, 0xfd, 0x00, 0x5f, 0x4e, 0xca, 0x15, 0x7d, 0x51, 0xb5, 0x64, 0xaa, 0xb3, + 0xf8, 0x92, 0xa0, 0x65, 0x1e, 0xe6, 0x73, 0x0d, 0xaf, 0xf4, 0x0f, 0xa9, 0xdb, 0x60, 0xe6, 0x23, + 0x01, 0xcc, 0x7c, 0xe4, 0x78, 0x55, 0xff, 0xd1, 0x64, 0x41, 0x4c, 0x1d, 0x17, 0x43, 0x11, 0xe4, + 0xfb, 0x62, 0x20, 0x9c, 0xdf, 0xd6, 0x23, 0x4c, 0xd6, 0xb4, 0x18, 0xab, 0xb2, 0xea, 0xe4, 0xf9, + 0xab, 0x68, 0x7e, 0xb8, 0x32, 0x5e, 0x8f, 0x79, 0xbd, 0x0d, 0x03, 0x2d, 0xbd, 0x21, 0x2c, 0x44, + 0x0f, 0x18, 0xa7, 0x89, 0xa2, 0xaa, 0xdf, 0x8a, 0xf3, 0x29, 0x35, 0x0a, 0x41, 0xb9, 0x82, 0x5f, + 0x92, 0xca, 0x7c, 0xa1, 0x02, 0x4f, 0xfa, 0x1e, 0x64, 0xcd, 0x86, 0xef, 0x3d, 0x64, 0xf5, 0xf0, + 0xab, 0xbe, 0xe7, 0x87, 0xe6, 0x1d, 0x15, 0xa5, 0x23, 0x0d, 0x35, 0x3c, 0x6c, 0xd3, 0x60, 0xa7, + 0x95, 0x89, 0x17, 0x2b, 0xad, 0x67, 0xfd, 0x17, 0x08, 0x7a, 0xb1, 0x4e, 0xb7, 0x80, 0xe7, 0x9b, + 0x78, 0xdc, 0x6f, 0xf0, 0x7d, 0xbf, 0xe1, 0x55, 0xb7, 0x68, 0xb0, 0xed, 0x85, 0x83, 0xb1, 0xfa, + 0xd1, 0x31, 0x10, 0xce, 0x16, 0x9a, 0x8b, 0xe5, 0xbb, 0x9b, 0x8c, 0xc1, 0xec, 0x68, 0xd1, 0xce, + 0x01, 0x32, 0x8f, 0xc7, 0xc2, 0x7f, 0xe5, 0x9a, 0x1f, 0x6d, 0x42, 0xfa, 0xb5, 0x3e, 0x87, 0xaf, + 0x0b, 0x98, 0xef, 0xb2, 0x20, 0xa0, 0x36, 0xdb, 0xa5, 0x41, 0xe0, 0x78, 0xf6, 0x6e, 0xdb, 0x63, + 0x1c, 0xdd, 0x4d, 0x7c, 0xa3, 0xd7, 0x44, 0x20, 0x36, 0x85, 0x2f, 0x7e, 0xd8, 0x82, 0x18, 0x11, + 0x6a, 0xbf, 0xd0, 0x8b, 0x10, 0xee, 0x56, 0xd6, 0xb2, 0xfa, 0xa6, 0x4b, 0xed, 0xf8, 0xfe, 0x14, + 0x5e, 0xfc, 0xa7, 0x73, 0x26, 0x80, 0x7f, 0x8a, 0x5f, 0xa9, 0xa7, 0xc6, 0xa0, 0x70, 0x1a, 0x3d, + 0xf2, 0x3b, 0xed, 0x12, 0xba, 0xcb, 0x0e, 0x77, 0x2b, 0x9f, 0x5d, 0xc3, 0x17, 0x04, 0x08, 0xf2, + 0x04, 0xe1, 0x51, 0xf9, 0xa2, 0x4e, 0xee, 0xf4, 0x58, 0xa3, 0x8b, 0x46, 0xa5, 0xdd, 0xed, 0xcb, + 0x36, 0xa2, 0xad, 0xbf, 0xf5, 0xc9, 0xdf, 0xfe, 0xfb, 0xe9, 0xd0, 0x9b, 0xe4, 0x96, 0x11, 0x9a, + 0x2e, 0x49, 0xaa, 0x64, 0x4b, 0xfa, 0x6b, 0x19, 0x19, 0xc7, 0xf0, 0xd5, 0x3b, 0x31, 0x8e, 0xc5, + 0x77, 0xee, 0x84, 0xfc, 0x0e, 0xe1, 0x31, 0xd9, 0x6f, 0xd9, 0x75, 0xd5, 0xb8, 0x64, 0x2b, 0x55, + 0x6a, 0x5c, 0x72, 0xd4, 0x27, 0x7d, 0x51, 0x70, 0xb9, 0x4e, 0x66, 0x15, 0xb8, 0x90, 0x7f, 0x21, + 0x7c, 0x25, 0x85, 0x1c, 0x04, 0x03, 0x52, 0xee, 0x03, 0x44, 0x52, 0xf5, 0xd0, 0xd6, 0xcf, 0xe2, + 0x02, 0xe8, 0xdc, 0x11, 0x74, 0xde, 0x20, 0x2b, 0x0a, 0x74, 0xc0, 0x16, 0x76, 0xe8, 0x84, 0xfc, + 0x13, 0xe1, 0xaf, 0x48, 0xb7, 0x72, 0x89, 0xdc, 0x77, 0x14, 0x91, 0xe5, 0x2a, 0x3a, 0x5a, 0xf9, + 0x0c, 0x1e, 0x80, 0xda, 0x9a, 0xa0, 0xb6, 0x4a, 0xde, 0xc8, 0xa1, 0xe6, 0x78, 0x39, 0xcc, 0x4c, + 0xa7, 0x7a, 0x42, 0x7e, 0x8b, 0xf0, 0xe5, 0x24, 0x39, 0xe5, 0x9c, 0xcb, 0xd0, 0x56, 0x94, 0x73, + 0x2e, 0x4b, 0x2f, 0xe9, 0x99, 0x73, 0x12, 0x93, 0x80, 0xfc, 0x15, 0x80, 0x4b, 0x77, 0xce, 0x35, + 0xc5, 0xc3, 0x9b, 0x79, 0xf3, 0xd6, 0xde, 0xea, 0xd3, 0x1a, 0xc0, 0x7f, 0x4b, 0x80, 0x5f, 0x21, + 0xaf, 0x77, 0x01, 0xdf, 0x36, 0x33, 0x8e, 0xe3, 0xe7, 0x13, 0xf2, 0x77, 0x84, 0x49, 0xa7, 0x16, + 0x41, 0x94, 0xf0, 0xe4, 0x2a, 0x20, 0xda, 0xb7, 0xfb, 0x35, 0x07, 0x3e, 0x65, 0xc1, 0xe7, 0x2e, + 0xb9, 0x9d, 0xcb, 0x27, 0xfd, 0x1f, 0x26, 0x66, 0x95, 0x72, 0x2a, 0x13, 0xfb, 0x03, 0xc2, 0xe3, + 0xc9, 0x15, 0xc2, 0xf4, 0x5a, 0x3b, 0x45, 0x8a, 0xf4, 0xb9, 0x4b, 0xb9, 0x9a, 0x87, 0xbe, 0x24, + 0x58, 0xcd, 0x91, 0xeb, 0x4a, 0xbb, 0x44, 0x7e, 0x85, 0xda, 0x77, 0x6d, 0xb2, 0xaa, 0x98, 0x20, + 0x29, 0x51, 0x40, 0x7b, 0xf3, 0xd4, 0x76, 0x00, 0xd6, 0x10, 0x60, 0xbf, 0x41, 0xe6, 0x72, 0xc0, + 0xda, 0x60, 0x10, 0xc6, 0xbc, 0xca, 0x9a, 0x27, 0xe4, 0x97, 0x08, 0x8f, 0xc4, 0x5e, 0xc2, 0x50, + 0xaf, 0x2a, 0x06, 0xab, 0x2f, 0xc4, 0x19, 0xd2, 0x84, 0x3e, 0x27, 0x10, 0x5f, 0x23, 0x33, 0x3d, + 0x10, 0x93, 0xcf, 0x11, 0x7e, 0x25, 0xdd, 0x77, 0x11, 0xa5, 0xe2, 0x91, 0xd3, 0x04, 0x6a, 0x6b, + 0xfd, 0x19, 0x2b, 0x86, 0xda, 0x4a, 0x63, 0x7d, 0x82, 0xf0, 0x88, 0xd4, 0x5a, 0x91, 0x7b, 0x2a, + 0xcb, 0xf7, 0x6a, 0xe1, 0xb4, 0xb7, 0xcf, 0xe8, 0x05, 0xd8, 0x2c, 0x08, 0x36, 0x5f, 0x27, 0x7a, + 0x0e, 0x1b, 0xa9, 0x1d, 0x25, 0x4f, 0x51, 0x87, 0xfa, 0x40, 0x54, 0x4b, 0x61, 0xb6, 0x76, 0xa2, + 0x56, 0x7a, 0xf2, 0x75, 0x1f, 0x7d, 0x55, 0xc0, 0x7f, 0x9d, 0x94, 0x72, 0xe0, 0xbb, 0x49, 0xbb, + 0x56, 0xfa, 0xff, 0x09, 0x61, 0x92, 0xf2, 0x19, 0x9e, 0x02, 0xd5, 0x92, 0x71, 0x16, 0x36, 0xf9, + 0xea, 0x8e, 0x5e, 0x12, 0x6c, 0xe6, 0xc9, 0x0d, 0x35, 0x36, 0xe4, 0xe7, 0x08, 0x9f, 0x17, 0xc5, + 0x67, 0x45, 0x31, 0x8c, 0x72, 0x79, 0xbc, 0x79, 0x2a, 0x1b, 0xc5, 0xef, 0xae, 0x05, 0x1f, 0x2c, + 0x11, 0xe4, 0xdf, 0x20, 0x3c, 0x22, 0xa9, 0x3a, 0xe4, 0xf6, 0x29, 0x56, 0x4c, 0x2a, 0x41, 0xfd, + 0x81, 0xbd, 0x25, 0xc0, 0x1a, 0x64, 0xa9, 0x2b, 0xd8, 0x8e, 0xe6, 0xfa, 0x67, 0x08, 0xbf, 0x1c, + 0x7f, 0x81, 0x56, 0x14, 0x77, 0xf4, 0xd4, 0x81, 0x4d, 0x29, 0x3b, 0xfa, 0xac, 0xc0, 0x3a, 0x4d, + 0x5e, 0xeb, 0x82, 0x35, 0xec, 0xc0, 0xc6, 0x52, 0xaa, 0x81, 0x5a, 0x0b, 0x96, 0xad, 0xca, 0xa8, + 0xb5, 0x60, 0x39, 0x02, 0x4c, 0xef, 0xca, 0x21, 0x81, 0xfc, 0x1f, 0xc2, 0xc5, 0xee, 0x72, 0x07, + 0xd9, 0xee, 0x03, 0x4b, 0xb6, 0xee, 0xa2, 0x7d, 0x77, 0x10, 0xae, 0x80, 0xe5, 0x6d, 0xc1, 0xf2, + 0x26, 0x59, 0xee, 0xcd, 0x32, 0xcd, 0x28, 0xec, 0x97, 0x93, 0x7f, 0x2e, 0xa1, 0x76, 0x02, 0x32, + 0xff, 0x00, 0x43, 0xbb, 0xd3, 0x8f, 0xa9, 0x62, 0x2b, 0xf3, 0x38, 0x89, 0x32, 0x04, 0x9e, 0xd4, + 0x5d, 0xd4, 0x80, 0x67, 0x2a, 0x39, 0x6a, 0xc0, 0xb3, 0x65, 0x9e, 0x9e, 0xc0, 0xdd, 0x24, 0xca, + 0xb0, 0x55, 0x48, 0xcb, 0x02, 0x6a, 0xad, 0x42, 0x8e, 0x80, 0xa1, 0xd6, 0x2a, 0xe4, 0x89, 0x1b, + 0x3d, 0x5b, 0x85, 0xb4, 0x54, 0xb1, 0xfe, 0xbd, 0xa7, 0xcf, 0x8a, 0xe8, 0x8b, 0x67, 0x45, 0xf4, + 0x9f, 0x67, 0x45, 0xf4, 0xd3, 0xe7, 0xc5, 0x73, 0x5f, 0x3c, 0x2f, 0x9e, 0xfb, 0xc7, 0xf3, 0xe2, + 0xb9, 0x07, 0xcb, 0xb6, 0xc3, 0x6b, 0x8d, 0xfd, 0x92, 0xe5, 0x1f, 0xc8, 0xce, 0x62, 0x4c, 0x46, + 0x53, 0xf6, 0xcb, 0x8f, 0x0e, 0x59, 0xb0, 0xff, 0x92, 0xf8, 0x76, 0xdf, 0xfc, 0x7f, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xc1, 0x55, 0xea, 0xa0, 0x5c, 0x25, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -4382,6 +4392,11 @@ func (m *QueryListPendingCctxWithinRateLimitResponse) MarshalToSizedBuffer(dAtA dAtA[i] = 0 } i-- + dAtA[i] = 0x20 + } + if m.ValueWithinWindow != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.ValueWithinWindow)) + i-- dAtA[i] = 0x18 } if m.TotalPending != 0 { @@ -5169,6 +5184,9 @@ func (m *QueryListPendingCctxWithinRateLimitResponse) Size() (n int) { if m.TotalPending != 0 { n += 1 + sovQuery(uint64(m.TotalPending)) } + if m.ValueWithinWindow != 0 { + n += 1 + sovQuery(uint64(m.ValueWithinWindow)) + } if m.RateLimitExceeded { n += 2 } @@ -8535,6 +8553,25 @@ func (m *QueryListPendingCctxWithinRateLimitResponse) Unmarshal(dAtA []byte) err } } case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ValueWithinWindow", wireType) + } + m.ValueWithinWindow = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ValueWithinWindow |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field RateLimitExceeded", wireType) } diff --git a/zetaclient/interfaces/interfaces.go b/zetaclient/interfaces/interfaces.go index 0fbaba26b3..a122a19131 100644 --- a/zetaclient/interfaces/interfaces.go +++ b/zetaclient/interfaces/interfaces.go @@ -98,7 +98,7 @@ type ZetaCoreBridger interface { GetZetaBlockHeight() (int64, error) GetLastBlockHeightByChain(chain chains.Chain) (*crosschaintypes.LastBlockHeight, error) ListPendingCctx(chainID int64) ([]*crosschaintypes.CrossChainTx, uint64, error) - ListPendingCctxWithinRatelimit() ([]*crosschaintypes.CrossChainTx, uint64, bool, error) + ListPendingCctxWithinRatelimit() ([]*crosschaintypes.CrossChainTx, uint64, uint64, bool, error) GetPendingNoncesByChain(chainID int64) (observertypes.PendingNonces, error) GetCctxByNonce(chainID int64, nonce uint64) (*crosschaintypes.CrossChainTx, error) GetOutTxTracker(chain chains.Chain, nonce uint64) (*crosschaintypes.OutTxTracker, error) diff --git a/zetaclient/testutils/stub/core_bridge.go b/zetaclient/testutils/stub/core_bridge.go index e66c309cc6..ca3f45a16b 100644 --- a/zetaclient/testutils/stub/core_bridge.go +++ b/zetaclient/testutils/stub/core_bridge.go @@ -121,11 +121,11 @@ func (z *MockZetaCoreBridge) ListPendingCctx(_ int64) ([]*cctxtypes.CrossChainTx return []*cctxtypes.CrossChainTx{}, 0, nil } -func (z *MockZetaCoreBridge) ListPendingCctxWithinRatelimit() ([]*cctxtypes.CrossChainTx, uint64, bool, error) { +func (z *MockZetaCoreBridge) ListPendingCctxWithinRatelimit() ([]*cctxtypes.CrossChainTx, uint64, uint64, bool, error) { if z.paused { - return nil, 0, false, errors.New(ErrMsgPaused) + return nil, 0, 0, false, errors.New(ErrMsgPaused) } - return []*cctxtypes.CrossChainTx{}, 0, false, nil + return []*cctxtypes.CrossChainTx{}, 0, 0, false, nil } func (z *MockZetaCoreBridge) GetPendingNoncesByChain(_ int64) (observerTypes.PendingNonces, error) { diff --git a/zetaclient/zetabridge/query.go b/zetaclient/zetabridge/query.go index 09d3b20e82..afed840fef 100644 --- a/zetaclient/zetabridge/query.go +++ b/zetaclient/zetabridge/query.go @@ -139,7 +139,7 @@ func (b *ZetaCoreBridge) ListPendingCctx(chainID int64) ([]*types.CrossChainTx, // ListPendingCctxWithinRatelimit returns a list of pending cctxs that do not exceed the outbound rate limit // - The max size of the list is crosschainkeeper.MaxPendingCctxs // - The returned `rateLimitExceeded` flag indicates if the rate limit is exceeded or not -func (b *ZetaCoreBridge) ListPendingCctxWithinRatelimit() ([]*types.CrossChainTx, uint64, bool, error) { +func (b *ZetaCoreBridge) ListPendingCctxWithinRatelimit() ([]*types.CrossChainTx, uint64, uint64, bool, error) { client := types.NewQueryClient(b.grpcConn) maxSizeOption := grpc.MaxCallRecvMsgSize(32 * 1024 * 1024) resp, err := client.ListPendingCctxWithinRateLimit( @@ -148,9 +148,9 @@ func (b *ZetaCoreBridge) ListPendingCctxWithinRatelimit() ([]*types.CrossChainTx maxSizeOption, ) if err != nil { - return nil, 0, false, err + return nil, 0, 0, false, err } - return resp.CrossChainTx, resp.TotalPending, resp.RateLimitExceeded, nil + return resp.CrossChainTx, resp.TotalPending, resp.ValueWithinWindow, resp.RateLimitExceeded, nil } func (b *ZetaCoreBridge) GetAbortedZetaAmount() (string, error) { diff --git a/zetaclient/zetacore_observer.go b/zetaclient/zetacore_observer.go index c66f15f50a..230e1ba894 100644 --- a/zetaclient/zetacore_observer.go +++ b/zetaclient/zetacore_observer.go @@ -134,10 +134,14 @@ func (co *CoreObserver) startCctxScheduler(appContext *appcontext.AppContext) { metrics.HotKeyBurnRate.Set(float64(co.ts.HotKeyBurnRate.GetBurnRate().Int64())) // query pending cctxs across all foreign chains with rate limit - cctxMap, err := co.getAllPendingCctxWithRatelimit() + cctxMap, valueWithinWindow, err := co.getAllPendingCctxWithRatelimit() if err != nil { co.logger.ZetaChainWatcher.Error().Err(err).Msgf("startCctxScheduler: queryPendingCctxWithRatelimit failed") } + // print value within rate limiter window every minute + if bn%10 == 0 { + co.logger.ZetaChainWatcher.Debug().Msgf("startCctxScheduler: value within rate limiter window is %d ZETA", valueWithinWindow) + } // schedule keysign for pending cctxs on each chain coreContext := appContext.ZetaCoreContext() @@ -190,10 +194,10 @@ func (co *CoreObserver) startCctxScheduler(appContext *appcontext.AppContext) { } // getAllPendingCctxWithRatelimit get pending cctxs across all foreign chains with rate limit -func (co *CoreObserver) getAllPendingCctxWithRatelimit() (map[int64][]*types.CrossChainTx, error) { - cctxList, totalPending, rateLimitExceeded, err := co.bridge.ListPendingCctxWithinRatelimit() +func (co *CoreObserver) getAllPendingCctxWithRatelimit() (map[int64][]*types.CrossChainTx, uint64, error) { + cctxList, totalPending, valueWithinWindow, rateLimitExceeded, err := co.bridge.ListPendingCctxWithinRatelimit() if err != nil { - return nil, err + return nil, 0, err } if rateLimitExceeded { co.logger.ZetaChainWatcher.Warn().Msgf("rate limit exceeded, fetched %d cctxs out of %d", len(cctxList), totalPending) @@ -209,7 +213,7 @@ func (co *CoreObserver) getAllPendingCctxWithRatelimit() (map[int64][]*types.Cro cctxMap[chainID] = append(cctxMap[chainID], cctx) } - return cctxMap, nil + return cctxMap, valueWithinWindow, nil } // scheduleCctxEVM schedules evm outtx keysign on each ZetaChain block (the ticker) From 7fe367fcc998e2c6124c153f434b91c8003b74aa Mon Sep 17 00:00:00 2001 From: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> Date: Mon, 22 Apr 2024 09:52:18 -0500 Subject: [PATCH 17/33] Update x/crosschain/keeper/grpc_query_cctx_rate_limit.go Co-authored-by: Lucas Bertrand --- x/crosschain/keeper/grpc_query_cctx_rate_limit.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go index 287ebe1147..d4650e1707 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go @@ -234,12 +234,12 @@ func ConvertCctxValue( } // get foreign coin decimals - _, found := foreignCoinMap[chainID] + foreignCoinFromChainMap, found := foreignCoinMap[chainID] if !found { // skip if no coin found for this chainID return sdk.NewDec(0) } - fCoin, found := foreignCoinMap[chainID][strings.ToLower(cctx.InboundTxParams.Asset)] + fCoin, found := foreignCoinFromChainMap[strings.ToLower(cctx.InboundTxParams.Asset)] if !found { // skip if no coin found for this Asset return sdk.NewDec(0) From e5e4e28a8d27e5b48c808d978ed11f25b98d2ea0 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Mon, 22 Apr 2024 09:55:02 -0500 Subject: [PATCH 18/33] change variable name fCoin to foreignCoin --- x/crosschain/keeper/grpc_query_cctx_rate_limit.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go index d4650e1707..b9e30a34c8 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go @@ -239,12 +239,12 @@ func ConvertCctxValue( // skip if no coin found for this chainID return sdk.NewDec(0) } - fCoin, found := foreignCoinFromChainMap[strings.ToLower(cctx.InboundTxParams.Asset)] + foreignCoin, found := foreignCoinFromChainMap[strings.ToLower(cctx.InboundTxParams.Asset)] if !found { // skip if no coin found for this Asset return sdk.NewDec(0) } - decimals = uint64(fCoin.Decimals) + decimals = uint64(foreignCoin.Decimals) // given decimals = 6, the `oneZrc20` amount will be 10^6 = 1000000 oneZrc20 := sdk.NewDec(10).Power(decimals) From 5e28dafd2cbe5184b3bdf823240d9b1ad4009e4c Mon Sep 17 00:00:00 2001 From: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> Date: Mon, 22 Apr 2024 09:55:56 -0500 Subject: [PATCH 19/33] Update x/fungible/keeper/foreign_coins.go Co-authored-by: Lucas Bertrand --- x/fungible/keeper/foreign_coins.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/fungible/keeper/foreign_coins.go b/x/fungible/keeper/foreign_coins.go index 2f3eaf7918..c695dcee1b 100644 --- a/x/fungible/keeper/foreign_coins.go +++ b/x/fungible/keeper/foreign_coins.go @@ -85,7 +85,7 @@ func (k Keeper) GetAllForeignCoins(ctx sdk.Context) (list []types.ForeignCoins) func (k Keeper) GetAllForeignCoinMap(ctx sdk.Context) map[int64]map[string]types.ForeignCoins { allForeignCoins := k.GetAllForeignCoins(ctx) - fCoinMap := make(map[int64]map[string]types.ForeignCoins) + foreignCoinMap := make(map[int64]map[string]types.ForeignCoins) for _, c := range allForeignCoins { if _, found := fCoinMap[c.ForeignChainId]; !found { fCoinMap[c.ForeignChainId] = make(map[string]types.ForeignCoins) From da27a8488d99c6020bc8a33be1f4353289827a89 Mon Sep 17 00:00:00 2001 From: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> Date: Mon, 22 Apr 2024 09:56:08 -0500 Subject: [PATCH 20/33] Update x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go Co-authored-by: Lucas Bertrand --- x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go index 8b53958ad3..0e0364dea7 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go @@ -366,7 +366,7 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { zk.ObserverKeeper.SetTSS(ctx, tss) // Set rate limiter flags as disabled - rFlags := sample.RateLimiterFlags() + rateLimiterFlags := sample.RateLimiterFlags() rFlags.Enabled = false k.SetRateLimiterFlags(ctx, rFlags) From f9eed1570eccc447230fe15c25ec99d41f1946fb Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Mon, 22 Apr 2024 17:19:45 -0500 Subject: [PATCH 21/33] converted rate limiter query unit tests to table test --- .../keeper/grpc_query_cctx_rate_limit.go | 2 +- .../keeper/grpc_query_cctx_rate_limit_test.go | 498 +++++++++++------- x/fungible/keeper/foreign_coins.go | 8 +- 3 files changed, 308 insertions(+), 200 deletions(-) diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go index b9e30a34c8..7a05e9341d 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go @@ -69,7 +69,7 @@ func (k Keeper) ListPendingCctxWithinRateLimit(c context.Context, req *types.Que } // calculate the rate limiter sliding window left boundary (inclusive) - leftWindowBoundary := height - rateLimitFlags.Window + leftWindowBoundary := height - rateLimitFlags.Window + 1 if leftWindowBoundary < 0 { leftWindowBoundary = 0 } diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go index 0e0364dea7..cd69e663d4 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go @@ -16,19 +16,29 @@ import ( observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) +var ( + // local eth chain ID + ethChainID = getValidEthChainID() + + // local btc chain ID + btcChainID = getValidBtcChainID() +) + // createTestRateLimiterFlags creates a custom rate limiter flags func createTestRateLimiterFlags( + window int64, + rate math.Uint, zrc20ETH string, zrc20BTC string, zrc20USDT string, ethRate string, btcRate string, usdtRate string, -) types.RateLimiterFlags { - var rateLimiterFlags = types.RateLimiterFlags{ +) *types.RateLimiterFlags { + return &types.RateLimiterFlags{ Enabled: true, - Window: 500, // 500 zeta blocks, 50 minutes - Rate: math.NewUint(5000), // 5000 ZETA + Window: window, // for instance: 500 zeta blocks, 50 minutes + Rate: rate, Conversions: []types.Conversion{ // ETH { @@ -47,7 +57,6 @@ func createTestRateLimiterFlags( }, }, } - return rateLimiterFlags } // createCctxsWithCoinTypeAndHeightRange @@ -56,10 +65,6 @@ func createTestRateLimiterFlags( // return created cctxs func createCctxsWithCoinTypeAndHeightRange( t *testing.T, - ctx sdk.Context, - k keeper.Keeper, - zk keepertest.ZetaKeepers, - tss observertypes.TSS, lowBlock uint64, highBlock uint64, chainID int64, @@ -80,34 +85,29 @@ func createCctxsWithCoinTypeAndHeightRange( cctx.GetCurrentOutTxParam().ReceiverChainId = chainID cctx.GetCurrentOutTxParam().Amount = sdk.NewUint(amount) cctx.GetCurrentOutTxParam().OutboundTxTssNonce = nonce - k.SetCrossChainTx(ctx, *cctx) - zk.ObserverKeeper.SetNonceToCctx(ctx, observertypes.NonceToCctx{ - ChainId: chainID, - // #nosec G701 always in range for tests - Nonce: int64(nonce), - CctxIndex: cctx.Index, - Tss: tss.TssPubkey, - }) cctxs = append(cctxs, cctx) } return cctxs } -// setPendingNonces sets the pending nonces for the given chainID -func setPendingNonces( +// setCctxsInKeeper sets the given cctxs to the keeper +func setCctxsInKeeper( ctx sdk.Context, + k keeper.Keeper, zk keepertest.ZetaKeepers, - chainID int64, - nonceLow int64, - nonceHigh int64, - tssPubKey string, + tss observertypes.TSS, + cctxs []*types.CrossChainTx, ) { - zk.ObserverKeeper.SetPendingNonces(ctx, observertypes.PendingNonces{ - ChainId: chainID, - NonceLow: nonceLow, - NonceHigh: nonceHigh, - Tss: tssPubKey, - }) + for _, cctx := range cctxs { + k.SetCrossChainTx(ctx, *cctx) + zk.ObserverKeeper.SetNonceToCctx(ctx, observertypes.NonceToCctx{ + ChainId: cctx.InboundTxParams.SenderChainId, + // #nosec G701 always in range for tests + Nonce: int64(cctx.GetCurrentOutTxParam().OutboundTxTssNonce), + CctxIndex: cctx.Index, + Tss: tss.TssPubkey, + }) + } } // setupForeignCoins adds ETH, BTC, USDT to the foreign coins store @@ -124,59 +124,6 @@ func setupForeignCoins( } } -// createKeeperForRateLimiterTest creates a keeper filled with cctxs for rate limiter test -func createKeeperForRateLimiterTest(t *testing.T) (k *keeper.Keeper, ctx sdk.Context, cctxsETH, cctxsBTC []*types.CrossChainTx, rateLimiterFlags types.RateLimiterFlags) { - // chain IDs - ethChainID := getValidEthChainID() - btcChainID := getValidBtcChainID() - - // zrc20 addresses for ETH, BTC, USDT and asset for USDT - zrc20ETH := sample.EthAddress().Hex() - zrc20BTC := sample.EthAddress().Hex() - zrc20USDT := sample.EthAddress().Hex() - assetUSDT := sample.EthAddress().Hex() - - // create test rate limiter flags - rateLimiterFlags = createTestRateLimiterFlags(zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8") - - // define cctx status - statusPending := types.CctxStatus_PendingOutbound - statusMined := types.CctxStatus_OutboundMined - - // create test keepers - k, ctx, _, zk := keepertest.CrosschainKeeper(t) - - // Set TSS - tss := sample.Tss() - zk.ObserverKeeper.SetTSS(ctx, tss) - - // Set foreign coins - setupForeignCoins(t, ctx, zk, zrc20ETH, zrc20BTC, zrc20USDT, assetUSDT) - - // Set rate limiter flags - k.SetRateLimiterFlags(ctx, rateLimiterFlags) - - // Create cctxs [0~999] and [1000~1199] for Eth chain, 0.001 ETH (2.5 ZETA) per cctx - createCctxsWithCoinTypeAndHeightRange(t, ctx, *k, zk, tss, 1, 1000, ethChainID, coin.CoinType_Gas, "", uint64(1e15), statusMined) - cctxsETH = createCctxsWithCoinTypeAndHeightRange(t, ctx, *k, zk, tss, 1001, 1200, ethChainID, coin.CoinType_Gas, "", uint64(1e15), statusPending) - - // Set Eth chain pending nonces, [1000~1099] are missed cctxs - setPendingNonces(ctx, zk, ethChainID, 1100, 1200, tss.TssPubkey) - - // Create cctxs [0~999] and [1000~1199] for Btc chain, 0.00001 BTC (0.5 ZETA) per cctx - createCctxsWithCoinTypeAndHeightRange(t, ctx, *k, zk, tss, 1, 1000, btcChainID, coin.CoinType_Gas, "", 1000, statusMined) - cctxsBTC = createCctxsWithCoinTypeAndHeightRange(t, ctx, *k, zk, tss, 1001, 1200, btcChainID, coin.CoinType_Gas, "", 1000, statusPending) - require.NotNil(t, cctxsBTC) - - // Set Btc chain pending nonces, [1000~1099] are missed cctxs - setPendingNonces(ctx, zk, btcChainID, 1100, 1200, tss.TssPubkey) - - // Set current block height to 1201, the window is now [701, 1201], the nonces [700~1200] fall into the window - ctx = ctx.WithBlockHeight(1201) - - return k, ctx, cctxsETH, cctxsBTC, rateLimiterFlags -} - func Test_ConvertCctxValue(t *testing.T) { // chain IDs ethChainID := getValidEthChainID() @@ -198,8 +145,8 @@ func Test_ConvertCctxValue(t *testing.T) { setupForeignCoins(t, ctx, zk, zrc20ETH, zrc20BTC, zrc20USDT, assetUSDT) // Set rate limiter flags - rateLimiterFlags := createTestRateLimiterFlags(zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8") - k.SetRateLimiterFlags(ctx, rateLimiterFlags) + rateLimiterFlags := createTestRateLimiterFlags(500, math.NewUint(5000), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8") + k.SetRateLimiterFlags(ctx, *rateLimiterFlags) // get rate limiter rates gasCoinRates, erc20CoinRates := k.GetRateLimiterRates(ctx) @@ -318,6 +265,278 @@ func Test_ConvertCctxValue(t *testing.T) { } func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { + // create sample TSS + tss := sample.Tss() + + // create sample zrc20 addresses for ETH, BTC, USDT + zrc20ETH := sample.EthAddress().Hex() + zrc20BTC := sample.EthAddress().Hex() + zrc20USDT := sample.EthAddress().Hex() + + // create Eth chain mined and pending cctxs for rate limiter test + ethMindedCctxs := createCctxsWithCoinTypeAndHeightRange(t, 1, 999, ethChainID, coin.CoinType_Gas, "", uint64(1e15), types.CctxStatus_OutboundMined) + ethPendingCctxs := createCctxsWithCoinTypeAndHeightRange(t, 1000, 1199, ethChainID, coin.CoinType_Gas, "", uint64(1e15), types.CctxStatus_PendingOutbound) + + // create Btc chain mined and pending cctxs for rate limiter test + btcMinedCctxs := createCctxsWithCoinTypeAndHeightRange(t, 1, 999, btcChainID, coin.CoinType_Gas, "", 1000, types.CctxStatus_OutboundMined) + btcPendingCctxs := createCctxsWithCoinTypeAndHeightRange(t, 1000, 1199, btcChainID, coin.CoinType_Gas, "", 1000, types.CctxStatus_PendingOutbound) + + // define test cases + tests := []struct { + name string + rateLimitFlags *types.RateLimiterFlags + + // Eth chain cctxs setup + ethMindedCctxs []*types.CrossChainTx + ethPendingCctxs []*types.CrossChainTx + ethPendingNonces observertypes.PendingNonces + + // Btc chain cctxs setup + btcMinedCctxs []*types.CrossChainTx + btcPendingCctxs []*types.CrossChainTx + btcPendingNonces observertypes.PendingNonces + + // current block height and limit + currentHeight int64 + queryLimit uint32 + + // expected results + expectedCctxs []*types.CrossChainTx + expectedTotalPending uint64 + expectedTotalValue uint64 + rateLimitExceeded bool + }{ + { + name: "should use fallback query if rate limiter is disabled", + rateLimitFlags: nil, // no rate limiter flags set in the keeper + ethMindedCctxs: ethMindedCctxs, + ethPendingCctxs: ethPendingCctxs, + ethPendingNonces: observertypes.PendingNonces{ + ChainId: ethChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + btcMinedCctxs: btcMinedCctxs, + btcPendingCctxs: btcPendingCctxs, + btcPendingNonces: observertypes.PendingNonces{ + ChainId: btcChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + currentHeight: 1199, + queryLimit: keeper.MaxPendingCctxs, + expectedCctxs: append(append([]*types.CrossChainTx{}, btcPendingCctxs...), ethPendingCctxs...), + expectedTotalPending: 400, + }, + { + name: "can retrieve pending cctx in range without exceeding rate limit", + rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(5000), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), + ethMindedCctxs: ethMindedCctxs, + ethPendingCctxs: ethPendingCctxs, + ethPendingNonces: observertypes.PendingNonces{ + ChainId: ethChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + btcMinedCctxs: btcMinedCctxs, + btcPendingCctxs: btcPendingCctxs, + btcPendingNonces: observertypes.PendingNonces{ + ChainId: btcChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + currentHeight: 1199, + queryLimit: keeper.MaxPendingCctxs, + expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs...), btcPendingCctxs...), + expectedTotalPending: 400, + expectedTotalValue: 1500, // 500 (window) * (2.5 + 0.5) + rateLimitExceeded: false, + }, + { + name: "can loop backwards all the way to endNonce 0", + rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(5000), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), + ethMindedCctxs: ethMindedCctxs, + ethPendingCctxs: ethPendingCctxs, + ethPendingNonces: observertypes.PendingNonces{ + ChainId: ethChainID, + NonceLow: 999, // endNonce will set to 0 as NonceLow - 1000 < 0 + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + btcMinedCctxs: btcMinedCctxs, + btcPendingCctxs: btcPendingCctxs, + btcPendingNonces: observertypes.PendingNonces{ + ChainId: btcChainID, + NonceLow: 999, // endNonce will set to 0 as NonceLow - 1000 < 0 + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + currentHeight: 1199, + queryLimit: keeper.MaxPendingCctxs, + expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs...), btcPendingCctxs...), + expectedTotalPending: 400, + expectedTotalValue: 1500, // 500 (window) * (2.5 + 0.5) + rateLimitExceeded: false, + }, + { + name: "set a low rate (< 1200) to early break the LoopBackwards with criteria #2", + rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(1000), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), // 1000 < 1200 + ethMindedCctxs: ethMindedCctxs, + ethPendingCctxs: ethPendingCctxs, + ethPendingNonces: observertypes.PendingNonces{ + ChainId: ethChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + btcMinedCctxs: btcMinedCctxs, + btcPendingCctxs: btcPendingCctxs, + btcPendingNonces: observertypes.PendingNonces{ + ChainId: btcChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + currentHeight: 1199, + queryLimit: keeper.MaxPendingCctxs, + expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs[0:100]...), btcPendingCctxs[0:100]...), + expectedTotalPending: 400, + rateLimitExceeded: true, + }, + { + name: "set high rate and big window to early to break inner loop with the criteria #1", + // The left boundary will be 49 (currentHeight-1150), which will be less than the endNonce 99 (1099 - 1000) + rateLimitFlags: createTestRateLimiterFlags(1150, math.NewUint(10000), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), + ethMindedCctxs: ethMindedCctxs, + ethPendingCctxs: ethPendingCctxs, + ethPendingNonces: observertypes.PendingNonces{ + ChainId: ethChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + btcMinedCctxs: btcMinedCctxs, + btcPendingCctxs: btcPendingCctxs, + btcPendingNonces: observertypes.PendingNonces{ + ChainId: btcChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + currentHeight: 1199, + queryLimit: keeper.MaxPendingCctxs, + expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs...), btcPendingCctxs...), + expectedTotalPending: 400, + expectedTotalValue: 3450, // 1150 (window) * (2.5 + 0.5) + rateLimitExceeded: false, + }, + { + name: "set lower request limit to early break the LoopForwards loop", + rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(5000), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), + ethMindedCctxs: ethMindedCctxs, + ethPendingCctxs: ethPendingCctxs, + ethPendingNonces: observertypes.PendingNonces{ + ChainId: ethChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + btcMinedCctxs: btcMinedCctxs, + btcPendingCctxs: btcPendingCctxs, + btcPendingNonces: observertypes.PendingNonces{ + ChainId: btcChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + currentHeight: 1199, + queryLimit: 300, // 300 < keeper.MaxPendingCctxs + expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs[0:100]...), btcPendingCctxs...), + expectedTotalPending: 400, + expectedTotalValue: 1250, // 500 * 0.5 + 400 * 2.5 + rateLimitExceeded: false, + }, + { + name: "set rate to middle value (1200 < rate < 1500) to early break the LoopForwards loop with criteria #2", + rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(1300), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), // 1200 < 1300 < 1500 + ethMindedCctxs: ethMindedCctxs, + ethPendingCctxs: ethPendingCctxs, + ethPendingNonces: observertypes.PendingNonces{ + ChainId: ethChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + btcMinedCctxs: btcMinedCctxs, + btcPendingCctxs: btcPendingCctxs, + btcPendingNonces: observertypes.PendingNonces{ + ChainId: btcChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + currentHeight: 1199, + queryLimit: keeper.MaxPendingCctxs, + // 120 ETH cctx + 200 BTC cctx + expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs[0:120]...), btcPendingCctxs...), + expectedTotalPending: 400, + rateLimitExceeded: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // create test keepers + k, ctx, _, zk := keepertest.CrosschainKeeper(t) + + // Set TSS + zk.ObserverKeeper.SetTSS(ctx, tss) + + // Set foreign coins + assetUSDT := sample.EthAddress().Hex() + setupForeignCoins(t, ctx, zk, zrc20ETH, zrc20BTC, zrc20USDT, assetUSDT) + + // Set rate limiter flags + if tt.rateLimitFlags != nil { + k.SetRateLimiterFlags(ctx, *tt.rateLimitFlags) + } + + // Set Eth chain mined cctxs, pending ccxts and pending nonces + setCctxsInKeeper(ctx, *k, zk, tss, tt.ethMindedCctxs) + setCctxsInKeeper(ctx, *k, zk, tss, tt.ethPendingCctxs) + zk.ObserverKeeper.SetPendingNonces(ctx, tt.ethPendingNonces) + + // Set Btc chain mined cctxs, pending ccxts and pending nonces + setCctxsInKeeper(ctx, *k, zk, tss, tt.btcMinedCctxs) + setCctxsInKeeper(ctx, *k, zk, tss, tt.btcPendingCctxs) + zk.ObserverKeeper.SetPendingNonces(ctx, tt.btcPendingNonces) + + // Set current block height + ctx = ctx.WithBlockHeight(tt.currentHeight) + + // Query pending cctxs + res, err := k.ListPendingCctxWithinRateLimit(ctx, &types.QueryListPendingCctxWithinRateLimitRequest{Limit: tt.queryLimit}) + require.NoError(t, err) + require.EqualValues(t, tt.expectedCctxs, res.CrossChainTx) + require.EqualValues(t, tt.expectedTotalPending, res.TotalPending) + + // check rate limiter related fields only if rate limiter flags is enabled + if tt.rateLimitFlags != nil { + if !tt.rateLimitExceeded { + require.EqualValues(t, tt.expectedTotalValue, res.ValueWithinWindow) + } else { + require.True(t, res.ValueWithinWindow > tt.rateLimitFlags.Rate.Uint64()) + } + } + }) + } +} + +func TestKeeper_ListPendingCctxWithinRateLimit_Errors(t *testing.T) { t.Run("should fail for empty req", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) _, err := k.ListPendingCctxWithinRateLimit(ctx, nil) @@ -358,115 +577,4 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { _, err := k.ListPendingCctxWithinRateLimit(ctx, &types.QueryListPendingCctxWithinRateLimitRequest{}) require.ErrorContains(t, err, "pending nonces not found") }) - t.Run("should use fallback query", func(t *testing.T) { - k, ctx, _, zk := keepertest.CrosschainKeeper(t) - - // Set TSS - tss := sample.Tss() - zk.ObserverKeeper.SetTSS(ctx, tss) - - // Set rate limiter flags as disabled - rateLimiterFlags := sample.RateLimiterFlags() - rFlags.Enabled = false - k.SetRateLimiterFlags(ctx, rFlags) - - // Create cctxs [0~999] and [1000~1199] for Eth chain, 0.001 ETH per cctx - ethChainID := getValidEthChainID() - _ = createCctxsWithCoinTypeAndHeightRange(t, ctx, *k, zk, tss, 1, 1000, ethChainID, coin.CoinType_Gas, "", uint64(1e15), types.CctxStatus_OutboundMined) - cctxsETH := createCctxsWithCoinTypeAndHeightRange(t, ctx, *k, zk, tss, 1001, 1200, ethChainID, coin.CoinType_Gas, "", uint64(1e15), types.CctxStatus_PendingOutbound) - - // Set Eth chain pending nonces which contains 100 missing cctxs - setPendingNonces(ctx, zk, ethChainID, 1100, 1200, tss.TssPubkey) - - // Query pending cctxs use small limit - res, err := k.ListPendingCctxWithinRateLimit(ctx, &types.QueryListPendingCctxWithinRateLimitRequest{Limit: 100}) - require.NoError(t, err) - require.Equal(t, 100, len(res.CrossChainTx)) - - // check response - require.EqualValues(t, cctxsETH[:100], res.CrossChainTx) - require.EqualValues(t, uint64(200), res.TotalPending) - - // Query pending cctxs use max limit - res, err = k.ListPendingCctxWithinRateLimit(ctx, &types.QueryListPendingCctxWithinRateLimitRequest{Limit: keeper.MaxPendingCctxs}) - require.NoError(t, err) - require.Equal(t, 200, len(res.CrossChainTx)) - - // check response - require.EqualValues(t, cctxsETH, res.CrossChainTx) - require.EqualValues(t, uint64(200), res.TotalPending) - }) - t.Run("can retrieve pending cctx in range without exceeding rate limit", func(t *testing.T) { - k, ctx, cctxsETH, cctxsBTC, _ := createKeeperForRateLimiterTest(t) - - res, err := k.ListPendingCctxWithinRateLimit(ctx, &types.QueryListPendingCctxWithinRateLimitRequest{}) - require.NoError(t, err) - require.Equal(t, 400, len(res.CrossChainTx)) - require.EqualValues(t, cctxsETH, res.CrossChainTx[0:200]) - require.EqualValues(t, cctxsBTC, res.CrossChainTx[200:400]) - require.EqualValues(t, uint64(400), res.TotalPending) - require.False(t, res.RateLimitExceeded) - require.Equal(t, uint64(1500), res.ValueWithinWindow) // 500 * (2.5 + 0.5) - }) - t.Run("Set rate to a lower value (< 1200) to early break the LoopBackwards with criteria #2", func(t *testing.T) { - k, ctx, cctxsETH, cctxsBTC, rlFlags := createKeeperForRateLimiterTest(t) - - rate := uint64(1000) // 1000 ZETA - rlFlags.Rate = math.NewUint(rate) - k.SetRateLimiterFlags(ctx, rlFlags) - - res, err := k.ListPendingCctxWithinRateLimit(ctx, &types.QueryListPendingCctxWithinRateLimitRequest{}) - require.NoError(t, err) - require.Equal(t, 200, len(res.CrossChainTx)) - require.EqualValues(t, cctxsETH[:100], res.CrossChainTx[0:100]) - require.EqualValues(t, cctxsBTC[:100], res.CrossChainTx[100:200]) - require.EqualValues(t, uint64(400), res.TotalPending) - require.True(t, res.RateLimitExceeded) - require.True(t, res.ValueWithinWindow >= rate) - }) - t.Run("Set high rate and big window to early to break inner loop with the criteria #1", func(t *testing.T) { - k, ctx, cctxsETH, cctxsBTC, rlFlags := createKeeperForRateLimiterTest(t) - - // The left boundary will be 51 (1201-1150), less than the endNonce 100 (1100 - 10000) - rlFlags.Rate = math.NewUint(10000) - rlFlags.Window = 1150 - k.SetRateLimiterFlags(ctx, rlFlags) - - res, err := k.ListPendingCctxWithinRateLimit(ctx, &types.QueryListPendingCctxWithinRateLimitRequest{}) - require.NoError(t, err) - require.Equal(t, 400, len(res.CrossChainTx)) - require.EqualValues(t, cctxsETH, res.CrossChainTx[0:200]) - require.EqualValues(t, cctxsBTC, res.CrossChainTx[200:400]) - require.EqualValues(t, uint64(400), res.TotalPending) - require.False(t, res.RateLimitExceeded) - require.EqualValues(t, uint64(3450), res.ValueWithinWindow) // 1150 * (2.5 + 0.5) - }) - t.Run("Set lower request limit to early break the LoopForwards loop", func(t *testing.T) { - k, ctx, cctxsETH, cctxsBTC, _ := createKeeperForRateLimiterTest(t) - - res, err := k.ListPendingCctxWithinRateLimit(ctx, &types.QueryListPendingCctxWithinRateLimitRequest{Limit: 300}) - require.NoError(t, err) - require.Equal(t, 300, len(res.CrossChainTx)) - require.EqualValues(t, cctxsETH[:100], res.CrossChainTx[0:100]) - require.EqualValues(t, cctxsBTC, res.CrossChainTx[100:300]) - require.EqualValues(t, uint64(400), res.TotalPending) - require.False(t, res.RateLimitExceeded) - require.EqualValues(t, uint64(1250), res.ValueWithinWindow) // 500 * 0.5 + 400 * 2.5 - }) - t.Run("Set rate to middle value (1200 < rate < 1500) to early break the LoopForwards loop with criteria #2", func(t *testing.T) { - k, ctx, cctxsETH, cctxsBTC, rlFlags := createKeeperForRateLimiterTest(t) - - rlFlags.Window = 500 - rlFlags.Rate = math.NewUint(1300) // 1300 ZETA - k.SetRateLimiterFlags(ctx, rlFlags) - - res, err := k.ListPendingCctxWithinRateLimit(ctx, &types.QueryListPendingCctxWithinRateLimitRequest{}) - require.NoError(t, err) - require.Equal(t, 320, len(res.CrossChainTx)) // 120 ETH cctx + 200 BTC cctx - require.EqualValues(t, cctxsETH[:120], res.CrossChainTx[0:120]) - require.EqualValues(t, cctxsBTC, res.CrossChainTx[120:320]) - require.EqualValues(t, uint64(400), res.TotalPending) - require.True(t, res.RateLimitExceeded) - require.True(t, res.ValueWithinWindow >= 1300) - }) } diff --git a/x/fungible/keeper/foreign_coins.go b/x/fungible/keeper/foreign_coins.go index c695dcee1b..5dfe744829 100644 --- a/x/fungible/keeper/foreign_coins.go +++ b/x/fungible/keeper/foreign_coins.go @@ -87,12 +87,12 @@ func (k Keeper) GetAllForeignCoinMap(ctx sdk.Context) map[int64]map[string]types foreignCoinMap := make(map[int64]map[string]types.ForeignCoins) for _, c := range allForeignCoins { - if _, found := fCoinMap[c.ForeignChainId]; !found { - fCoinMap[c.ForeignChainId] = make(map[string]types.ForeignCoins) + if _, found := foreignCoinMap[c.ForeignChainId]; !found { + foreignCoinMap[c.ForeignChainId] = make(map[string]types.ForeignCoins) } - fCoinMap[c.ForeignChainId][strings.ToLower(c.Asset)] = c + foreignCoinMap[c.ForeignChainId][strings.ToLower(c.Asset)] = c } - return fCoinMap + return foreignCoinMap } // GetGasCoinForForeignCoin returns the gas coin for a given chain From f40cf454d51e86f86fd4bd963a0d89c3e740b545 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Wed, 24 Apr 2024 00:31:23 -0500 Subject: [PATCH 22/33] handle edge case when pending cctxs span wider block range than sliding window --- .../keeper/grpc_query_cctx_rate_limit.go | 40 +++++++++++++++---- .../keeper/grpc_query_cctx_rate_limit_test.go | 31 +++++++++++++- 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go index 7a05e9341d..ce9987d2a1 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go @@ -78,11 +78,13 @@ func (k Keeper) ListPendingCctxWithinRateLimit(c context.Context, req *types.Que var gasCoinRates map[int64]sdk.Dec var erc20CoinRates map[int64]map[string]sdk.Dec var foreignCoinMap map[int64]map[string]fungibletypes.ForeignCoins - var rateLimitInZeta sdk.Dec + var windowLimitInZeta sdk.Dec + var blockLimitInZeta sdk.Dec if applyLimit { gasCoinRates, erc20CoinRates = k.GetRateLimiterRates(ctx) foreignCoinMap = k.fungibleKeeper.GetAllForeignCoinMap(ctx) - rateLimitInZeta = sdk.NewDecFromBigInt(rateLimitFlags.Rate.BigInt()) + windowLimitInZeta = sdk.NewDecFromBigInt(rateLimitFlags.Rate.BigInt()) + blockLimitInZeta = windowLimitInZeta.Quo(sdk.NewDec(rateLimitFlags.Window)) } // the criteria to stop adding cctxs to the rpc response @@ -97,15 +99,40 @@ func (k Keeper) ListPendingCctxWithinRateLimit(c context.Context, req *types.Que return cctx.InboundTxParams.InboundTxObservedExternalHeight >= uint64(leftWindowBoundary) } - // query pending nonces for each foreign chain + // query pending nonces for each foreign chain and get the lowest height of the pending cctxs // Note: The pending nonces could change during the RPC call, so query them beforehand + lowestPendingCctxHeight := int64(0) pendingNoncesMap := make(map[int64]*observertypes.PendingNonces) for _, chain := range chains { pendingNonces, found := k.GetObserverKeeper().GetPendingNonces(ctx, tss.TssPubkey, chain.ChainId) if !found { return nil, status.Error(codes.Internal, "pending nonces not found") } - pendingNoncesMap[chain.ChainId] = &pendingNonces + + // insert pending nonces and update lowest height + if pendingNonces.NonceLow < pendingNonces.NonceHigh { + pendingNoncesMap[chain.ChainId] = &pendingNonces + cctx, err := getCctxByChainIDAndNonce(k, ctx, tss.TssPubkey, chain.ChainId, pendingNonces.NonceLow) + if err != nil { + return nil, err + } + // #nosec G701 len always in range + cctxHeight := int64(cctx.InboundTxParams.InboundTxObservedExternalHeight) + if lowestPendingCctxHeight == 0 || cctxHeight < lowestPendingCctxHeight { + lowestPendingCctxHeight = cctxHeight + } + } + } + + // invariant: for period of time > window, the average rate per block cannot exceed `blockLimitInZeta` + pendingCctxsLimitInZeta := windowLimitInZeta + if lowestPendingCctxHeight != 0 { + // `pendingCctxWindow` is the width of [lowestPendingCctxHeight, height] window + // if the window can be wider than the rate limit window, we should adjust the total limit proportionally + pendingCctxWindow := height - lowestPendingCctxHeight + 1 + if pendingCctxWindow > rateLimitFlags.Window { + pendingCctxsLimitInZeta = blockLimitInZeta.Mul(sdk.NewDec(pendingCctxWindow)) + } } // query backwards for potential missed pending cctxs for each foreign chain @@ -143,7 +170,7 @@ LoopBackwards: break } // criteria #2: we should finish the RPC call if the rate limit is exceeded - if inWindow && rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap, &totalCctxValueInZeta, rateLimitInZeta) { + if inWindow && rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap, &totalCctxValueInZeta, windowLimitInZeta) { limitExceeded = true break LoopBackwards } @@ -168,14 +195,13 @@ LoopForwards: if err != nil { return nil, err } - inWindow := isCctxInWindow(cctx) // only take a `limit` number of pending cctxs as result if maxCCTXsReached() { break LoopForwards } // criteria #2: we should finish the RPC call if the rate limit is exceeded - if inWindow && rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap, &totalCctxValueInZeta, rateLimitInZeta) { + if rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap, &totalCctxValueInZeta, pendingCctxsLimitInZeta) { limitExceeded = true break LoopForwards } diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go index cd69e663d4..c47317edad 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go @@ -408,7 +408,7 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { rateLimitExceeded: true, }, { - name: "set high rate and big window to early to break inner loop with the criteria #1", + name: "set high rate and wide window to early to break inner loop with the criteria #1", // The left boundary will be 49 (currentHeight-1150), which will be less than the endNonce 99 (1099 - 1000) rateLimitFlags: createTestRateLimiterFlags(1150, math.NewUint(10000), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), ethMindedCctxs: ethMindedCctxs, @@ -486,6 +486,35 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { expectedTotalPending: 400, rateLimitExceeded: true, }, + { + name: "set low rate and narrow window to early break the LoopForwards loop with criteria #2", + // the left boundary will be 1149 (currentHeight-50), the pending nonces [1099, 1148] fall beyond the left boundary. + // `pendingCctxWindow` is 100 which is wider than rate limiter window 50. + // give a block rate of 2 ZETA/block, the max value allowed should be 100 * 2 = 200 ZETA + rateLimitFlags: createTestRateLimiterFlags(50, math.NewUint(100), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), + ethMindedCctxs: ethMindedCctxs, + ethPendingCctxs: ethPendingCctxs, + ethPendingNonces: observertypes.PendingNonces{ + ChainId: ethChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + btcMinedCctxs: btcMinedCctxs, + btcPendingCctxs: btcPendingCctxs, + btcPendingNonces: observertypes.PendingNonces{ + ChainId: btcChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + currentHeight: 1199, + queryLimit: keeper.MaxPendingCctxs, + // 160 ETH cctx + 200 BTC cctx + expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs[0:160]...), btcPendingCctxs...), + expectedTotalPending: 400, + rateLimitExceeded: true, + }, } for _, tt := range tests { From 578afccb54c86839c9c505dab05893132164b7ee Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Wed, 24 Apr 2024 13:43:44 -0500 Subject: [PATCH 23/33] added zero rate check; added comment to make unit test clearer --- x/crosschain/keeper/grpc_query_cctx.go | 5 +- .../keeper/grpc_query_cctx_rate_limit.go | 5 +- .../keeper/grpc_query_cctx_rate_limit_test.go | 69 ++++++++++++++----- 3 files changed, 58 insertions(+), 21 deletions(-) diff --git a/x/crosschain/keeper/grpc_query_cctx.go b/x/crosschain/keeper/grpc_query_cctx.go index 2aeab7007a..688c9cb205 100644 --- a/x/crosschain/keeper/grpc_query_cctx.go +++ b/x/crosschain/keeper/grpc_query_cctx.go @@ -16,6 +16,9 @@ import ( const ( // MaxPendingCctxs is the maximum number of pending cctxs that can be queried MaxPendingCctxs = 500 + + // MaxLookbackNonce is the maximum number of nonces to look back to find missed pending cctxs + MaxLookbackNonce = 1000 ) func (k Keeper) ZetaAccounting(c context.Context, _ *types.QueryZetaAccountingRequest) (*types.QueryZetaAccountingResponse, error) { @@ -122,7 +125,7 @@ func (k Keeper) ListPendingCctx(c context.Context, req *types.QueryListPendingCc // now query the previous nonces up to 1000 prior to find any pending cctx that we might have missed // need this logic because a confirmation of higher nonce will automatically update the p.NonceLow // therefore might mask some lower nonce cctx that is still pending. - startNonce := pendingNonces.NonceLow - 1000 + startNonce := pendingNonces.NonceLow - MaxLookbackNonce if startNonce < 0 { startNonce = 0 } diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go index ce9987d2a1..95a8c5b031 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go @@ -41,6 +41,9 @@ func (k Keeper) ListPendingCctxWithinRateLimit(c context.Context, req *types.Que if !found || !rateLimitFlags.Enabled { applyLimit = false } + if rateLimitFlags.Rate.IsNil() || rateLimitFlags.Rate.IsZero() { + applyLimit = false + } // fallback to non-rate-limited query if rate limiter is disabled if !applyLimit { @@ -143,7 +146,7 @@ LoopBackwards: // therefore might mask some lower nonce cctx that is still pending. pendingNonces := pendingNoncesMap[chain.ChainId] startNonce := pendingNonces.NonceLow - 1 - endNonce := pendingNonces.NonceLow - 1000 + endNonce := pendingNonces.NonceLow - MaxLookbackNonce if endNonce < 0 { endNonce = 0 } diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go index c47317edad..f5ed9e4413 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go @@ -170,7 +170,7 @@ func Test_ConvertCctxValue(t *testing.T) { cctx.InboundTxParams.Asset = "" cctx.GetCurrentOutTxParam().Amount = sdk.NewUint(3e15) // 0.003 ETH - // convert cctx value + // convert cctx value: 0.003 ETH * 2500 = 7.5 ZETA value := keeper.ConvertCctxValue(ethChainID, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap) require.Equal(t, sdk.MustNewDecFromStr("7.5"), value) }) @@ -181,7 +181,7 @@ func Test_ConvertCctxValue(t *testing.T) { cctx.InboundTxParams.Asset = "" cctx.GetCurrentOutTxParam().Amount = sdk.NewUint(70000) // 0.0007 BTC - // convert cctx value + // convert cctx value: 0.0007 BTC * 50000 = 35.0 ZETA value := keeper.ConvertCctxValue(btcChainID, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap) require.Equal(t, sdk.MustNewDecFromStr("35.0"), value) }) @@ -192,7 +192,7 @@ func Test_ConvertCctxValue(t *testing.T) { cctx.InboundTxParams.Asset = assetUSDT cctx.GetCurrentOutTxParam().Amount = sdk.NewUint(3e6) // 3 USDT - // convert cctx value + // convert cctx value: 3 USDT * 0.8 = 2.4 ZETA value := keeper.ConvertCctxValue(ethChainID, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap) require.Equal(t, sdk.MustNewDecFromStr("2.4"), value) }) @@ -273,11 +273,13 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { zrc20BTC := sample.EthAddress().Hex() zrc20USDT := sample.EthAddress().Hex() - // create Eth chain mined and pending cctxs for rate limiter test - ethMindedCctxs := createCctxsWithCoinTypeAndHeightRange(t, 1, 999, ethChainID, coin.CoinType_Gas, "", uint64(1e15), types.CctxStatus_OutboundMined) + // create Eth chain 999 mined and 200 pending cctxs for rate limiter test + // the number 999 is to make it less than `MaxLookbackNonce` so the LoopBackwards gets the chance to hit nonce 0 + ethMinedCctxs := createCctxsWithCoinTypeAndHeightRange(t, 1, 999, ethChainID, coin.CoinType_Gas, "", uint64(1e15), types.CctxStatus_OutboundMined) ethPendingCctxs := createCctxsWithCoinTypeAndHeightRange(t, 1000, 1199, ethChainID, coin.CoinType_Gas, "", uint64(1e15), types.CctxStatus_PendingOutbound) - // create Btc chain mined and pending cctxs for rate limiter test + // create Btc chain 999 mined and 200 pending cctxs for rate limiter test + // the number 999 is to make it less than `MaxLookbackNonce` so the LoopBackwards gets the chance to hit nonce 0 btcMinedCctxs := createCctxsWithCoinTypeAndHeightRange(t, 1, 999, btcChainID, coin.CoinType_Gas, "", 1000, types.CctxStatus_OutboundMined) btcPendingCctxs := createCctxsWithCoinTypeAndHeightRange(t, 1000, 1199, btcChainID, coin.CoinType_Gas, "", 1000, types.CctxStatus_PendingOutbound) @@ -287,7 +289,7 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { rateLimitFlags *types.RateLimiterFlags // Eth chain cctxs setup - ethMindedCctxs []*types.CrossChainTx + ethMinedCctxs []*types.CrossChainTx ethPendingCctxs []*types.CrossChainTx ethPendingNonces observertypes.PendingNonces @@ -309,7 +311,31 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { { name: "should use fallback query if rate limiter is disabled", rateLimitFlags: nil, // no rate limiter flags set in the keeper - ethMindedCctxs: ethMindedCctxs, + ethMinedCctxs: ethMinedCctxs, + ethPendingCctxs: ethPendingCctxs, + ethPendingNonces: observertypes.PendingNonces{ + ChainId: ethChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + btcMinedCctxs: btcMinedCctxs, + btcPendingCctxs: btcPendingCctxs, + btcPendingNonces: observertypes.PendingNonces{ + ChainId: btcChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + currentHeight: 1199, + queryLimit: keeper.MaxPendingCctxs, + expectedCctxs: append(append([]*types.CrossChainTx{}, btcPendingCctxs...), ethPendingCctxs...), + expectedTotalPending: 400, + }, + { + name: "should use fallback query if rate is 0", + rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(0), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), + ethMinedCctxs: ethMinedCctxs, ethPendingCctxs: ethPendingCctxs, ethPendingNonces: observertypes.PendingNonces{ ChainId: ethChainID, @@ -333,7 +359,7 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { { name: "can retrieve pending cctx in range without exceeding rate limit", rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(5000), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), - ethMindedCctxs: ethMindedCctxs, + ethMinedCctxs: ethMinedCctxs, ethPendingCctxs: ethPendingCctxs, ethPendingNonces: observertypes.PendingNonces{ ChainId: ethChainID, @@ -359,7 +385,7 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { { name: "can loop backwards all the way to endNonce 0", rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(5000), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), - ethMindedCctxs: ethMindedCctxs, + ethMinedCctxs: ethMinedCctxs, ethPendingCctxs: ethPendingCctxs, ethPendingNonces: observertypes.PendingNonces{ ChainId: ethChainID, @@ -385,7 +411,7 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { { name: "set a low rate (< 1200) to early break the LoopBackwards with criteria #2", rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(1000), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), // 1000 < 1200 - ethMindedCctxs: ethMindedCctxs, + ethMinedCctxs: ethMinedCctxs, ethPendingCctxs: ethPendingCctxs, ethPendingNonces: observertypes.PendingNonces{ ChainId: ethChainID, @@ -408,10 +434,11 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { rateLimitExceeded: true, }, { - name: "set high rate and wide window to early to break inner loop with the criteria #1", + // this test case is to break the LoopBackwards with criteria #1: the 1st break in LoopBackwards + name: "set high rate and wide window to break inner loop of LoopBackwards when left window boundary is reached", // The left boundary will be 49 (currentHeight-1150), which will be less than the endNonce 99 (1099 - 1000) rateLimitFlags: createTestRateLimiterFlags(1150, math.NewUint(10000), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), - ethMindedCctxs: ethMindedCctxs, + ethMinedCctxs: ethMinedCctxs, ethPendingCctxs: ethPendingCctxs, ethPendingNonces: observertypes.PendingNonces{ ChainId: ethChainID, @@ -437,7 +464,7 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { { name: "set lower request limit to early break the LoopForwards loop", rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(5000), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), - ethMindedCctxs: ethMindedCctxs, + ethMinedCctxs: ethMinedCctxs, ethPendingCctxs: ethPendingCctxs, ethPendingNonces: observertypes.PendingNonces{ ChainId: ethChainID, @@ -461,9 +488,11 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { rateLimitExceeded: false, }, { - name: "set rate to middle value (1200 < rate < 1500) to early break the LoopForwards loop with criteria #2", + // all pending cctxs fall within the sliding window in this test case. + // this test case is to break the LoopBackwards with criteria #2: the 2nd break in LoopForwards + name: "set rate to middle value (1200 < rate < 1500) to early break the LoopForwards when rate limit is exceeded", rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(1300), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), // 1200 < 1300 < 1500 - ethMindedCctxs: ethMindedCctxs, + ethMinedCctxs: ethMinedCctxs, ethPendingCctxs: ethPendingCctxs, ethPendingNonces: observertypes.PendingNonces{ ChainId: ethChainID, @@ -487,12 +516,14 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { rateLimitExceeded: true, }, { - name: "set low rate and narrow window to early break the LoopForwards loop with criteria #2", + // many pending cctxs fall beyond the sliding window in this test case. + // this test case is to break the LoopBackwards with criteria #2: the 2nd break in LoopForwards + name: "set low rate and narrow window to early break the LoopForwards when rate limit is exceeded", // the left boundary will be 1149 (currentHeight-50), the pending nonces [1099, 1148] fall beyond the left boundary. // `pendingCctxWindow` is 100 which is wider than rate limiter window 50. // give a block rate of 2 ZETA/block, the max value allowed should be 100 * 2 = 200 ZETA rateLimitFlags: createTestRateLimiterFlags(50, math.NewUint(100), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), - ethMindedCctxs: ethMindedCctxs, + ethMinedCctxs: ethMinedCctxs, ethPendingCctxs: ethPendingCctxs, ethPendingNonces: observertypes.PendingNonces{ ChainId: ethChainID, @@ -535,7 +566,7 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { } // Set Eth chain mined cctxs, pending ccxts and pending nonces - setCctxsInKeeper(ctx, *k, zk, tss, tt.ethMindedCctxs) + setCctxsInKeeper(ctx, *k, zk, tss, tt.ethMinedCctxs) setCctxsInKeeper(ctx, *k, zk, tss, tt.ethPendingCctxs) zk.ObserverKeeper.SetPendingNonces(ctx, tt.ethPendingNonces) From fa24f32191e070f8729095afe027e573ac1a3d51 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Wed, 24 Apr 2024 14:59:54 -0500 Subject: [PATCH 24/33] added unit test and note for method GetAllForeignCoinMap --- x/fungible/keeper/foreign_coins.go | 1 + x/fungible/keeper/foreign_coins_test.go | 66 +++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/x/fungible/keeper/foreign_coins.go b/x/fungible/keeper/foreign_coins.go index 5dfe744829..5c52eb543e 100644 --- a/x/fungible/keeper/foreign_coins.go +++ b/x/fungible/keeper/foreign_coins.go @@ -82,6 +82,7 @@ func (k Keeper) GetAllForeignCoins(ctx sdk.Context) (list []types.ForeignCoins) } // GetAllForeignCoinMap returns all foreign ERC20 coins in a map of chainID -> asset -> coin +// Note: DO NOT use this method outside of gRPC queries func (k Keeper) GetAllForeignCoinMap(ctx sdk.Context) map[int64]map[string]types.ForeignCoins { allForeignCoins := k.GetAllForeignCoins(ctx) diff --git a/x/fungible/keeper/foreign_coins_test.go b/x/fungible/keeper/foreign_coins_test.go index d9a98a4031..f3a6f6dacd 100644 --- a/x/fungible/keeper/foreign_coins_test.go +++ b/x/fungible/keeper/foreign_coins_test.go @@ -2,8 +2,10 @@ package keeper_test import ( "strconv" + "strings" "testing" + "cosmossdk.io/math" "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/pkg/coin" keepertest "github.com/zeta-chain/zetacore/testutil/keeper" @@ -152,3 +154,67 @@ func TestKeeperGetForeignCoinFromAsset(t *testing.T) { require.Equal(t, "foo", fc.Name) }) } + +func TestKeeperGetAllForeignCoinMap(t *testing.T) { + t.Run("can get all foreign foreign map", func(t *testing.T) { + k, ctx, _, _ := keepertest.FungibleKeeper(t) + + // create foreign coins + coinFoo1 := types.ForeignCoins{ + Zrc20ContractAddress: sample.EthAddress().String(), + Asset: strings.ToLower(sample.EthAddress().String()), + ForeignChainId: 1, + Decimals: 6, + CoinType: coin.CoinType_ERC20, + Name: "foo", + LiquidityCap: math.NewUint(100), + } + coinBar1 := types.ForeignCoins{ + Zrc20ContractAddress: sample.EthAddress().String(), + Asset: "", + ForeignChainId: 1, + Decimals: 18, + CoinType: coin.CoinType_Gas, + Name: "bar", + LiquidityCap: math.NewUint(100), + } + coinFoo2 := types.ForeignCoins{ + Zrc20ContractAddress: sample.EthAddress().String(), + Asset: strings.ToLower(sample.EthAddress().String()), + ForeignChainId: 2, + Decimals: 8, + CoinType: coin.CoinType_ERC20, + Name: "foo", + LiquidityCap: math.NewUint(200), + } + coinBar2 := types.ForeignCoins{ + Zrc20ContractAddress: sample.EthAddress().String(), + Asset: "", + ForeignChainId: 2, + Decimals: 18, + CoinType: coin.CoinType_Gas, + Name: "bar", + LiquidityCap: math.NewUint(200), + } + + // populate and get + setForeignCoins(ctx, k, + coinFoo1, + coinBar1, + coinFoo2, + coinBar2, + ) + foreignCoinMap := k.GetAllForeignCoinMap(ctx) + + // check length + require.Len(t, foreignCoinMap, 2) + require.Len(t, foreignCoinMap[1], 2) + require.Len(t, foreignCoinMap[2], 2) + + // check coin + require.Equal(t, coinFoo1, foreignCoinMap[1][coinFoo1.Asset]) + require.Equal(t, coinBar1, foreignCoinMap[1][coinBar1.Asset]) + require.Equal(t, coinFoo2, foreignCoinMap[2][coinFoo2.Asset]) + require.Equal(t, coinBar2, foreignCoinMap[2][coinBar2.Asset]) + }) +} From 61627b1b22a0400c7f865f4c64b000ea4824a4bf Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Thu, 25 Apr 2024 01:57:26 -0500 Subject: [PATCH 25/33] treat Rate as average block rate; stop outbound when current rate limit exceeds Rate; updated metrics --- docs/openapi/openapi.swagger.yaml | 6 +- proto/crosschain/query.proto | 5 +- typescript/crosschain/query_pb.d.ts | 11 +- .../keeper/grpc_query_cctx_rate_limit.go | 83 ++-- .../keeper/grpc_query_cctx_rate_limit_test.go | 437 +++++++++--------- x/crosschain/types/query.pb.go | 325 +++++++------ zetaclient/interfaces/interfaces.go | 2 +- zetaclient/testutils/stub/core_bridge.go | 6 +- zetaclient/zetabridge/query.go | 6 +- zetaclient/zetacore_observer.go | 13 +- 10 files changed, 473 insertions(+), 421 deletions(-) diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index 139ee8110a..903cbd10b2 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -54013,9 +54013,11 @@ definitions: total_pending: type: string format: uint64 - value_within_window: + current_withdraw_window: + type: string + format: int64 + current_withdraw_rate: type: string - format: uint64 rate_limit_exceeded: type: boolean crosschainQueryMessagePassingProtocolFeeResponse: diff --git a/proto/crosschain/query.proto b/proto/crosschain/query.proto index 1ecd041c48..07c65e4c31 100644 --- a/proto/crosschain/query.proto +++ b/proto/crosschain/query.proto @@ -270,8 +270,9 @@ message QueryListPendingCctxWithinRateLimitRequest { message QueryListPendingCctxWithinRateLimitResponse { repeated CrossChainTx cross_chain_tx = 1; uint64 total_pending = 2; - uint64 value_within_window = 3; - bool rate_limit_exceeded = 4; + int64 current_withdraw_window = 3; + string current_withdraw_rate = 4; + bool rate_limit_exceeded = 5; } message QueryLastZetaHeightRequest {} diff --git a/typescript/crosschain/query_pb.d.ts b/typescript/crosschain/query_pb.d.ts index 62e8fdfe3a..19877c30bd 100644 --- a/typescript/crosschain/query_pb.d.ts +++ b/typescript/crosschain/query_pb.d.ts @@ -910,12 +910,17 @@ export declare class QueryListPendingCctxWithinRateLimitResponse extends Message totalPending: bigint; /** - * @generated from field: uint64 value_within_window = 3; + * @generated from field: int64 current_withdraw_window = 3; */ - valueWithinWindow: bigint; + currentWithdrawWindow: bigint; /** - * @generated from field: bool rate_limit_exceeded = 4; + * @generated from field: string current_withdraw_rate = 4; + */ + currentWithdrawRate: string; + + /** + * @generated from field: bool rate_limit_exceeded = 5; */ rateLimitExceeded: boolean; diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go index 95a8c5b031..aadb94674d 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go @@ -31,7 +31,7 @@ func (k Keeper) ListPendingCctxWithinRateLimit(c context.Context, req *types.Que // define a few variables to be used in the query loops limitExceeded := false totalPending := uint64(0) - totalCctxValueInZeta := sdk.NewDec(0) + totalWithdrawInZeta := sdk.NewDec(0) cctxs := make([]*types.CrossChainTx, 0) chains := k.zetaObserverKeeper.GetSupportedForeignChains(ctx) @@ -86,12 +86,14 @@ func (k Keeper) ListPendingCctxWithinRateLimit(c context.Context, req *types.Que if applyLimit { gasCoinRates, erc20CoinRates = k.GetRateLimiterRates(ctx) foreignCoinMap = k.fungibleKeeper.GetAllForeignCoinMap(ctx) - windowLimitInZeta = sdk.NewDecFromBigInt(rateLimitFlags.Rate.BigInt()) - blockLimitInZeta = windowLimitInZeta.Quo(sdk.NewDec(rateLimitFlags.Window)) + + // convert the rate limit from aZETA to ZETA + blockLimitInZeta = sdk.NewDecFromBigInt(rateLimitFlags.Rate.BigInt()).Quo(sdk.NewDec(10).Power(18)) + windowLimitInZeta = blockLimitInZeta.Mul(sdk.NewDec(rateLimitFlags.Window)) } // the criteria to stop adding cctxs to the rpc response - maxCCTXsReached := func() bool { + maxCCTXsReached := func(cctxs []*types.CrossChainTx) bool { // #nosec G701 len always positive return uint32(len(cctxs)) >= limit } @@ -127,19 +129,21 @@ func (k Keeper) ListPendingCctxWithinRateLimit(c context.Context, req *types.Que } } - // invariant: for period of time > window, the average rate per block cannot exceed `blockLimitInZeta` - pendingCctxsLimitInZeta := windowLimitInZeta + // invariant: for period of time >= `rateLimitFlags.Window`, the zetaclient-side average withdraw rate should be <= `blockLimitInZeta` + // otherwise, this query should return empty result and wait for the average rate to drop below `blockLimitInZeta` + withdrawWindow := rateLimitFlags.Window + withdrawLimitInZeta := windowLimitInZeta if lowestPendingCctxHeight != 0 { // `pendingCctxWindow` is the width of [lowestPendingCctxHeight, height] window - // if the window can be wider than the rate limit window, we should adjust the total limit proportionally + // if the window can be wider than `rateLimitFlags.Window`, we should adjust the total withdraw limit proportionally pendingCctxWindow := height - lowestPendingCctxHeight + 1 if pendingCctxWindow > rateLimitFlags.Window { - pendingCctxsLimitInZeta = blockLimitInZeta.Mul(sdk.NewDec(pendingCctxWindow)) + withdrawWindow = pendingCctxWindow + withdrawLimitInZeta = blockLimitInZeta.Mul(sdk.NewDec(pendingCctxWindow)) } } // query backwards for potential missed pending cctxs for each foreign chain -LoopBackwards: for _, chain := range chains { // we should at least query 1000 prior to find any pending cctx that we might have missed // this logic is needed because a confirmation of higher nonce will automatically update the p.NonceLow @@ -151,12 +155,6 @@ LoopBackwards: endNonce = 0 } - // add the pending nonces to the total pending - // Note: the `totalPending` may not be accurate only if the rate limiter triggers early exit - // `totalPending` is now used for metrics only and it's okay to trade off accuracy for performance - // #nosec G701 always in range - totalPending += uint64(pendingNonces.NonceHigh - pendingNonces.NonceLow) - // query cctx by nonce backwards to the left boundary of the rate limit sliding window for nonce := startNonce; nonce >= 0; nonce-- { cctx, err := getCctxByChainIDAndNonce(k, ctx, tss.TssPubkey, chain.ChainId, nonce) @@ -165,53 +163,63 @@ LoopBackwards: } inWindow := isCctxInWindow(cctx) - // We should at least go backwards by 1000 nonces to pick up missed pending cctxs - // We might go even further back if rate limiter is enabled and the endNonce hasn't hit the left window boundary yet - // There are two criteria to stop scanning backwards: - // criteria #1: we'll stop at the left window boundary if the `endNonce` hasn't hit it yet + // we should at least go backwards by 1000 nonces to pick up missed pending cctxs + // we might go even further back if rate limiter is enabled and the endNonce hasn't hit the left window boundary yet + // stop at the left window boundary if the `endNonce` hasn't hit it yet if nonce < endNonce && !inWindow { break } - // criteria #2: we should finish the RPC call if the rate limit is exceeded - if inWindow && rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap, &totalCctxValueInZeta, windowLimitInZeta) { + // skip the cctx if rate limit is exceeded but still accumulate the total withdraw value + if inWindow && rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap, &totalWithdrawInZeta, withdrawLimitInZeta) { limitExceeded = true - break LoopBackwards + continue } // only take a `limit` number of pending cctxs as result but still count the total pending cctxs if IsPending(cctx) { totalPending++ - if !maxCCTXsReached() { + if !maxCCTXsReached(cctxs) { cctxs = append(cctxs, cctx) } } } } + // remember the number of missed pending cctxs + missedPending := len(cctxs) + // query forwards for pending cctxs for each foreign chain -LoopForwards: for _, chain := range chains { // query the pending cctxs in range [NonceLow, NonceHigh) pendingNonces := pendingNoncesMap[chain.ChainId] + + // #nosec G701 always in range + totalPending += uint64(pendingNonces.NonceHigh - pendingNonces.NonceLow) + for nonce := pendingNonces.NonceLow; nonce < pendingNonces.NonceHigh; nonce++ { cctx, err := getCctxByChainIDAndNonce(k, ctx, tss.TssPubkey, chain.ChainId, nonce) if err != nil { return nil, err } - // only take a `limit` number of pending cctxs as result - if maxCCTXsReached() { - break LoopForwards - } - // criteria #2: we should finish the RPC call if the rate limit is exceeded - if rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap, &totalCctxValueInZeta, pendingCctxsLimitInZeta) { + // skip the cctx if rate limit is exceeded but still accumulate the total withdraw value + if rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap, &totalWithdrawInZeta, withdrawLimitInZeta) { limitExceeded = true - break LoopForwards + continue + } + // only take a `limit` number of pending cctxs as result + if maxCCTXsReached(cctxs) { + continue } cctxs = append(cctxs, cctx) } } + // if the rate limit is exceeded, only return the missed pending cctxs + if limitExceeded { + cctxs = cctxs[:missedPending] + } + // sort the cctxs by chain ID and nonce (lower nonce holds higher priority for scheduling) sort.Slice(cctxs, func(i, j int) bool { if cctxs[i].GetCurrentOutTxParam().ReceiverChainId == cctxs[j].GetCurrentOutTxParam().ReceiverChainId { @@ -221,10 +229,11 @@ LoopForwards: }) return &types.QueryListPendingCctxWithinRateLimitResponse{ - CrossChainTx: cctxs, - TotalPending: totalPending, - ValueWithinWindow: totalCctxValueInZeta.TruncateInt().Uint64(), - RateLimitExceeded: limitExceeded, + CrossChainTx: cctxs, + TotalPending: totalPending, + CurrentWithdrawWindow: withdrawWindow, + CurrentWithdrawRate: totalWithdrawInZeta.Mul(sdk.NewDec(10).Power(18)).Quo(sdk.NewDec(withdrawWindow)).String(), + RateLimitExceeded: limitExceeded, }, nil } @@ -298,9 +307,9 @@ func rateLimitExceeded( erc20CoinRates map[int64]map[string]sdk.Dec, foreignCoinMap map[int64]map[string]fungibletypes.ForeignCoins, currentCctxValue *sdk.Dec, - rateLimitValue sdk.Dec, + withdrawLimitInZeta sdk.Dec, ) bool { amountZeta := ConvertCctxValue(chainID, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap) *currentCctxValue = currentCctxValue.Add(amountZeta) - return currentCctxValue.GT(rateLimitValue) + return currentCctxValue.GT(withdrawLimitInZeta) } diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go index f5ed9e4413..2aa96ca51b 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go @@ -145,7 +145,7 @@ func Test_ConvertCctxValue(t *testing.T) { setupForeignCoins(t, ctx, zk, zrc20ETH, zrc20BTC, zrc20USDT, assetUSDT) // Set rate limiter flags - rateLimiterFlags := createTestRateLimiterFlags(500, math.NewUint(5000), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8") + rateLimiterFlags := createTestRateLimiterFlags(500, math.NewUint(10), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8") k.SetRateLimiterFlags(ctx, *rateLimiterFlags) // get rate limiter rates @@ -286,6 +286,7 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { // define test cases tests := []struct { name string + fallback bool rateLimitFlags *types.RateLimiterFlags // Eth chain cctxs setup @@ -303,226 +304,206 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { queryLimit uint32 // expected results - expectedCctxs []*types.CrossChainTx - expectedTotalPending uint64 - expectedTotalValue uint64 - rateLimitExceeded bool + expectedCctxs []*types.CrossChainTx + expectedTotalPending uint64 + expectedWithdrawWindow int64 + expectedWithdrawRate string + rateLimitExceeded bool }{ + // { + // name: "should use fallback query if rate limiter is disabled", + // fallback: true, + // rateLimitFlags: nil, // no rate limiter flags set in the keeper + // ethMinedCctxs: ethMinedCctxs, + // ethPendingCctxs: ethPendingCctxs, + // ethPendingNonces: observertypes.PendingNonces{ + // ChainId: ethChainID, + // NonceLow: 1099, + // NonceHigh: 1199, + // Tss: tss.TssPubkey, + // }, + // btcMinedCctxs: btcMinedCctxs, + // btcPendingCctxs: btcPendingCctxs, + // btcPendingNonces: observertypes.PendingNonces{ + // ChainId: btcChainID, + // NonceLow: 1099, + // NonceHigh: 1199, + // Tss: tss.TssPubkey, + // }, + // currentHeight: 1199, + // queryLimit: keeper.MaxPendingCctxs, + // expectedCctxs: append(append([]*types.CrossChainTx{}, btcPendingCctxs...), ethPendingCctxs...), + // expectedTotalPending: 400, + // }, + // { + // name: "should use fallback query if rate is 0", + // fallback: true, + // rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(0), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), + // ethMinedCctxs: ethMinedCctxs, + // ethPendingCctxs: ethPendingCctxs, + // ethPendingNonces: observertypes.PendingNonces{ + // ChainId: ethChainID, + // NonceLow: 1099, + // NonceHigh: 1199, + // Tss: tss.TssPubkey, + // }, + // btcMinedCctxs: btcMinedCctxs, + // btcPendingCctxs: btcPendingCctxs, + // btcPendingNonces: observertypes.PendingNonces{ + // ChainId: btcChainID, + // NonceLow: 1099, + // NonceHigh: 1199, + // Tss: tss.TssPubkey, + // }, + // currentHeight: 1199, + // queryLimit: keeper.MaxPendingCctxs, + // expectedCctxs: append(append([]*types.CrossChainTx{}, btcPendingCctxs...), ethPendingCctxs...), + // expectedTotalPending: 400, + // }, + // { + // name: "can retrieve all pending cctx without exceeding rate limit", + // rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(10*1e18), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), + // ethMinedCctxs: ethMinedCctxs, + // ethPendingCctxs: ethPendingCctxs, + // ethPendingNonces: observertypes.PendingNonces{ + // ChainId: ethChainID, + // NonceLow: 1099, + // NonceHigh: 1199, + // Tss: tss.TssPubkey, + // }, + // btcMinedCctxs: btcMinedCctxs, + // btcPendingCctxs: btcPendingCctxs, + // btcPendingNonces: observertypes.PendingNonces{ + // ChainId: btcChainID, + // NonceLow: 1099, + // NonceHigh: 1199, + // Tss: tss.TssPubkey, + // }, + // currentHeight: 1199, + // queryLimit: keeper.MaxPendingCctxs, + // expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs...), btcPendingCctxs...), + // expectedTotalPending: 400, + // expectedWithdrawWindow: 500, // the sliding window + // expectedWithdrawRate: sdk.NewDec(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block + // rateLimitExceeded: false, + // }, + // { + // name: "can loop backwards all the way to endNonce 0", + // rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(10*1e18), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), + // ethMinedCctxs: ethMinedCctxs, + // ethPendingCctxs: ethPendingCctxs, + // ethPendingNonces: observertypes.PendingNonces{ + // ChainId: ethChainID, + // NonceLow: 999, // endNonce will be set to 0 (NonceLow - 1000 < 0) + // NonceHigh: 1199, + // Tss: tss.TssPubkey, + // }, + // btcMinedCctxs: btcMinedCctxs, + // btcPendingCctxs: btcPendingCctxs, + // btcPendingNonces: observertypes.PendingNonces{ + // ChainId: btcChainID, + // NonceLow: 999, // endNonce will be set to 0 (NonceLow - 1000 < 0) + // NonceHigh: 1199, + // Tss: tss.TssPubkey, + // }, + // currentHeight: 1199, + // queryLimit: keeper.MaxPendingCctxs, + // expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs...), btcPendingCctxs...), + // expectedTotalPending: 400, + // expectedWithdrawWindow: 500, // the sliding window + // expectedWithdrawRate: sdk.NewDec(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block + // rateLimitExceeded: false, + // }, + // { + // name: "set a low rate (rate < 2.4 ZETA) to exceed rate limit in backward loop", + // rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(2*1e18), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), + // ethMinedCctxs: ethMinedCctxs, + // ethPendingCctxs: ethPendingCctxs, + // ethPendingNonces: observertypes.PendingNonces{ + // ChainId: ethChainID, + // NonceLow: 1099, + // NonceHigh: 1199, + // Tss: tss.TssPubkey, + // }, + // btcMinedCctxs: btcMinedCctxs, + // btcPendingCctxs: btcPendingCctxs, + // btcPendingNonces: observertypes.PendingNonces{ + // ChainId: btcChainID, + // NonceLow: 1099, + // NonceHigh: 1199, + // Tss: tss.TssPubkey, + // }, + // currentHeight: 1199, + // queryLimit: keeper.MaxPendingCctxs, + // // return missed cctxs only if rate limit is exceeded + // expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs[0:100]...), btcPendingCctxs[0:100]...), + // expectedTotalPending: 400, + // expectedWithdrawWindow: 500, // the sliding window + // expectedWithdrawRate: sdk.NewDec(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block + // rateLimitExceeded: true, + // }, + // { + // name: "set a lower gRPC request limit and reach the limit of the query in forward loop", + // rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(10*1e18), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), + // ethMinedCctxs: ethMinedCctxs, + // ethPendingCctxs: ethPendingCctxs, + // ethPendingNonces: observertypes.PendingNonces{ + // ChainId: ethChainID, + // NonceLow: 1099, + // NonceHigh: 1199, + // Tss: tss.TssPubkey, + // }, + // btcMinedCctxs: btcMinedCctxs, + // btcPendingCctxs: btcPendingCctxs, + // btcPendingNonces: observertypes.PendingNonces{ + // ChainId: btcChainID, + // NonceLow: 1099, + // NonceHigh: 1199, + // Tss: tss.TssPubkey, + // }, + // currentHeight: 1199, + // queryLimit: 300, // 300 < keeper.MaxPendingCctxs + // expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs[0:100]...), btcPendingCctxs...), + // expectedTotalPending: 400, + // expectedWithdrawWindow: 500, // the sliding window + // expectedWithdrawRate: sdk.NewDec(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block + // rateLimitExceeded: false, + // }, + // { + // name: "set a median rate (2.4 ZETA < rate < 3 ZETA) to exceed rate limit in forward loop", + // rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(26*1e17), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), + // ethMinedCctxs: ethMinedCctxs, + // ethPendingCctxs: ethPendingCctxs, + // ethPendingNonces: observertypes.PendingNonces{ + // ChainId: ethChainID, + // NonceLow: 1099, + // NonceHigh: 1199, + // Tss: tss.TssPubkey, + // }, + // btcMinedCctxs: btcMinedCctxs, + // btcPendingCctxs: btcPendingCctxs, + // btcPendingNonces: observertypes.PendingNonces{ + // ChainId: btcChainID, + // NonceLow: 1099, + // NonceHigh: 1199, + // Tss: tss.TssPubkey, + // }, + // currentHeight: 1199, + // queryLimit: keeper.MaxPendingCctxs, + // // return missed cctxs only if rate limit is exceeded + // expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs[0:100]...), btcPendingCctxs[0:100]...), + // expectedTotalPending: 400, + // expectedWithdrawWindow: 500, // the sliding window + // expectedWithdrawRate: sdk.NewDec(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block + // rateLimitExceeded: true, + // }, { - name: "should use fallback query if rate limiter is disabled", - rateLimitFlags: nil, // no rate limiter flags set in the keeper - ethMinedCctxs: ethMinedCctxs, - ethPendingCctxs: ethPendingCctxs, - ethPendingNonces: observertypes.PendingNonces{ - ChainId: ethChainID, - NonceLow: 1099, - NonceHigh: 1199, - Tss: tss.TssPubkey, - }, - btcMinedCctxs: btcMinedCctxs, - btcPendingCctxs: btcPendingCctxs, - btcPendingNonces: observertypes.PendingNonces{ - ChainId: btcChainID, - NonceLow: 1099, - NonceHigh: 1199, - Tss: tss.TssPubkey, - }, - currentHeight: 1199, - queryLimit: keeper.MaxPendingCctxs, - expectedCctxs: append(append([]*types.CrossChainTx{}, btcPendingCctxs...), ethPendingCctxs...), - expectedTotalPending: 400, - }, - { - name: "should use fallback query if rate is 0", - rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(0), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), - ethMinedCctxs: ethMinedCctxs, - ethPendingCctxs: ethPendingCctxs, - ethPendingNonces: observertypes.PendingNonces{ - ChainId: ethChainID, - NonceLow: 1099, - NonceHigh: 1199, - Tss: tss.TssPubkey, - }, - btcMinedCctxs: btcMinedCctxs, - btcPendingCctxs: btcPendingCctxs, - btcPendingNonces: observertypes.PendingNonces{ - ChainId: btcChainID, - NonceLow: 1099, - NonceHigh: 1199, - Tss: tss.TssPubkey, - }, - currentHeight: 1199, - queryLimit: keeper.MaxPendingCctxs, - expectedCctxs: append(append([]*types.CrossChainTx{}, btcPendingCctxs...), ethPendingCctxs...), - expectedTotalPending: 400, - }, - { - name: "can retrieve pending cctx in range without exceeding rate limit", - rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(5000), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), - ethMinedCctxs: ethMinedCctxs, - ethPendingCctxs: ethPendingCctxs, - ethPendingNonces: observertypes.PendingNonces{ - ChainId: ethChainID, - NonceLow: 1099, - NonceHigh: 1199, - Tss: tss.TssPubkey, - }, - btcMinedCctxs: btcMinedCctxs, - btcPendingCctxs: btcPendingCctxs, - btcPendingNonces: observertypes.PendingNonces{ - ChainId: btcChainID, - NonceLow: 1099, - NonceHigh: 1199, - Tss: tss.TssPubkey, - }, - currentHeight: 1199, - queryLimit: keeper.MaxPendingCctxs, - expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs...), btcPendingCctxs...), - expectedTotalPending: 400, - expectedTotalValue: 1500, // 500 (window) * (2.5 + 0.5) - rateLimitExceeded: false, - }, - { - name: "can loop backwards all the way to endNonce 0", - rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(5000), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), - ethMinedCctxs: ethMinedCctxs, - ethPendingCctxs: ethPendingCctxs, - ethPendingNonces: observertypes.PendingNonces{ - ChainId: ethChainID, - NonceLow: 999, // endNonce will set to 0 as NonceLow - 1000 < 0 - NonceHigh: 1199, - Tss: tss.TssPubkey, - }, - btcMinedCctxs: btcMinedCctxs, - btcPendingCctxs: btcPendingCctxs, - btcPendingNonces: observertypes.PendingNonces{ - ChainId: btcChainID, - NonceLow: 999, // endNonce will set to 0 as NonceLow - 1000 < 0 - NonceHigh: 1199, - Tss: tss.TssPubkey, - }, - currentHeight: 1199, - queryLimit: keeper.MaxPendingCctxs, - expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs...), btcPendingCctxs...), - expectedTotalPending: 400, - expectedTotalValue: 1500, // 500 (window) * (2.5 + 0.5) - rateLimitExceeded: false, - }, - { - name: "set a low rate (< 1200) to early break the LoopBackwards with criteria #2", - rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(1000), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), // 1000 < 1200 - ethMinedCctxs: ethMinedCctxs, - ethPendingCctxs: ethPendingCctxs, - ethPendingNonces: observertypes.PendingNonces{ - ChainId: ethChainID, - NonceLow: 1099, - NonceHigh: 1199, - Tss: tss.TssPubkey, - }, - btcMinedCctxs: btcMinedCctxs, - btcPendingCctxs: btcPendingCctxs, - btcPendingNonces: observertypes.PendingNonces{ - ChainId: btcChainID, - NonceLow: 1099, - NonceHigh: 1199, - Tss: tss.TssPubkey, - }, - currentHeight: 1199, - queryLimit: keeper.MaxPendingCctxs, - expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs[0:100]...), btcPendingCctxs[0:100]...), - expectedTotalPending: 400, - rateLimitExceeded: true, - }, - { - // this test case is to break the LoopBackwards with criteria #1: the 1st break in LoopBackwards - name: "set high rate and wide window to break inner loop of LoopBackwards when left window boundary is reached", - // The left boundary will be 49 (currentHeight-1150), which will be less than the endNonce 99 (1099 - 1000) - rateLimitFlags: createTestRateLimiterFlags(1150, math.NewUint(10000), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), - ethMinedCctxs: ethMinedCctxs, - ethPendingCctxs: ethPendingCctxs, - ethPendingNonces: observertypes.PendingNonces{ - ChainId: ethChainID, - NonceLow: 1099, - NonceHigh: 1199, - Tss: tss.TssPubkey, - }, - btcMinedCctxs: btcMinedCctxs, - btcPendingCctxs: btcPendingCctxs, - btcPendingNonces: observertypes.PendingNonces{ - ChainId: btcChainID, - NonceLow: 1099, - NonceHigh: 1199, - Tss: tss.TssPubkey, - }, - currentHeight: 1199, - queryLimit: keeper.MaxPendingCctxs, - expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs...), btcPendingCctxs...), - expectedTotalPending: 400, - expectedTotalValue: 3450, // 1150 (window) * (2.5 + 0.5) - rateLimitExceeded: false, - }, - { - name: "set lower request limit to early break the LoopForwards loop", - rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(5000), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), - ethMinedCctxs: ethMinedCctxs, - ethPendingCctxs: ethPendingCctxs, - ethPendingNonces: observertypes.PendingNonces{ - ChainId: ethChainID, - NonceLow: 1099, - NonceHigh: 1199, - Tss: tss.TssPubkey, - }, - btcMinedCctxs: btcMinedCctxs, - btcPendingCctxs: btcPendingCctxs, - btcPendingNonces: observertypes.PendingNonces{ - ChainId: btcChainID, - NonceLow: 1099, - NonceHigh: 1199, - Tss: tss.TssPubkey, - }, - currentHeight: 1199, - queryLimit: 300, // 300 < keeper.MaxPendingCctxs - expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs[0:100]...), btcPendingCctxs...), - expectedTotalPending: 400, - expectedTotalValue: 1250, // 500 * 0.5 + 400 * 2.5 - rateLimitExceeded: false, - }, - { - // all pending cctxs fall within the sliding window in this test case. - // this test case is to break the LoopBackwards with criteria #2: the 2nd break in LoopForwards - name: "set rate to middle value (1200 < rate < 1500) to early break the LoopForwards when rate limit is exceeded", - rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(1300), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), // 1200 < 1300 < 1500 - ethMinedCctxs: ethMinedCctxs, - ethPendingCctxs: ethPendingCctxs, - ethPendingNonces: observertypes.PendingNonces{ - ChainId: ethChainID, - NonceLow: 1099, - NonceHigh: 1199, - Tss: tss.TssPubkey, - }, - btcMinedCctxs: btcMinedCctxs, - btcPendingCctxs: btcPendingCctxs, - btcPendingNonces: observertypes.PendingNonces{ - ChainId: btcChainID, - NonceLow: 1099, - NonceHigh: 1199, - Tss: tss.TssPubkey, - }, - currentHeight: 1199, - queryLimit: keeper.MaxPendingCctxs, - // 120 ETH cctx + 200 BTC cctx - expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs[0:120]...), btcPendingCctxs...), - expectedTotalPending: 400, - rateLimitExceeded: true, - }, - { - // many pending cctxs fall beyond the sliding window in this test case. - // this test case is to break the LoopBackwards with criteria #2: the 2nd break in LoopForwards - name: "set low rate and narrow window to early break the LoopForwards when rate limit is exceeded", + // the pending cctxs window is wider than the rate limiter sliding window in this test case. + name: "set low rate and narrow window to early exceed rate limit in forward loop", // the left boundary will be 1149 (currentHeight-50), the pending nonces [1099, 1148] fall beyond the left boundary. // `pendingCctxWindow` is 100 which is wider than rate limiter window 50. // give a block rate of 2 ZETA/block, the max value allowed should be 100 * 2 = 200 ZETA - rateLimitFlags: createTestRateLimiterFlags(50, math.NewUint(100), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), + rateLimitFlags: createTestRateLimiterFlags(50, math.NewUint(2*1e18), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), ethMinedCctxs: ethMinedCctxs, ethPendingCctxs: ethPendingCctxs, ethPendingNonces: observertypes.PendingNonces{ @@ -541,10 +522,12 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { }, currentHeight: 1199, queryLimit: keeper.MaxPendingCctxs, - // 160 ETH cctx + 200 BTC cctx - expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs[0:160]...), btcPendingCctxs...), - expectedTotalPending: 400, - rateLimitExceeded: true, + // return missed cctxs only if rate limit is exceeded + expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs[0:100]...), btcPendingCctxs[0:100]...), + expectedTotalPending: 400, + expectedWithdrawWindow: 100, // 100 > sliding window 50 + expectedWithdrawRate: sdk.NewDec(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block + rateLimitExceeded: true, }, } @@ -582,15 +565,13 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { res, err := k.ListPendingCctxWithinRateLimit(ctx, &types.QueryListPendingCctxWithinRateLimitRequest{Limit: tt.queryLimit}) require.NoError(t, err) require.EqualValues(t, tt.expectedCctxs, res.CrossChainTx) - require.EqualValues(t, tt.expectedTotalPending, res.TotalPending) + require.Equal(t, tt.expectedTotalPending, res.TotalPending) - // check rate limiter related fields only if rate limiter flags is enabled - if tt.rateLimitFlags != nil { - if !tt.rateLimitExceeded { - require.EqualValues(t, tt.expectedTotalValue, res.ValueWithinWindow) - } else { - require.True(t, res.ValueWithinWindow > tt.rateLimitFlags.Rate.Uint64()) - } + // check rate limiter related fields only if it's not a fallback query + if !tt.fallback { + require.Equal(t, tt.expectedWithdrawWindow, res.CurrentWithdrawWindow) + require.Equal(t, tt.expectedWithdrawRate, res.CurrentWithdrawRate) + require.Equal(t, tt.rateLimitExceeded, res.RateLimitExceeded) } }) } diff --git a/x/crosschain/types/query.pb.go b/x/crosschain/types/query.pb.go index 4d7c826736..8fce000ace 100644 --- a/x/crosschain/types/query.pb.go +++ b/x/crosschain/types/query.pb.go @@ -1636,10 +1636,11 @@ func (m *QueryListPendingCctxWithinRateLimitRequest) GetLimit() uint32 { } type QueryListPendingCctxWithinRateLimitResponse struct { - CrossChainTx []*CrossChainTx `protobuf:"bytes,1,rep,name=cross_chain_tx,json=crossChainTx,proto3" json:"cross_chain_tx,omitempty"` - TotalPending uint64 `protobuf:"varint,2,opt,name=total_pending,json=totalPending,proto3" json:"total_pending,omitempty"` - ValueWithinWindow uint64 `protobuf:"varint,3,opt,name=value_within_window,json=valueWithinWindow,proto3" json:"value_within_window,omitempty"` - RateLimitExceeded bool `protobuf:"varint,4,opt,name=rate_limit_exceeded,json=rateLimitExceeded,proto3" json:"rate_limit_exceeded,omitempty"` + CrossChainTx []*CrossChainTx `protobuf:"bytes,1,rep,name=cross_chain_tx,json=crossChainTx,proto3" json:"cross_chain_tx,omitempty"` + TotalPending uint64 `protobuf:"varint,2,opt,name=total_pending,json=totalPending,proto3" json:"total_pending,omitempty"` + CurrentWithdrawWindow int64 `protobuf:"varint,3,opt,name=current_withdraw_window,json=currentWithdrawWindow,proto3" json:"current_withdraw_window,omitempty"` + CurrentWithdrawRate string `protobuf:"bytes,4,opt,name=current_withdraw_rate,json=currentWithdrawRate,proto3" json:"current_withdraw_rate,omitempty"` + RateLimitExceeded bool `protobuf:"varint,5,opt,name=rate_limit_exceeded,json=rateLimitExceeded,proto3" json:"rate_limit_exceeded,omitempty"` } func (m *QueryListPendingCctxWithinRateLimitResponse) Reset() { @@ -1693,13 +1694,20 @@ func (m *QueryListPendingCctxWithinRateLimitResponse) GetTotalPending() uint64 { return 0 } -func (m *QueryListPendingCctxWithinRateLimitResponse) GetValueWithinWindow() uint64 { +func (m *QueryListPendingCctxWithinRateLimitResponse) GetCurrentWithdrawWindow() int64 { if m != nil { - return m.ValueWithinWindow + return m.CurrentWithdrawWindow } return 0 } +func (m *QueryListPendingCctxWithinRateLimitResponse) GetCurrentWithdrawRate() string { + if m != nil { + return m.CurrentWithdrawRate + } + return "" +} + func (m *QueryListPendingCctxWithinRateLimitResponse) GetRateLimitExceeded() bool { if m != nil { return m.RateLimitExceeded @@ -2110,128 +2118,130 @@ func init() { func init() { proto.RegisterFile("crosschain/query.proto", fileDescriptor_65a992045e92a606) } var fileDescriptor_65a992045e92a606 = []byte{ - // 1931 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5a, 0x41, 0x6f, 0xdc, 0xc6, - 0x15, 0xf6, 0x68, 0xed, 0x44, 0x1e, 0xc9, 0x56, 0x34, 0x51, 0x5d, 0x95, 0x91, 0x56, 0x36, 0x55, - 0x5b, 0xaa, 0x54, 0x2d, 0x23, 0x39, 0x56, 0x6a, 0x5b, 0x29, 0xba, 0x92, 0x23, 0x45, 0xad, 0x92, - 0x28, 0x0b, 0x15, 0x2e, 0x5c, 0x14, 0xc4, 0x88, 0x3b, 0xe1, 0x12, 0xa1, 0x48, 0x65, 0x39, 0x6b, - 0xaf, 0x2c, 0xe8, 0x12, 0xa0, 0x3d, 0x17, 0xc8, 0xa1, 0x97, 0x5e, 0x8b, 0xe6, 0xd0, 0x43, 0x0f, - 0x45, 0x7b, 0x28, 0x90, 0xa2, 0x68, 0xeb, 0xfa, 0x18, 0xa0, 0x40, 0x51, 0xb4, 0x40, 0x51, 0xd8, - 0xfd, 0x05, 0xfd, 0x05, 0x05, 0x87, 0x8f, 0xbb, 0x43, 0x2e, 0xb9, 0x3b, 0x5a, 0x6d, 0x0e, 0x3e, - 0x79, 0xc9, 0x99, 0xf7, 0xe6, 0xfb, 0xde, 0xbc, 0x79, 0x7c, 0xf3, 0x59, 0xf8, 0x8a, 0x55, 0xf7, - 0x83, 0xc0, 0xaa, 0x51, 0xc7, 0x33, 0x3e, 0x6e, 0xb0, 0xfa, 0x51, 0xe9, 0xb0, 0xee, 0x73, 0x9f, - 0x4c, 0x3f, 0x66, 0x9c, 0x8a, 0xd7, 0x25, 0xf1, 0xcb, 0xaf, 0xb3, 0x52, 0x7b, 0xaa, 0xb6, 0x60, - 0xf9, 0xc1, 0x81, 0x1f, 0x18, 0xfb, 0x34, 0x60, 0x91, 0x9d, 0xf1, 0x70, 0x79, 0x9f, 0x71, 0xba, - 0x6c, 0x1c, 0x52, 0xdb, 0xf1, 0x28, 0x77, 0x7c, 0x2f, 0x72, 0xa5, 0xcd, 0x48, 0x4b, 0x88, 0x9f, - 0xa6, 0xf8, 0x6d, 0xf2, 0x26, 0x4c, 0xd0, 0xa4, 0x09, 0x36, 0x0d, 0xcc, 0xc3, 0xba, 0x63, 0x31, - 0x18, 0x9b, 0x95, 0xc6, 0x84, 0x8d, 0x59, 0xa3, 0x41, 0xcd, 0xe4, 0xbe, 0x69, 0x59, 0x2d, 0x07, - 0xc5, 0x8e, 0x49, 0xbc, 0x4e, 0xad, 0x8f, 0x58, 0x1d, 0xc6, 0x75, 0x69, 0xdc, 0xa5, 0x01, 0x37, - 0xf7, 0x5d, 0xdf, 0xfa, 0xc8, 0xac, 0x31, 0xc7, 0xae, 0xf1, 0x0c, 0x94, 0x7e, 0x83, 0x77, 0x3a, - 0x91, 0x91, 0xd4, 0x29, 0x67, 0xa6, 0xeb, 0x1c, 0x38, 0x9c, 0xd5, 0xcd, 0x0f, 0x5d, 0x6a, 0x07, - 0x30, 0x69, 0xc2, 0xf6, 0x6d, 0x5f, 0xfc, 0x34, 0xc2, 0x5f, 0xf0, 0x76, 0xca, 0xf6, 0x7d, 0xdb, - 0x65, 0x06, 0x3d, 0x74, 0x0c, 0xea, 0x79, 0x3e, 0x17, 0xe1, 0x01, 0x1b, 0x7d, 0x0a, 0x6b, 0x1f, - 0x84, 0x11, 0x7c, 0xc0, 0x38, 0x2d, 0x5b, 0x96, 0xdf, 0xf0, 0xb8, 0xe3, 0xd9, 0x15, 0xf6, 0x71, - 0x83, 0x05, 0x5c, 0x7f, 0x17, 0xbf, 0x96, 0x39, 0x1a, 0x1c, 0xfa, 0x5e, 0xc0, 0x48, 0x09, 0xbf, - 0x4a, 0xf7, 0xfd, 0x3a, 0x67, 0x55, 0x33, 0xdc, 0x27, 0x93, 0x1e, 0x84, 0x33, 0x26, 0xd1, 0x55, - 0x34, 0x7f, 0xb1, 0x32, 0x0e, 0x43, 0xc2, 0x56, 0x0c, 0xb4, 0xdc, 0x6d, 0x31, 0xfe, 0x7e, 0x83, - 0xef, 0x35, 0xf7, 0x22, 0x8e, 0xb0, 0x1a, 0x99, 0xc4, 0x2f, 0x0b, 0x86, 0xdb, 0xf7, 0x84, 0x8b, - 0x42, 0x25, 0x7e, 0x24, 0x13, 0xf8, 0x82, 0xe7, 0x7b, 0x16, 0x9b, 0x1c, 0xba, 0x8a, 0xe6, 0xcf, - 0x57, 0xa2, 0x07, 0xbd, 0x81, 0xa7, 0xb2, 0xdd, 0x01, 0xbc, 0xef, 0xe3, 0x51, 0x5f, 0x7a, 0x2f, - 0x9c, 0x8e, 0xac, 0x2c, 0x96, 0xba, 0x66, 0x57, 0x49, 0x76, 0xb5, 0x7e, 0xfe, 0xe9, 0xbf, 0x67, - 0xce, 0x55, 0x12, 0x6e, 0x74, 0x06, 0x2c, 0xca, 0xae, 0x9b, 0xc5, 0x62, 0x13, 0xe3, 0x76, 0x16, - 0xc2, 0x9a, 0x37, 0x4a, 0x51, 0xca, 0x96, 0xc2, 0x94, 0x2d, 0x45, 0xa9, 0x0e, 0x29, 0x5b, 0xda, - 0xa5, 0x36, 0x03, 0xdb, 0x8a, 0x64, 0xa9, 0x7f, 0x8e, 0x80, 0x5e, 0xc7, 0x3a, 0xb9, 0xf4, 0x0a, - 0x03, 0xa0, 0x47, 0xb6, 0x12, 0xf8, 0x87, 0x04, 0xfe, 0xb9, 0x9e, 0xf8, 0x23, 0x4c, 0x09, 0x02, - 0x9f, 0x20, 0xac, 0x67, 0x11, 0x58, 0x3f, 0xda, 0x08, 0x91, 0xc4, 0xf1, 0x9a, 0xc0, 0x17, 0x04, - 0x32, 0xd8, 0xf3, 0xe8, 0x21, 0x15, 0xc5, 0xa1, 0xbe, 0xa3, 0xf8, 0x17, 0x84, 0x67, 0xbb, 0x82, - 0x78, 0x41, 0x82, 0xf9, 0x13, 0x84, 0xaf, 0xc5, 0x3c, 0xb6, 0xbd, 0xbc, 0x58, 0x7e, 0x0d, 0x0f, - 0x47, 0xe5, 0xcd, 0xa9, 0x26, 0x8f, 0x50, 0x75, 0x60, 0x01, 0xfd, 0xa3, 0xb4, 0xab, 0x59, 0x40, - 0x20, 0x9e, 0x15, 0x3c, 0xe2, 0x78, 0xe9, 0x70, 0x2e, 0xf4, 0x08, 0xa7, 0xec, 0x2f, 0x8a, 0xa6, - 0xec, 0x64, 0x70, 0xc1, 0x94, 0x4e, 0xb0, 0xb4, 0x64, 0x30, 0xe8, 0x13, 0xfc, 0x7b, 0xe9, 0x04, - 0x27, 0xd7, 0x79, 0x11, 0x82, 0x74, 0x17, 0x4f, 0xc7, 0xd5, 0x35, 0x5c, 0xf2, 0x1d, 0x1a, 0xd4, - 0xf6, 0xfc, 0x0d, 0x8b, 0x37, 0xe3, 0x30, 0x69, 0x78, 0xd8, 0x81, 0x01, 0x28, 0xf9, 0xad, 0x67, - 0xfd, 0x04, 0x17, 0xf3, 0x8c, 0x81, 0xfb, 0x0f, 0xf1, 0x65, 0x27, 0x31, 0x02, 0x81, 0x5e, 0x52, - 0xa0, 0xdf, 0x36, 0x82, 0x08, 0xa4, 0x5c, 0xe9, 0x6b, 0xb0, 0x7c, 0x72, 0xf2, 0x3d, 0xca, 0xa9, - 0x0a, 0xf8, 0xc7, 0x78, 0x26, 0xd7, 0x1a, 0xd0, 0xdf, 0xc7, 0x97, 0x36, 0x42, 0x4c, 0x22, 0xe9, - 0xf7, 0x9a, 0x81, 0x62, 0xbd, 0x90, 0x6d, 0x00, 0x7a, 0xd2, 0x8f, 0x6e, 0x43, 0xd4, 0x21, 0x65, - 0x3a, 0xa3, 0x3e, 0xa8, 0xe4, 0x7c, 0x82, 0x20, 0x46, 0x19, 0x2b, 0x75, 0xd9, 0xa2, 0xc2, 0x80, - 0xb6, 0x68, 0x70, 0x79, 0x6a, 0xe0, 0xaf, 0xc6, 0xa9, 0xb6, 0x45, 0x83, 0xdd, 0xb0, 0x7d, 0x93, - 0x3e, 0x2d, 0x8e, 0x57, 0x65, 0x4d, 0xd8, 0xe1, 0xe8, 0x41, 0x37, 0xf1, 0x64, 0xa7, 0x01, 0x50, - 0xde, 0xc0, 0xc3, 0xf1, 0x3b, 0x88, 0xed, 0x5c, 0x0f, 0xb2, 0x2d, 0x17, 0x2d, 0x43, 0x9d, 0x02, - 0xa2, 0xb2, 0xeb, 0xa6, 0x11, 0x0d, 0x6a, 0xf7, 0x3e, 0x43, 0x40, 0x22, 0xb1, 0x46, 0x26, 0x89, - 0x42, 0x5f, 0x24, 0x06, 0xb7, 0x3f, 0xab, 0xed, 0x52, 0xb0, 0x43, 0x03, 0xbe, 0x1e, 0x76, 0xbf, - 0xef, 0x88, 0xe6, 0xb7, 0xfb, 0x36, 0x1d, 0xc3, 0x29, 0xcc, 0xb2, 0x03, 0xa2, 0x3f, 0xc0, 0x63, - 0xa9, 0x21, 0x08, 0x69, 0xa9, 0x07, 0xdf, 0xb4, 0xc3, 0xb4, 0x1b, 0xbd, 0xd6, 0x3e, 0x1c, 0x39, - 0xa0, 0x07, 0xb5, 0x93, 0x7f, 0x46, 0xc0, 0x33, 0x6b, 0xa9, 0x6e, 0x3c, 0x0b, 0x03, 0xe0, 0x39, - 0xb8, 0x5d, 0x5e, 0xc4, 0xaf, 0xc6, 0xbb, 0x25, 0x57, 0xab, 0xec, 0xad, 0xdd, 0x81, 0x4b, 0x07, - 0x4c, 0x5e, 0x3f, 0x7a, 0x2f, 0xec, 0xe7, 0xfb, 0xbd, 0x06, 0xd8, 0x78, 0x22, 0xb9, 0x34, 0x44, - 0xed, 0x7d, 0x3c, 0x2a, 0xd7, 0x56, 0xc5, 0xf6, 0x5f, 0x36, 0xa9, 0x24, 0x1c, 0xe8, 0x3f, 0x02, - 0x8e, 0x65, 0xd7, 0xfd, 0x32, 0x2a, 0xf2, 0xaf, 0x11, 0x10, 0x69, 0xf9, 0xcf, 0x25, 0x52, 0x38, - 0x13, 0x91, 0xc1, 0xed, 0xfa, 0x7b, 0xd0, 0x48, 0xed, 0x38, 0x01, 0xdf, 0x65, 0x5e, 0xd5, 0xf1, - 0x6c, 0x39, 0x32, 0x5d, 0xda, 0xd1, 0x09, 0x7c, 0x41, 0x5c, 0x61, 0xc5, 0xea, 0x97, 0x2a, 0xd1, - 0x83, 0xfe, 0x69, 0xdc, 0x31, 0x75, 0x38, 0xfc, 0xb2, 0x42, 0xa1, 0xe3, 0x51, 0xee, 0x73, 0xea, - 0xc2, 0x62, 0x90, 0x59, 0x89, 0x77, 0xfa, 0x3a, 0x5e, 0xc8, 0x02, 0x75, 0xdf, 0xe1, 0x35, 0xc7, - 0xab, 0x50, 0xce, 0x76, 0x42, 0xf0, 0x52, 0xca, 0x47, 0xcc, 0x90, 0xcc, 0xec, 0xc7, 0x43, 0x78, - 0x51, 0xc9, 0x09, 0x10, 0xfd, 0x00, 0x5f, 0x4e, 0xca, 0x15, 0x7d, 0x51, 0xb5, 0x64, 0xaa, 0xb3, - 0xf8, 0x92, 0xa0, 0x65, 0x1e, 0xe6, 0x73, 0x0d, 0xaf, 0xf4, 0x0f, 0xa9, 0xdb, 0x60, 0xe6, 0x23, - 0x01, 0xcc, 0x7c, 0xe4, 0x78, 0x55, 0xff, 0xd1, 0x64, 0x41, 0x4c, 0x1d, 0x17, 0x43, 0x11, 0xe4, - 0xfb, 0x62, 0x20, 0x9c, 0xdf, 0xd6, 0x23, 0x4c, 0xd6, 0xb4, 0x18, 0xab, 0xb2, 0xea, 0xe4, 0xf9, - 0xab, 0x68, 0x7e, 0xb8, 0x32, 0x5e, 0x8f, 0x79, 0xbd, 0x0d, 0x03, 0x2d, 0xbd, 0x21, 0x2c, 0x44, - 0x0f, 0x18, 0xa7, 0x89, 0xa2, 0xaa, 0xdf, 0x8a, 0xf3, 0x29, 0x35, 0x0a, 0x41, 0xb9, 0x82, 0x5f, - 0x92, 0xca, 0x7c, 0xa1, 0x02, 0x4f, 0xfa, 0x1e, 0x64, 0xcd, 0x86, 0xef, 0x3d, 0x64, 0xf5, 0xf0, - 0xab, 0xbe, 0xe7, 0x87, 0xe6, 0x1d, 0x15, 0xa5, 0x23, 0x0d, 0x35, 0x3c, 0x6c, 0xd3, 0x60, 0xa7, - 0x95, 0x89, 0x17, 0x2b, 0xad, 0x67, 0xfd, 0x17, 0x08, 0x7a, 0xb1, 0x4e, 0xb7, 0x80, 0xe7, 0x9b, - 0x78, 0xdc, 0x6f, 0xf0, 0x7d, 0xbf, 0xe1, 0x55, 0xb7, 0x68, 0xb0, 0xed, 0x85, 0x83, 0xb1, 0xfa, - 0xd1, 0x31, 0x10, 0xce, 0x16, 0x9a, 0x8b, 0xe5, 0xbb, 0x9b, 0x8c, 0xc1, 0xec, 0x68, 0xd1, 0xce, - 0x01, 0x32, 0x8f, 0xc7, 0xc2, 0x7f, 0xe5, 0x9a, 0x1f, 0x6d, 0x42, 0xfa, 0xb5, 0x3e, 0x87, 0xaf, - 0x0b, 0x98, 0xef, 0xb2, 0x20, 0xa0, 0x36, 0xdb, 0xa5, 0x41, 0xe0, 0x78, 0xf6, 0x6e, 0xdb, 0x63, - 0x1c, 0xdd, 0x4d, 0x7c, 0xa3, 0xd7, 0x44, 0x20, 0x36, 0x85, 0x2f, 0x7e, 0xd8, 0x82, 0x18, 0x11, - 0x6a, 0xbf, 0xd0, 0x8b, 0x10, 0xee, 0x56, 0xd6, 0xb2, 0xfa, 0xa6, 0x4b, 0xed, 0xf8, 0xfe, 0x14, - 0x5e, 0xfc, 0xa7, 0x73, 0x26, 0x80, 0x7f, 0x8a, 0x5f, 0xa9, 0xa7, 0xc6, 0xa0, 0x70, 0x1a, 0x3d, - 0xf2, 0x3b, 0xed, 0x12, 0xba, 0xcb, 0x0e, 0x77, 0x2b, 0x9f, 0x5d, 0xc3, 0x17, 0x04, 0x08, 0xf2, - 0x04, 0xe1, 0x51, 0xf9, 0xa2, 0x4e, 0xee, 0xf4, 0x58, 0xa3, 0x8b, 0x46, 0xa5, 0xdd, 0xed, 0xcb, - 0x36, 0xa2, 0xad, 0xbf, 0xf5, 0xc9, 0xdf, 0xfe, 0xfb, 0xe9, 0xd0, 0x9b, 0xe4, 0x96, 0x11, 0x9a, - 0x2e, 0x49, 0xaa, 0x64, 0x4b, 0xfa, 0x6b, 0x19, 0x19, 0xc7, 0xf0, 0xd5, 0x3b, 0x31, 0x8e, 0xc5, - 0x77, 0xee, 0x84, 0xfc, 0x0e, 0xe1, 0x31, 0xd9, 0x6f, 0xd9, 0x75, 0xd5, 0xb8, 0x64, 0x2b, 0x55, - 0x6a, 0x5c, 0x72, 0xd4, 0x27, 0x7d, 0x51, 0x70, 0xb9, 0x4e, 0x66, 0x15, 0xb8, 0x90, 0x7f, 0x21, - 0x7c, 0x25, 0x85, 0x1c, 0x04, 0x03, 0x52, 0xee, 0x03, 0x44, 0x52, 0xf5, 0xd0, 0xd6, 0xcf, 0xe2, - 0x02, 0xe8, 0xdc, 0x11, 0x74, 0xde, 0x20, 0x2b, 0x0a, 0x74, 0xc0, 0x16, 0x76, 0xe8, 0x84, 0xfc, - 0x13, 0xe1, 0xaf, 0x48, 0xb7, 0x72, 0x89, 0xdc, 0x77, 0x14, 0x91, 0xe5, 0x2a, 0x3a, 0x5a, 0xf9, - 0x0c, 0x1e, 0x80, 0xda, 0x9a, 0xa0, 0xb6, 0x4a, 0xde, 0xc8, 0xa1, 0xe6, 0x78, 0x39, 0xcc, 0x4c, - 0xa7, 0x7a, 0x42, 0x7e, 0x8b, 0xf0, 0xe5, 0x24, 0x39, 0xe5, 0x9c, 0xcb, 0xd0, 0x56, 0x94, 0x73, - 0x2e, 0x4b, 0x2f, 0xe9, 0x99, 0x73, 0x12, 0x93, 0x80, 0xfc, 0x15, 0x80, 0x4b, 0x77, 0xce, 0x35, - 0xc5, 0xc3, 0x9b, 0x79, 0xf3, 0xd6, 0xde, 0xea, 0xd3, 0x1a, 0xc0, 0x7f, 0x4b, 0x80, 0x5f, 0x21, - 0xaf, 0x77, 0x01, 0xdf, 0x36, 0x33, 0x8e, 0xe3, 0xe7, 0x13, 0xf2, 0x77, 0x84, 0x49, 0xa7, 0x16, - 0x41, 0x94, 0xf0, 0xe4, 0x2a, 0x20, 0xda, 0xb7, 0xfb, 0x35, 0x07, 0x3e, 0x65, 0xc1, 0xe7, 0x2e, - 0xb9, 0x9d, 0xcb, 0x27, 0xfd, 0x1f, 0x26, 0x66, 0x95, 0x72, 0x2a, 0x13, 0xfb, 0x03, 0xc2, 0xe3, - 0xc9, 0x15, 0xc2, 0xf4, 0x5a, 0x3b, 0x45, 0x8a, 0xf4, 0xb9, 0x4b, 0xb9, 0x9a, 0x87, 0xbe, 0x24, - 0x58, 0xcd, 0x91, 0xeb, 0x4a, 0xbb, 0x44, 0x7e, 0x85, 0xda, 0x77, 0x6d, 0xb2, 0xaa, 0x98, 0x20, - 0x29, 0x51, 0x40, 0x7b, 0xf3, 0xd4, 0x76, 0x00, 0xd6, 0x10, 0x60, 0xbf, 0x41, 0xe6, 0x72, 0xc0, - 0xda, 0x60, 0x10, 0xc6, 0xbc, 0xca, 0x9a, 0x27, 0xe4, 0x97, 0x08, 0x8f, 0xc4, 0x5e, 0xc2, 0x50, - 0xaf, 0x2a, 0x06, 0xab, 0x2f, 0xc4, 0x19, 0xd2, 0x84, 0x3e, 0x27, 0x10, 0x5f, 0x23, 0x33, 0x3d, - 0x10, 0x93, 0xcf, 0x11, 0x7e, 0x25, 0xdd, 0x77, 0x11, 0xa5, 0xe2, 0x91, 0xd3, 0x04, 0x6a, 0x6b, - 0xfd, 0x19, 0x2b, 0x86, 0xda, 0x4a, 0x63, 0x7d, 0x82, 0xf0, 0x88, 0xd4, 0x5a, 0x91, 0x7b, 0x2a, - 0xcb, 0xf7, 0x6a, 0xe1, 0xb4, 0xb7, 0xcf, 0xe8, 0x05, 0xd8, 0x2c, 0x08, 0x36, 0x5f, 0x27, 0x7a, - 0x0e, 0x1b, 0xa9, 0x1d, 0x25, 0x4f, 0x51, 0x87, 0xfa, 0x40, 0x54, 0x4b, 0x61, 0xb6, 0x76, 0xa2, - 0x56, 0x7a, 0xf2, 0x75, 0x1f, 0x7d, 0x55, 0xc0, 0x7f, 0x9d, 0x94, 0x72, 0xe0, 0xbb, 0x49, 0xbb, - 0x56, 0xfa, 0xff, 0x09, 0x61, 0x92, 0xf2, 0x19, 0x9e, 0x02, 0xd5, 0x92, 0x71, 0x16, 0x36, 0xf9, - 0xea, 0x8e, 0x5e, 0x12, 0x6c, 0xe6, 0xc9, 0x0d, 0x35, 0x36, 0xe4, 0xe7, 0x08, 0x9f, 0x17, 0xc5, - 0x67, 0x45, 0x31, 0x8c, 0x72, 0x79, 0xbc, 0x79, 0x2a, 0x1b, 0xc5, 0xef, 0xae, 0x05, 0x1f, 0x2c, - 0x11, 0xe4, 0xdf, 0x20, 0x3c, 0x22, 0xa9, 0x3a, 0xe4, 0xf6, 0x29, 0x56, 0x4c, 0x2a, 0x41, 0xfd, - 0x81, 0xbd, 0x25, 0xc0, 0x1a, 0x64, 0xa9, 0x2b, 0xd8, 0x8e, 0xe6, 0xfa, 0x67, 0x08, 0xbf, 0x1c, - 0x7f, 0x81, 0x56, 0x14, 0x77, 0xf4, 0xd4, 0x81, 0x4d, 0x29, 0x3b, 0xfa, 0xac, 0xc0, 0x3a, 0x4d, - 0x5e, 0xeb, 0x82, 0x35, 0xec, 0xc0, 0xc6, 0x52, 0xaa, 0x81, 0x5a, 0x0b, 0x96, 0xad, 0xca, 0xa8, - 0xb5, 0x60, 0x39, 0x02, 0x4c, 0xef, 0xca, 0x21, 0x81, 0xfc, 0x1f, 0xc2, 0xc5, 0xee, 0x72, 0x07, - 0xd9, 0xee, 0x03, 0x4b, 0xb6, 0xee, 0xa2, 0x7d, 0x77, 0x10, 0xae, 0x80, 0xe5, 0x6d, 0xc1, 0xf2, - 0x26, 0x59, 0xee, 0xcd, 0x32, 0xcd, 0x28, 0xec, 0x97, 0x93, 0x7f, 0x2e, 0xa1, 0x76, 0x02, 0x32, - 0xff, 0x00, 0x43, 0xbb, 0xd3, 0x8f, 0xa9, 0x62, 0x2b, 0xf3, 0x38, 0x89, 0x32, 0x04, 0x9e, 0xd4, - 0x5d, 0xd4, 0x80, 0x67, 0x2a, 0x39, 0x6a, 0xc0, 0xb3, 0x65, 0x9e, 0x9e, 0xc0, 0xdd, 0x24, 0xca, - 0xb0, 0x55, 0x48, 0xcb, 0x02, 0x6a, 0xad, 0x42, 0x8e, 0x80, 0xa1, 0xd6, 0x2a, 0xe4, 0x89, 0x1b, - 0x3d, 0x5b, 0x85, 0xb4, 0x54, 0xb1, 0xfe, 0xbd, 0xa7, 0xcf, 0x8a, 0xe8, 0x8b, 0x67, 0x45, 0xf4, - 0x9f, 0x67, 0x45, 0xf4, 0xd3, 0xe7, 0xc5, 0x73, 0x5f, 0x3c, 0x2f, 0x9e, 0xfb, 0xc7, 0xf3, 0xe2, - 0xb9, 0x07, 0xcb, 0xb6, 0xc3, 0x6b, 0x8d, 0xfd, 0x92, 0xe5, 0x1f, 0xc8, 0xce, 0x62, 0x4c, 0x46, - 0x53, 0xf6, 0xcb, 0x8f, 0x0e, 0x59, 0xb0, 0xff, 0x92, 0xf8, 0x76, 0xdf, 0xfc, 0x7f, 0x00, 0x00, - 0x00, 0xff, 0xff, 0xc1, 0x55, 0xea, 0xa0, 0x5c, 0x25, 0x00, 0x00, + // 1957 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5a, 0xcf, 0x6f, 0xdc, 0xc6, + 0x15, 0xf6, 0x68, 0xad, 0x44, 0x1e, 0xf9, 0x47, 0x3c, 0x96, 0x1d, 0x95, 0xb1, 0xd7, 0x36, 0x55, + 0x5b, 0xaa, 0x5d, 0x2f, 0x63, 0x39, 0x56, 0x6a, 0x5b, 0x29, 0xba, 0x92, 0x63, 0x47, 0xad, 0x92, + 0x28, 0x0b, 0x15, 0x2a, 0x5c, 0x14, 0xc4, 0x88, 0x3b, 0xe1, 0x12, 0xa1, 0x48, 0x85, 0x9c, 0x8d, + 0x56, 0x16, 0x74, 0xf1, 0xa1, 0xe7, 0x02, 0x39, 0xf4, 0xd2, 0x6b, 0xd1, 0x1c, 0x7a, 0xe8, 0xa1, + 0x68, 0x0f, 0x05, 0x52, 0x04, 0x6d, 0x5d, 0x1f, 0x03, 0x14, 0x28, 0x8a, 0x16, 0x28, 0x0a, 0xbb, + 0x7f, 0x41, 0xff, 0x82, 0x82, 0xc3, 0xc7, 0xdd, 0xe1, 0xaf, 0xdd, 0xd1, 0x6a, 0x73, 0xc8, 0xc9, + 0x4b, 0xce, 0xbc, 0x37, 0xdf, 0xf7, 0xde, 0x9b, 0xe1, 0x9b, 0xcf, 0xc2, 0xe7, 0xac, 0xc0, 0x0f, + 0x43, 0xab, 0x45, 0x1d, 0xcf, 0xf8, 0xb8, 0xcd, 0x82, 0xdd, 0xda, 0x76, 0xe0, 0x73, 0x9f, 0x5c, + 0x78, 0xcc, 0x38, 0x15, 0xaf, 0x6b, 0xe2, 0x97, 0x1f, 0xb0, 0x5a, 0x6f, 0xaa, 0x76, 0xcd, 0xf2, + 0xc3, 0x2d, 0x3f, 0x34, 0x36, 0x69, 0xc8, 0x62, 0x3b, 0xe3, 0x93, 0x9b, 0x9b, 0x8c, 0xd3, 0x9b, + 0xc6, 0x36, 0xb5, 0x1d, 0x8f, 0x72, 0xc7, 0xf7, 0x62, 0x57, 0xda, 0x45, 0x69, 0x09, 0xf1, 0xd3, + 0x14, 0xbf, 0x4d, 0xde, 0x81, 0x09, 0x9a, 0x34, 0xc1, 0xa6, 0xa1, 0xb9, 0x1d, 0x38, 0x16, 0x83, + 0xb1, 0x19, 0x69, 0x4c, 0xd8, 0x98, 0x2d, 0x1a, 0xb6, 0x4c, 0xee, 0x9b, 0x96, 0xd5, 0x75, 0x50, + 0xcd, 0x4d, 0xe2, 0x01, 0xb5, 0x3e, 0x62, 0x01, 0x8c, 0xeb, 0xd2, 0xb8, 0x4b, 0x43, 0x6e, 0x6e, + 0xba, 0xbe, 0xf5, 0x91, 0xd9, 0x62, 0x8e, 0xdd, 0xe2, 0x05, 0x28, 0xfd, 0x36, 0xcf, 0x3b, 0x91, + 0x91, 0x04, 0x94, 0x33, 0xd3, 0x75, 0xb6, 0x1c, 0xce, 0x02, 0xf3, 0x43, 0x97, 0xda, 0x21, 0x4c, + 0x9a, 0xb2, 0x7d, 0xdb, 0x17, 0x3f, 0x8d, 0xe8, 0x17, 0xbc, 0x3d, 0x6f, 0xfb, 0xbe, 0xed, 0x32, + 0x83, 0x6e, 0x3b, 0x06, 0xf5, 0x3c, 0x9f, 0x8b, 0xf0, 0x80, 0x8d, 0x7e, 0x1e, 0x6b, 0x1f, 0x44, + 0x11, 0x7c, 0xc4, 0x38, 0xad, 0x5b, 0x96, 0xdf, 0xf6, 0xb8, 0xe3, 0xd9, 0x0d, 0xf6, 0x71, 0x9b, + 0x85, 0x5c, 0x7f, 0x17, 0xbf, 0x56, 0x38, 0x1a, 0x6e, 0xfb, 0x5e, 0xc8, 0x48, 0x0d, 0x9f, 0xa1, + 0x9b, 0x7e, 0xc0, 0x59, 0xd3, 0x8c, 0xf2, 0x64, 0xd2, 0xad, 0x68, 0xc6, 0x34, 0xba, 0x84, 0xe6, + 0x8e, 0x35, 0x4e, 0xc3, 0x90, 0xb0, 0x15, 0x03, 0x5d, 0x77, 0x0f, 0x19, 0x7f, 0xbf, 0xcd, 0xd7, + 0x3b, 0xeb, 0x31, 0x47, 0x58, 0x8d, 0x4c, 0xe3, 0x97, 0x05, 0xc3, 0x95, 0xfb, 0xc2, 0x45, 0xa5, + 0x91, 0x3c, 0x92, 0x29, 0x3c, 0xee, 0xf9, 0x9e, 0xc5, 0xa6, 0xc7, 0x2e, 0xa1, 0xb9, 0xa3, 0x8d, + 0xf8, 0x41, 0x6f, 0xe3, 0xf3, 0xc5, 0xee, 0x00, 0xde, 0x0f, 0xf1, 0x71, 0x5f, 0x7a, 0x2f, 0x9c, + 0x4e, 0xce, 0x5f, 0xaf, 0xf5, 0xad, 0xae, 0x9a, 0xec, 0x6a, 0xe9, 0xe8, 0xb3, 0x7f, 0x5f, 0x3c, + 0xd2, 0x48, 0xb9, 0xd1, 0x19, 0xb0, 0xa8, 0xbb, 0x6e, 0x11, 0x8b, 0x07, 0x18, 0xf7, 0xaa, 0x10, + 0xd6, 0xbc, 0x5a, 0x8b, 0x4b, 0xb6, 0x16, 0x95, 0x6c, 0x2d, 0x2e, 0x75, 0x28, 0xd9, 0xda, 0x1a, + 0xb5, 0x19, 0xd8, 0x36, 0x24, 0x4b, 0xfd, 0x73, 0x04, 0xf4, 0x72, 0xeb, 0x94, 0xd2, 0xab, 0x8c, + 0x80, 0x1e, 0x79, 0x98, 0xc2, 0x3f, 0x26, 0xf0, 0xcf, 0x0e, 0xc4, 0x1f, 0x63, 0x4a, 0x11, 0x78, + 0x82, 0xb0, 0x5e, 0x44, 0x60, 0x69, 0x77, 0x39, 0x42, 0x92, 0xc4, 0x6b, 0x0a, 0x8f, 0x0b, 0x64, + 0x90, 0xf3, 0xf8, 0x21, 0x13, 0xc5, 0xb1, 0xa1, 0xa3, 0xf8, 0x17, 0x84, 0x67, 0xfa, 0x82, 0xf8, + 0x9a, 0x04, 0xf3, 0xa7, 0x08, 0x5f, 0x4e, 0x78, 0xac, 0x78, 0x65, 0xb1, 0xfc, 0x06, 0x9e, 0x88, + 0x8f, 0x37, 0xa7, 0x99, 0xde, 0x42, 0xcd, 0x91, 0x05, 0xf4, 0x0b, 0x29, 0xab, 0x45, 0x40, 0x20, + 0x9e, 0x0d, 0x3c, 0xe9, 0x78, 0xd9, 0x70, 0x5e, 0x1b, 0x10, 0x4e, 0xd9, 0x5f, 0x1c, 0x4d, 0xd9, + 0xc9, 0xe8, 0x82, 0x29, 0xed, 0x60, 0x69, 0xc9, 0x70, 0xd4, 0x3b, 0xf8, 0x0f, 0xd2, 0x0e, 0x4e, + 0xaf, 0xf3, 0x75, 0x08, 0xd2, 0x3d, 0x7c, 0x21, 0x39, 0x5d, 0xa3, 0x25, 0xdf, 0xa1, 0x61, 0x6b, + 0xdd, 0x5f, 0xb6, 0x78, 0x27, 0x09, 0x93, 0x86, 0x27, 0x1c, 0x18, 0x80, 0x23, 0xbf, 0xfb, 0xac, + 0xef, 0xe3, 0x6a, 0x99, 0x31, 0x70, 0xff, 0x31, 0x3e, 0xe9, 0xa4, 0x46, 0x20, 0xd0, 0x37, 0x14, + 0xe8, 0xf7, 0x8c, 0x20, 0x02, 0x19, 0x57, 0xfa, 0x22, 0x2c, 0x9f, 0x9e, 0x7c, 0x9f, 0x72, 0xaa, + 0x02, 0xfe, 0x31, 0xbe, 0x58, 0x6a, 0x0d, 0xe8, 0x37, 0xf0, 0x89, 0xe5, 0x08, 0x93, 0x28, 0xfa, + 0xf5, 0x4e, 0xa8, 0x78, 0x5e, 0xc8, 0x36, 0x00, 0x3d, 0xed, 0x47, 0xb7, 0x21, 0xea, 0x50, 0x32, + 0xf9, 0xa8, 0x8f, 0xaa, 0x38, 0x9f, 0x22, 0x88, 0x51, 0xc1, 0x4a, 0x7d, 0x52, 0x54, 0x19, 0x51, + 0x8a, 0x46, 0x57, 0xa7, 0x06, 0x7e, 0x35, 0x29, 0xb5, 0x87, 0x34, 0x5c, 0x8b, 0xda, 0x37, 0xe9, + 0xd3, 0xe2, 0x78, 0x4d, 0xd6, 0x81, 0x0c, 0xc7, 0x0f, 0xba, 0x89, 0xa7, 0xf3, 0x06, 0x40, 0x79, + 0x19, 0x4f, 0x24, 0xef, 0x20, 0xb6, 0xb3, 0x03, 0xc8, 0x76, 0x5d, 0x74, 0x0d, 0x75, 0x0a, 0x88, + 0xea, 0xae, 0x9b, 0x45, 0x34, 0xaa, 0xec, 0x7d, 0x86, 0x80, 0x44, 0x6a, 0x8d, 0x42, 0x12, 0x95, + 0xa1, 0x48, 0x8c, 0x2e, 0x3f, 0x0b, 0xbd, 0xa3, 0x60, 0x95, 0x86, 0x7c, 0x29, 0xea, 0x7e, 0xdf, + 0x11, 0xcd, 0x6f, 0xff, 0x34, 0xed, 0xc1, 0x2e, 0x2c, 0xb2, 0x03, 0xa2, 0x3f, 0xc2, 0xa7, 0x32, + 0x43, 0x10, 0xd2, 0xda, 0x00, 0xbe, 0x59, 0x87, 0x59, 0x37, 0x7a, 0xab, 0xb7, 0x39, 0x4a, 0x40, + 0x8f, 0x2a, 0x93, 0x7f, 0x46, 0xc0, 0xb3, 0x68, 0xa9, 0x7e, 0x3c, 0x2b, 0x23, 0xe0, 0x39, 0xba, + 0x2c, 0x5f, 0xc7, 0x67, 0x92, 0x6c, 0xc9, 0xa7, 0x55, 0x71, 0x6a, 0x57, 0xe1, 0xd2, 0x01, 0x93, + 0x97, 0x76, 0xdf, 0x8b, 0xfa, 0xf9, 0x61, 0xaf, 0x01, 0x36, 0x9e, 0x4a, 0x2f, 0x0d, 0x51, 0x7b, + 0x1f, 0x1f, 0x97, 0xcf, 0x56, 0xc5, 0xf6, 0x5f, 0x36, 0x69, 0xa4, 0x1c, 0xe8, 0x3f, 0x01, 0x8e, + 0x75, 0xd7, 0xfd, 0x2a, 0x4e, 0xe4, 0xdf, 0x20, 0x20, 0xd2, 0xf5, 0x5f, 0x4a, 0xa4, 0x72, 0x28, + 0x22, 0xa3, 0xcb, 0xfa, 0x7b, 0xd0, 0x48, 0xad, 0x3a, 0x21, 0x5f, 0x63, 0x5e, 0xd3, 0xf1, 0x6c, + 0x39, 0x32, 0x7d, 0xda, 0xd1, 0x29, 0x3c, 0x2e, 0xae, 0xb0, 0x62, 0xf5, 0x13, 0x8d, 0xf8, 0x41, + 0xff, 0x34, 0xe9, 0x98, 0x72, 0x0e, 0xbf, 0xaa, 0x50, 0xe8, 0xf8, 0x38, 0xf7, 0x39, 0x75, 0x61, + 0x31, 0xa8, 0xac, 0xd4, 0x3b, 0x7d, 0x09, 0x5f, 0x2b, 0x02, 0xb5, 0xe1, 0xf0, 0x96, 0xe3, 0x35, + 0x28, 0x67, 0xab, 0x11, 0x78, 0xa9, 0xe4, 0x63, 0x66, 0x48, 0x66, 0xf6, 0xc5, 0x18, 0xbe, 0xae, + 0xe4, 0x04, 0x88, 0x7e, 0x80, 0x4f, 0xa6, 0xe5, 0x8a, 0xa1, 0xa8, 0x5a, 0x32, 0xd5, 0x19, 0x7c, + 0x42, 0xd0, 0x32, 0xb7, 0xcb, 0xb9, 0x92, 0x05, 0xfc, 0xaa, 0xd5, 0x0e, 0x02, 0xe6, 0x71, 0x73, + 0xc7, 0xe1, 0xad, 0x66, 0x40, 0x77, 0xcc, 0x1d, 0xc7, 0x6b, 0xfa, 0x3b, 0xd3, 0x15, 0x91, 0xc1, + 0xb3, 0x30, 0xbc, 0x01, 0xa3, 0x1b, 0x62, 0x90, 0xcc, 0xe3, 0xb3, 0x39, 0xbb, 0x80, 0x72, 0x36, + 0x7d, 0x54, 0x6c, 0xfc, 0x33, 0x19, 0xab, 0x88, 0x30, 0xa9, 0xe1, 0x33, 0x3d, 0x2d, 0xc3, 0x64, + 0x1d, 0x8b, 0xb1, 0x26, 0x6b, 0x4e, 0x8f, 0x5f, 0x42, 0x73, 0x13, 0x8d, 0xd3, 0x41, 0x12, 0x93, + 0xb7, 0x61, 0xa0, 0xab, 0x55, 0x44, 0x87, 0xd8, 0x23, 0xc6, 0x69, 0xea, 0x40, 0xd6, 0x6f, 0x27, + 0xb5, 0x98, 0x19, 0x85, 0x80, 0x9e, 0xc3, 0x2f, 0x49, 0x9f, 0x88, 0x4a, 0x03, 0x9e, 0xf4, 0x75, + 0xa8, 0xb8, 0x65, 0xdf, 0xfb, 0x84, 0x05, 0x51, 0x47, 0xb0, 0xee, 0x47, 0xe6, 0xb9, 0xd3, 0x28, + 0x57, 0xc2, 0x1a, 0x9e, 0xb0, 0x69, 0xb8, 0xda, 0xad, 0xe2, 0x63, 0x8d, 0xee, 0xb3, 0xfe, 0x4b, + 0x04, 0x7d, 0x5c, 0xde, 0x2d, 0xe0, 0xf9, 0x36, 0x3e, 0xed, 0xb7, 0xf9, 0xa6, 0xdf, 0xf6, 0x9a, + 0x0f, 0x69, 0xb8, 0xe2, 0x45, 0x83, 0x89, 0x72, 0x92, 0x1b, 0x88, 0x66, 0x0b, 0xbd, 0xc6, 0xf2, + 0xdd, 0x07, 0x8c, 0xc1, 0xec, 0x78, 0xd1, 0xfc, 0x00, 0x99, 0xc3, 0xa7, 0xa2, 0x7f, 0xe5, 0xef, + 0x45, 0x45, 0xe4, 0x3a, 0xfb, 0x5a, 0x9f, 0xc5, 0x57, 0x04, 0xcc, 0x77, 0x59, 0x18, 0x52, 0x9b, + 0xad, 0xd1, 0x30, 0x74, 0x3c, 0x7b, 0xad, 0xe7, 0x31, 0x89, 0xee, 0x03, 0x7c, 0x75, 0xd0, 0x44, + 0x20, 0x76, 0x1e, 0x1f, 0xfb, 0xb0, 0x0b, 0x31, 0x26, 0xd4, 0x7b, 0xa1, 0x57, 0x21, 0xdc, 0xdd, + 0x8a, 0x67, 0xc1, 0x03, 0x97, 0xda, 0xc9, 0xdd, 0x4b, 0x7f, 0x92, 0x04, 0x2e, 0x3f, 0x01, 0xfc, + 0x53, 0xfc, 0x4a, 0x90, 0x19, 0x83, 0x43, 0xd7, 0x18, 0xb0, 0x37, 0xb2, 0x2e, 0xa1, 0x33, 0xcd, + 0xb9, 0x9b, 0xff, 0xec, 0x32, 0x1e, 0x17, 0x20, 0xc8, 0x53, 0x84, 0x8f, 0xcb, 0x97, 0x7c, 0x72, + 0x77, 0xc0, 0x1a, 0x7d, 0xf4, 0x2d, 0xed, 0xde, 0x50, 0xb6, 0x31, 0x6d, 0xfd, 0xad, 0x27, 0x7f, + 0xfb, 0xef, 0xa7, 0x63, 0x6f, 0x92, 0xdb, 0x46, 0x64, 0x7a, 0x43, 0x52, 0x34, 0xbb, 0xb2, 0x61, + 0xd7, 0xc8, 0xd8, 0x83, 0x2f, 0xe6, 0xbe, 0xb1, 0x27, 0xbe, 0x91, 0xfb, 0xe4, 0xf7, 0x08, 0x9f, + 0x92, 0xfd, 0xd6, 0x5d, 0x57, 0x8d, 0x4b, 0xb1, 0xca, 0xa5, 0xc6, 0xa5, 0x44, 0xb9, 0xd2, 0xaf, + 0x0b, 0x2e, 0x57, 0xc8, 0x8c, 0x02, 0x17, 0xf2, 0x2f, 0x84, 0xcf, 0x65, 0x90, 0x83, 0xd8, 0x40, + 0xea, 0x43, 0x80, 0x48, 0x2b, 0x26, 0xda, 0xd2, 0x61, 0x5c, 0x00, 0x9d, 0xbb, 0x82, 0xce, 0x1b, + 0x64, 0x5e, 0x81, 0x0e, 0xd8, 0x42, 0x86, 0xf6, 0xc9, 0x3f, 0x11, 0x3e, 0x2b, 0xdd, 0xe8, 0x25, + 0x72, 0xdf, 0x53, 0x44, 0x56, 0xaa, 0x06, 0x69, 0xf5, 0x43, 0x78, 0x00, 0x6a, 0x8b, 0x82, 0xda, + 0x02, 0x79, 0xa3, 0x84, 0x9a, 0xe3, 0x95, 0x30, 0x33, 0x9d, 0xe6, 0x3e, 0xf9, 0x1d, 0xc2, 0x27, + 0xd3, 0xe4, 0x94, 0x6b, 0xae, 0x40, 0x97, 0x51, 0xae, 0xb9, 0x22, 0xad, 0x65, 0x60, 0xcd, 0x49, + 0x4c, 0x42, 0xf2, 0x57, 0x00, 0x2e, 0xdd, 0x57, 0x17, 0x15, 0x37, 0x6f, 0xe1, 0xad, 0x5d, 0x7b, + 0x6b, 0x48, 0x6b, 0x00, 0xff, 0x1d, 0x01, 0x7e, 0x9e, 0xbc, 0xde, 0x07, 0x7c, 0xcf, 0xcc, 0xd8, + 0x4b, 0x9e, 0xf7, 0xc9, 0xdf, 0x11, 0x26, 0x79, 0x1d, 0x83, 0x28, 0xe1, 0x29, 0x55, 0x4f, 0xb4, + 0xef, 0x0e, 0x6b, 0x0e, 0x7c, 0xea, 0x82, 0xcf, 0x3d, 0x72, 0xa7, 0x94, 0x4f, 0xf6, 0x3f, 0x5b, + 0xcc, 0x26, 0xe5, 0x54, 0x26, 0xf6, 0x47, 0x84, 0x4f, 0xa7, 0x57, 0x88, 0xca, 0x6b, 0xf1, 0x00, + 0x25, 0x32, 0x64, 0x96, 0x4a, 0xf5, 0x12, 0xfd, 0x86, 0x60, 0x35, 0x4b, 0xae, 0x28, 0x65, 0x89, + 0xfc, 0x1a, 0xf5, 0xee, 0xe9, 0x64, 0x41, 0xb1, 0x40, 0x32, 0x82, 0x82, 0xf6, 0xe6, 0x81, 0xed, + 0x00, 0xac, 0x21, 0xc0, 0x7e, 0x8b, 0xcc, 0x96, 0x80, 0xb5, 0xc1, 0x20, 0x8a, 0x79, 0x93, 0x75, + 0xf6, 0xc9, 0xaf, 0x10, 0x9e, 0x4c, 0xbc, 0x44, 0xa1, 0x5e, 0x50, 0x0c, 0xd6, 0x50, 0x88, 0x0b, + 0x64, 0x0d, 0x7d, 0x56, 0x20, 0xbe, 0x4c, 0x2e, 0x0e, 0x40, 0x4c, 0x3e, 0x47, 0xf8, 0x95, 0x6c, + 0xdf, 0x45, 0x94, 0x0e, 0x8f, 0x92, 0x26, 0x50, 0x5b, 0x1c, 0xce, 0x58, 0x31, 0xd4, 0x56, 0x16, + 0xeb, 0x53, 0x84, 0x27, 0xa5, 0xd6, 0x8a, 0xdc, 0x57, 0x59, 0x7e, 0x50, 0x0b, 0xa7, 0xbd, 0x7d, + 0x48, 0x2f, 0xc0, 0xe6, 0x9a, 0x60, 0xf3, 0x4d, 0xa2, 0x97, 0xb0, 0x91, 0xda, 0x51, 0xf2, 0x0c, + 0xe5, 0x94, 0x0b, 0xa2, 0x7a, 0x14, 0x16, 0xeb, 0x2e, 0x6a, 0x47, 0x4f, 0xb9, 0x66, 0xa4, 0x2f, + 0x08, 0xf8, 0xaf, 0x93, 0x5a, 0x09, 0x7c, 0x37, 0x6d, 0xd7, 0x2d, 0xff, 0x3f, 0x21, 0x4c, 0x32, + 0x3e, 0xa3, 0x5d, 0xa0, 0x7a, 0x64, 0x1c, 0x86, 0x4d, 0xb9, 0x32, 0xa4, 0xd7, 0x04, 0x9b, 0x39, + 0x72, 0x55, 0x8d, 0x0d, 0xf9, 0x05, 0xc2, 0x47, 0xc5, 0xe1, 0x33, 0xaf, 0x18, 0x46, 0xf9, 0x78, + 0xbc, 0x75, 0x20, 0x1b, 0xc5, 0xef, 0xae, 0x05, 0x1f, 0x2c, 0x11, 0xe4, 0xdf, 0x22, 0x3c, 0x29, + 0x29, 0x42, 0xe4, 0xce, 0x01, 0x56, 0x4c, 0xab, 0x48, 0xc3, 0x81, 0xbd, 0x2d, 0xc0, 0x1a, 0xe4, + 0x46, 0x5f, 0xb0, 0xb9, 0xe6, 0xfa, 0xe7, 0x08, 0xbf, 0x9c, 0x7c, 0x81, 0xe6, 0x15, 0x33, 0x7a, + 0xe0, 0xc0, 0x66, 0x54, 0x21, 0x7d, 0x46, 0x60, 0xbd, 0x40, 0x5e, 0xeb, 0x83, 0x35, 0xea, 0xc0, + 0x4e, 0x65, 0x14, 0x07, 0xb5, 0x16, 0xac, 0x58, 0xd1, 0x51, 0x6b, 0xc1, 0x4a, 0xc4, 0x9b, 0xc1, + 0x27, 0x87, 0x04, 0xf2, 0x7f, 0x08, 0x57, 0xfb, 0x4b, 0x25, 0x64, 0x65, 0x08, 0x2c, 0xc5, 0x9a, + 0x8d, 0xf6, 0xfd, 0x51, 0xb8, 0x02, 0x96, 0x77, 0x04, 0xcb, 0x5b, 0xe4, 0xe6, 0x60, 0x96, 0x59, + 0x46, 0x51, 0xbf, 0x9c, 0xfe, 0x53, 0x0b, 0xb5, 0x1d, 0x50, 0xf8, 0xc7, 0x1b, 0xda, 0xdd, 0x61, + 0x4c, 0x15, 0x5b, 0x99, 0xc7, 0x69, 0x94, 0x11, 0xf0, 0xb4, 0xee, 0xa2, 0x06, 0xbc, 0x50, 0xc9, + 0x51, 0x03, 0x5e, 0x2c, 0xf3, 0x0c, 0x04, 0xee, 0xa6, 0x51, 0x46, 0xad, 0x42, 0x56, 0x16, 0x50, + 0x6b, 0x15, 0x4a, 0x04, 0x0c, 0xb5, 0x56, 0xa1, 0x4c, 0xdc, 0x18, 0xd8, 0x2a, 0x64, 0xa5, 0x8a, + 0xa5, 0x1f, 0x3c, 0x7b, 0x5e, 0x45, 0x5f, 0x3e, 0xaf, 0xa2, 0xff, 0x3c, 0xaf, 0xa2, 0x9f, 0xbd, + 0xa8, 0x1e, 0xf9, 0xf2, 0x45, 0xf5, 0xc8, 0x3f, 0x5e, 0x54, 0x8f, 0x3c, 0xba, 0x69, 0x3b, 0xbc, + 0xd5, 0xde, 0xac, 0x59, 0xfe, 0x96, 0xec, 0x2c, 0xc1, 0x64, 0x74, 0x64, 0xbf, 0x7c, 0x77, 0x9b, + 0x85, 0x9b, 0x2f, 0x89, 0x6f, 0xf7, 0xad, 0xff, 0x07, 0x00, 0x00, 0xff, 0xff, 0x13, 0xb9, 0xf7, + 0xad, 0x98, 0x25, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -4392,10 +4402,17 @@ func (m *QueryListPendingCctxWithinRateLimitResponse) MarshalToSizedBuffer(dAtA dAtA[i] = 0 } i-- - dAtA[i] = 0x20 + dAtA[i] = 0x28 } - if m.ValueWithinWindow != 0 { - i = encodeVarintQuery(dAtA, i, uint64(m.ValueWithinWindow)) + if len(m.CurrentWithdrawRate) > 0 { + i -= len(m.CurrentWithdrawRate) + copy(dAtA[i:], m.CurrentWithdrawRate) + i = encodeVarintQuery(dAtA, i, uint64(len(m.CurrentWithdrawRate))) + i-- + dAtA[i] = 0x22 + } + if m.CurrentWithdrawWindow != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.CurrentWithdrawWindow)) i-- dAtA[i] = 0x18 } @@ -5184,8 +5201,12 @@ func (m *QueryListPendingCctxWithinRateLimitResponse) Size() (n int) { if m.TotalPending != 0 { n += 1 + sovQuery(uint64(m.TotalPending)) } - if m.ValueWithinWindow != 0 { - n += 1 + sovQuery(uint64(m.ValueWithinWindow)) + if m.CurrentWithdrawWindow != 0 { + n += 1 + sovQuery(uint64(m.CurrentWithdrawWindow)) + } + l = len(m.CurrentWithdrawRate) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) } if m.RateLimitExceeded { n += 2 @@ -8554,9 +8575,9 @@ func (m *QueryListPendingCctxWithinRateLimitResponse) Unmarshal(dAtA []byte) err } case 3: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ValueWithinWindow", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field CurrentWithdrawWindow", wireType) } - m.ValueWithinWindow = 0 + m.CurrentWithdrawWindow = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowQuery @@ -8566,12 +8587,44 @@ func (m *QueryListPendingCctxWithinRateLimitResponse) Unmarshal(dAtA []byte) err } b := dAtA[iNdEx] iNdEx++ - m.ValueWithinWindow |= uint64(b&0x7F) << shift + m.CurrentWithdrawWindow |= int64(b&0x7F) << shift if b < 0x80 { break } } case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CurrentWithdrawRate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + 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 ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CurrentWithdrawRate = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field RateLimitExceeded", wireType) } diff --git a/zetaclient/interfaces/interfaces.go b/zetaclient/interfaces/interfaces.go index a122a19131..d40ac4689b 100644 --- a/zetaclient/interfaces/interfaces.go +++ b/zetaclient/interfaces/interfaces.go @@ -98,7 +98,7 @@ type ZetaCoreBridger interface { GetZetaBlockHeight() (int64, error) GetLastBlockHeightByChain(chain chains.Chain) (*crosschaintypes.LastBlockHeight, error) ListPendingCctx(chainID int64) ([]*crosschaintypes.CrossChainTx, uint64, error) - ListPendingCctxWithinRatelimit() ([]*crosschaintypes.CrossChainTx, uint64, uint64, bool, error) + ListPendingCctxWithinRatelimit() ([]*crosschaintypes.CrossChainTx, uint64, int64, string, bool, error) GetPendingNoncesByChain(chainID int64) (observertypes.PendingNonces, error) GetCctxByNonce(chainID int64, nonce uint64) (*crosschaintypes.CrossChainTx, error) GetOutTxTracker(chain chains.Chain, nonce uint64) (*crosschaintypes.OutTxTracker, error) diff --git a/zetaclient/testutils/stub/core_bridge.go b/zetaclient/testutils/stub/core_bridge.go index ca3f45a16b..ec72eae7d8 100644 --- a/zetaclient/testutils/stub/core_bridge.go +++ b/zetaclient/testutils/stub/core_bridge.go @@ -121,11 +121,11 @@ func (z *MockZetaCoreBridge) ListPendingCctx(_ int64) ([]*cctxtypes.CrossChainTx return []*cctxtypes.CrossChainTx{}, 0, nil } -func (z *MockZetaCoreBridge) ListPendingCctxWithinRatelimit() ([]*cctxtypes.CrossChainTx, uint64, uint64, bool, error) { +func (z *MockZetaCoreBridge) ListPendingCctxWithinRatelimit() ([]*cctxtypes.CrossChainTx, uint64, int64, string, bool, error) { if z.paused { - return nil, 0, 0, false, errors.New(ErrMsgPaused) + return nil, 0, 0, "", false, errors.New(ErrMsgPaused) } - return []*cctxtypes.CrossChainTx{}, 0, 0, false, nil + return []*cctxtypes.CrossChainTx{}, 0, 0, "", false, nil } func (z *MockZetaCoreBridge) GetPendingNoncesByChain(_ int64) (observerTypes.PendingNonces, error) { diff --git a/zetaclient/zetabridge/query.go b/zetaclient/zetabridge/query.go index afed840fef..9c313f364a 100644 --- a/zetaclient/zetabridge/query.go +++ b/zetaclient/zetabridge/query.go @@ -139,7 +139,7 @@ func (b *ZetaCoreBridge) ListPendingCctx(chainID int64) ([]*types.CrossChainTx, // ListPendingCctxWithinRatelimit returns a list of pending cctxs that do not exceed the outbound rate limit // - The max size of the list is crosschainkeeper.MaxPendingCctxs // - The returned `rateLimitExceeded` flag indicates if the rate limit is exceeded or not -func (b *ZetaCoreBridge) ListPendingCctxWithinRatelimit() ([]*types.CrossChainTx, uint64, uint64, bool, error) { +func (b *ZetaCoreBridge) ListPendingCctxWithinRatelimit() ([]*types.CrossChainTx, uint64, int64, string, bool, error) { client := types.NewQueryClient(b.grpcConn) maxSizeOption := grpc.MaxCallRecvMsgSize(32 * 1024 * 1024) resp, err := client.ListPendingCctxWithinRateLimit( @@ -148,9 +148,9 @@ func (b *ZetaCoreBridge) ListPendingCctxWithinRatelimit() ([]*types.CrossChainTx maxSizeOption, ) if err != nil { - return nil, 0, 0, false, err + return nil, 0, 0, "", false, err } - return resp.CrossChainTx, resp.TotalPending, resp.ValueWithinWindow, resp.RateLimitExceeded, nil + return resp.CrossChainTx, resp.TotalPending, resp.CurrentWithdrawWindow, resp.CurrentWithdrawRate, resp.RateLimitExceeded, nil } func (b *ZetaCoreBridge) GetAbortedZetaAmount() (string, error) { diff --git a/zetaclient/zetacore_observer.go b/zetaclient/zetacore_observer.go index 230e1ba894..535f741db1 100644 --- a/zetaclient/zetacore_observer.go +++ b/zetaclient/zetacore_observer.go @@ -134,13 +134,14 @@ func (co *CoreObserver) startCctxScheduler(appContext *appcontext.AppContext) { metrics.HotKeyBurnRate.Set(float64(co.ts.HotKeyBurnRate.GetBurnRate().Int64())) // query pending cctxs across all foreign chains with rate limit - cctxMap, valueWithinWindow, err := co.getAllPendingCctxWithRatelimit() + cctxMap, withdrawWindow, withdrawRate, err := co.getAllPendingCctxWithRatelimit() if err != nil { co.logger.ZetaChainWatcher.Error().Err(err).Msgf("startCctxScheduler: queryPendingCctxWithRatelimit failed") } // print value within rate limiter window every minute if bn%10 == 0 { - co.logger.ZetaChainWatcher.Debug().Msgf("startCctxScheduler: value within rate limiter window is %d ZETA", valueWithinWindow) + co.logger.ZetaChainWatcher.Debug().Msgf( + "startCctxScheduler: withdraw window is %d, withdraw rate is %s", withdrawWindow, withdrawRate) } // schedule keysign for pending cctxs on each chain @@ -194,10 +195,10 @@ func (co *CoreObserver) startCctxScheduler(appContext *appcontext.AppContext) { } // getAllPendingCctxWithRatelimit get pending cctxs across all foreign chains with rate limit -func (co *CoreObserver) getAllPendingCctxWithRatelimit() (map[int64][]*types.CrossChainTx, uint64, error) { - cctxList, totalPending, valueWithinWindow, rateLimitExceeded, err := co.bridge.ListPendingCctxWithinRatelimit() +func (co *CoreObserver) getAllPendingCctxWithRatelimit() (map[int64][]*types.CrossChainTx, int64, string, error) { + cctxList, totalPending, withdrawWindow, withdrawRate, rateLimitExceeded, err := co.bridge.ListPendingCctxWithinRatelimit() if err != nil { - return nil, 0, err + return nil, 0, "", err } if rateLimitExceeded { co.logger.ZetaChainWatcher.Warn().Msgf("rate limit exceeded, fetched %d cctxs out of %d", len(cctxList), totalPending) @@ -213,7 +214,7 @@ func (co *CoreObserver) getAllPendingCctxWithRatelimit() (map[int64][]*types.Cro cctxMap[chainID] = append(cctxMap[chainID], cctx) } - return cctxMap, valueWithinWindow, nil + return cctxMap, withdrawWindow, withdrawRate, nil } // scheduleCctxEVM schedules evm outtx keysign on each ZetaChain block (the ticker) From daba26989032619c1b8a8ee064cd88d477e81d70 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Thu, 25 Apr 2024 11:29:23 -0500 Subject: [PATCH 26/33] add commented unit tests back --- .../keeper/grpc_query_cctx_rate_limit_test.go | 374 +++++++++--------- 1 file changed, 187 insertions(+), 187 deletions(-) diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go index 2aa96ca51b..71a31ce2f7 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go @@ -310,193 +310,193 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { expectedWithdrawRate string rateLimitExceeded bool }{ - // { - // name: "should use fallback query if rate limiter is disabled", - // fallback: true, - // rateLimitFlags: nil, // no rate limiter flags set in the keeper - // ethMinedCctxs: ethMinedCctxs, - // ethPendingCctxs: ethPendingCctxs, - // ethPendingNonces: observertypes.PendingNonces{ - // ChainId: ethChainID, - // NonceLow: 1099, - // NonceHigh: 1199, - // Tss: tss.TssPubkey, - // }, - // btcMinedCctxs: btcMinedCctxs, - // btcPendingCctxs: btcPendingCctxs, - // btcPendingNonces: observertypes.PendingNonces{ - // ChainId: btcChainID, - // NonceLow: 1099, - // NonceHigh: 1199, - // Tss: tss.TssPubkey, - // }, - // currentHeight: 1199, - // queryLimit: keeper.MaxPendingCctxs, - // expectedCctxs: append(append([]*types.CrossChainTx{}, btcPendingCctxs...), ethPendingCctxs...), - // expectedTotalPending: 400, - // }, - // { - // name: "should use fallback query if rate is 0", - // fallback: true, - // rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(0), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), - // ethMinedCctxs: ethMinedCctxs, - // ethPendingCctxs: ethPendingCctxs, - // ethPendingNonces: observertypes.PendingNonces{ - // ChainId: ethChainID, - // NonceLow: 1099, - // NonceHigh: 1199, - // Tss: tss.TssPubkey, - // }, - // btcMinedCctxs: btcMinedCctxs, - // btcPendingCctxs: btcPendingCctxs, - // btcPendingNonces: observertypes.PendingNonces{ - // ChainId: btcChainID, - // NonceLow: 1099, - // NonceHigh: 1199, - // Tss: tss.TssPubkey, - // }, - // currentHeight: 1199, - // queryLimit: keeper.MaxPendingCctxs, - // expectedCctxs: append(append([]*types.CrossChainTx{}, btcPendingCctxs...), ethPendingCctxs...), - // expectedTotalPending: 400, - // }, - // { - // name: "can retrieve all pending cctx without exceeding rate limit", - // rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(10*1e18), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), - // ethMinedCctxs: ethMinedCctxs, - // ethPendingCctxs: ethPendingCctxs, - // ethPendingNonces: observertypes.PendingNonces{ - // ChainId: ethChainID, - // NonceLow: 1099, - // NonceHigh: 1199, - // Tss: tss.TssPubkey, - // }, - // btcMinedCctxs: btcMinedCctxs, - // btcPendingCctxs: btcPendingCctxs, - // btcPendingNonces: observertypes.PendingNonces{ - // ChainId: btcChainID, - // NonceLow: 1099, - // NonceHigh: 1199, - // Tss: tss.TssPubkey, - // }, - // currentHeight: 1199, - // queryLimit: keeper.MaxPendingCctxs, - // expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs...), btcPendingCctxs...), - // expectedTotalPending: 400, - // expectedWithdrawWindow: 500, // the sliding window - // expectedWithdrawRate: sdk.NewDec(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block - // rateLimitExceeded: false, - // }, - // { - // name: "can loop backwards all the way to endNonce 0", - // rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(10*1e18), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), - // ethMinedCctxs: ethMinedCctxs, - // ethPendingCctxs: ethPendingCctxs, - // ethPendingNonces: observertypes.PendingNonces{ - // ChainId: ethChainID, - // NonceLow: 999, // endNonce will be set to 0 (NonceLow - 1000 < 0) - // NonceHigh: 1199, - // Tss: tss.TssPubkey, - // }, - // btcMinedCctxs: btcMinedCctxs, - // btcPendingCctxs: btcPendingCctxs, - // btcPendingNonces: observertypes.PendingNonces{ - // ChainId: btcChainID, - // NonceLow: 999, // endNonce will be set to 0 (NonceLow - 1000 < 0) - // NonceHigh: 1199, - // Tss: tss.TssPubkey, - // }, - // currentHeight: 1199, - // queryLimit: keeper.MaxPendingCctxs, - // expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs...), btcPendingCctxs...), - // expectedTotalPending: 400, - // expectedWithdrawWindow: 500, // the sliding window - // expectedWithdrawRate: sdk.NewDec(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block - // rateLimitExceeded: false, - // }, - // { - // name: "set a low rate (rate < 2.4 ZETA) to exceed rate limit in backward loop", - // rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(2*1e18), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), - // ethMinedCctxs: ethMinedCctxs, - // ethPendingCctxs: ethPendingCctxs, - // ethPendingNonces: observertypes.PendingNonces{ - // ChainId: ethChainID, - // NonceLow: 1099, - // NonceHigh: 1199, - // Tss: tss.TssPubkey, - // }, - // btcMinedCctxs: btcMinedCctxs, - // btcPendingCctxs: btcPendingCctxs, - // btcPendingNonces: observertypes.PendingNonces{ - // ChainId: btcChainID, - // NonceLow: 1099, - // NonceHigh: 1199, - // Tss: tss.TssPubkey, - // }, - // currentHeight: 1199, - // queryLimit: keeper.MaxPendingCctxs, - // // return missed cctxs only if rate limit is exceeded - // expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs[0:100]...), btcPendingCctxs[0:100]...), - // expectedTotalPending: 400, - // expectedWithdrawWindow: 500, // the sliding window - // expectedWithdrawRate: sdk.NewDec(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block - // rateLimitExceeded: true, - // }, - // { - // name: "set a lower gRPC request limit and reach the limit of the query in forward loop", - // rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(10*1e18), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), - // ethMinedCctxs: ethMinedCctxs, - // ethPendingCctxs: ethPendingCctxs, - // ethPendingNonces: observertypes.PendingNonces{ - // ChainId: ethChainID, - // NonceLow: 1099, - // NonceHigh: 1199, - // Tss: tss.TssPubkey, - // }, - // btcMinedCctxs: btcMinedCctxs, - // btcPendingCctxs: btcPendingCctxs, - // btcPendingNonces: observertypes.PendingNonces{ - // ChainId: btcChainID, - // NonceLow: 1099, - // NonceHigh: 1199, - // Tss: tss.TssPubkey, - // }, - // currentHeight: 1199, - // queryLimit: 300, // 300 < keeper.MaxPendingCctxs - // expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs[0:100]...), btcPendingCctxs...), - // expectedTotalPending: 400, - // expectedWithdrawWindow: 500, // the sliding window - // expectedWithdrawRate: sdk.NewDec(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block - // rateLimitExceeded: false, - // }, - // { - // name: "set a median rate (2.4 ZETA < rate < 3 ZETA) to exceed rate limit in forward loop", - // rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(26*1e17), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), - // ethMinedCctxs: ethMinedCctxs, - // ethPendingCctxs: ethPendingCctxs, - // ethPendingNonces: observertypes.PendingNonces{ - // ChainId: ethChainID, - // NonceLow: 1099, - // NonceHigh: 1199, - // Tss: tss.TssPubkey, - // }, - // btcMinedCctxs: btcMinedCctxs, - // btcPendingCctxs: btcPendingCctxs, - // btcPendingNonces: observertypes.PendingNonces{ - // ChainId: btcChainID, - // NonceLow: 1099, - // NonceHigh: 1199, - // Tss: tss.TssPubkey, - // }, - // currentHeight: 1199, - // queryLimit: keeper.MaxPendingCctxs, - // // return missed cctxs only if rate limit is exceeded - // expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs[0:100]...), btcPendingCctxs[0:100]...), - // expectedTotalPending: 400, - // expectedWithdrawWindow: 500, // the sliding window - // expectedWithdrawRate: sdk.NewDec(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block - // rateLimitExceeded: true, - // }, + { + name: "should use fallback query if rate limiter is disabled", + fallback: true, + rateLimitFlags: nil, // no rate limiter flags set in the keeper + ethMinedCctxs: ethMinedCctxs, + ethPendingCctxs: ethPendingCctxs, + ethPendingNonces: observertypes.PendingNonces{ + ChainId: ethChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + btcMinedCctxs: btcMinedCctxs, + btcPendingCctxs: btcPendingCctxs, + btcPendingNonces: observertypes.PendingNonces{ + ChainId: btcChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + currentHeight: 1199, + queryLimit: keeper.MaxPendingCctxs, + expectedCctxs: append(append([]*types.CrossChainTx{}, btcPendingCctxs...), ethPendingCctxs...), + expectedTotalPending: 400, + }, + { + name: "should use fallback query if rate is 0", + fallback: true, + rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(0), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), + ethMinedCctxs: ethMinedCctxs, + ethPendingCctxs: ethPendingCctxs, + ethPendingNonces: observertypes.PendingNonces{ + ChainId: ethChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + btcMinedCctxs: btcMinedCctxs, + btcPendingCctxs: btcPendingCctxs, + btcPendingNonces: observertypes.PendingNonces{ + ChainId: btcChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + currentHeight: 1199, + queryLimit: keeper.MaxPendingCctxs, + expectedCctxs: append(append([]*types.CrossChainTx{}, btcPendingCctxs...), ethPendingCctxs...), + expectedTotalPending: 400, + }, + { + name: "can retrieve all pending cctx without exceeding rate limit", + rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(10*1e18), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), + ethMinedCctxs: ethMinedCctxs, + ethPendingCctxs: ethPendingCctxs, + ethPendingNonces: observertypes.PendingNonces{ + ChainId: ethChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + btcMinedCctxs: btcMinedCctxs, + btcPendingCctxs: btcPendingCctxs, + btcPendingNonces: observertypes.PendingNonces{ + ChainId: btcChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + currentHeight: 1199, + queryLimit: keeper.MaxPendingCctxs, + expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs...), btcPendingCctxs...), + expectedTotalPending: 400, + expectedWithdrawWindow: 500, // the sliding window + expectedWithdrawRate: sdk.NewDec(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block + rateLimitExceeded: false, + }, + { + name: "can loop backwards all the way to endNonce 0", + rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(10*1e18), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), + ethMinedCctxs: ethMinedCctxs, + ethPendingCctxs: ethPendingCctxs, + ethPendingNonces: observertypes.PendingNonces{ + ChainId: ethChainID, + NonceLow: 999, // endNonce will be set to 0 (NonceLow - 1000 < 0) + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + btcMinedCctxs: btcMinedCctxs, + btcPendingCctxs: btcPendingCctxs, + btcPendingNonces: observertypes.PendingNonces{ + ChainId: btcChainID, + NonceLow: 999, // endNonce will be set to 0 (NonceLow - 1000 < 0) + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + currentHeight: 1199, + queryLimit: keeper.MaxPendingCctxs, + expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs...), btcPendingCctxs...), + expectedTotalPending: 400, + expectedWithdrawWindow: 500, // the sliding window + expectedWithdrawRate: sdk.NewDec(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block + rateLimitExceeded: false, + }, + { + name: "set a low rate (rate < 2.4 ZETA) to exceed rate limit in backward loop", + rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(2*1e18), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), + ethMinedCctxs: ethMinedCctxs, + ethPendingCctxs: ethPendingCctxs, + ethPendingNonces: observertypes.PendingNonces{ + ChainId: ethChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + btcMinedCctxs: btcMinedCctxs, + btcPendingCctxs: btcPendingCctxs, + btcPendingNonces: observertypes.PendingNonces{ + ChainId: btcChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + currentHeight: 1199, + queryLimit: keeper.MaxPendingCctxs, + // return missed cctxs only if rate limit is exceeded + expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs[0:100]...), btcPendingCctxs[0:100]...), + expectedTotalPending: 400, + expectedWithdrawWindow: 500, // the sliding window + expectedWithdrawRate: sdk.NewDec(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block + rateLimitExceeded: true, + }, + { + name: "set a lower gRPC request limit and reach the limit of the query in forward loop", + rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(10*1e18), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), + ethMinedCctxs: ethMinedCctxs, + ethPendingCctxs: ethPendingCctxs, + ethPendingNonces: observertypes.PendingNonces{ + ChainId: ethChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + btcMinedCctxs: btcMinedCctxs, + btcPendingCctxs: btcPendingCctxs, + btcPendingNonces: observertypes.PendingNonces{ + ChainId: btcChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + currentHeight: 1199, + queryLimit: 300, // 300 < keeper.MaxPendingCctxs + expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs[0:100]...), btcPendingCctxs...), + expectedTotalPending: 400, + expectedWithdrawWindow: 500, // the sliding window + expectedWithdrawRate: sdk.NewDec(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block + rateLimitExceeded: false, + }, + { + name: "set a median rate (2.4 ZETA < rate < 3 ZETA) to exceed rate limit in forward loop", + rateLimitFlags: createTestRateLimiterFlags(500, math.NewUint(26*1e17), zrc20ETH, zrc20BTC, zrc20USDT, "2500", "50000", "0.8"), + ethMinedCctxs: ethMinedCctxs, + ethPendingCctxs: ethPendingCctxs, + ethPendingNonces: observertypes.PendingNonces{ + ChainId: ethChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + btcMinedCctxs: btcMinedCctxs, + btcPendingCctxs: btcPendingCctxs, + btcPendingNonces: observertypes.PendingNonces{ + ChainId: btcChainID, + NonceLow: 1099, + NonceHigh: 1199, + Tss: tss.TssPubkey, + }, + currentHeight: 1199, + queryLimit: keeper.MaxPendingCctxs, + // return missed cctxs only if rate limit is exceeded + expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs[0:100]...), btcPendingCctxs[0:100]...), + expectedTotalPending: 400, + expectedWithdrawWindow: 500, // the sliding window + expectedWithdrawRate: sdk.NewDec(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block + rateLimitExceeded: true, + }, { // the pending cctxs window is wider than the rate limiter sliding window in this test case. name: "set low rate and narrow window to early exceed rate limit in forward loop", From c011900c2fdd4e651a9e58a3f10f93aee4ec5774 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Mon, 29 Apr 2024 12:27:59 -0500 Subject: [PATCH 27/33] replace sdk.Dec with sdkmath.Int to represent cctx value in azeta --- pkg/coin/coin.go | 4 ++ pkg/coin/coin_test.go | 4 ++ .../keeper/grpc_query_cctx_rate_limit.go | 66 +++++++++---------- .../keeper/grpc_query_cctx_rate_limit_test.go | 34 +++++----- 4 files changed, 58 insertions(+), 50 deletions(-) diff --git a/pkg/coin/coin.go b/pkg/coin/coin.go index 74bbca935b..a11f5b91bd 100644 --- a/pkg/coin/coin.go +++ b/pkg/coin/coin.go @@ -7,6 +7,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +func AzetaPerZeta() sdk.Dec { + return sdk.NewDec(1e18) +} + func GetCoinType(coin string) (CoinType, error) { coinInt, err := strconv.ParseInt(coin, 10, 32) if err != nil { diff --git a/pkg/coin/coin_test.go b/pkg/coin/coin_test.go index 6110c20538..be7808d7a2 100644 --- a/pkg/coin/coin_test.go +++ b/pkg/coin/coin_test.go @@ -7,6 +7,10 @@ import ( "github.com/stretchr/testify/require" ) +func Test_AzetaPerZeta(t *testing.T) { + require.Equal(t, sdk.NewDec(1e18), AzetaPerZeta()) +} + func Test_GetAzetaDecFromAmountInZeta(t *testing.T) { tt := []struct { name string diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go index aadb94674d..57ce375048 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go @@ -5,6 +5,7 @@ import ( "sort" "strings" + sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/zeta-chain/zetacore/pkg/coin" "github.com/zeta-chain/zetacore/x/crosschain/types" @@ -31,7 +32,7 @@ func (k Keeper) ListPendingCctxWithinRateLimit(c context.Context, req *types.Que // define a few variables to be used in the query loops limitExceeded := false totalPending := uint64(0) - totalWithdrawInZeta := sdk.NewDec(0) + totalWithdrawInAzeta := sdkmath.NewInt(0) cctxs := make([]*types.CrossChainTx, 0) chains := k.zetaObserverKeeper.GetSupportedForeignChains(ctx) @@ -81,15 +82,15 @@ func (k Keeper) ListPendingCctxWithinRateLimit(c context.Context, req *types.Que var gasCoinRates map[int64]sdk.Dec var erc20CoinRates map[int64]map[string]sdk.Dec var foreignCoinMap map[int64]map[string]fungibletypes.ForeignCoins - var windowLimitInZeta sdk.Dec - var blockLimitInZeta sdk.Dec + var blockLimitInAzeta sdkmath.Int + var windowLimitInAzeta sdkmath.Int if applyLimit { gasCoinRates, erc20CoinRates = k.GetRateLimiterRates(ctx) foreignCoinMap = k.fungibleKeeper.GetAllForeignCoinMap(ctx) - // convert the rate limit from aZETA to ZETA - blockLimitInZeta = sdk.NewDecFromBigInt(rateLimitFlags.Rate.BigInt()).Quo(sdk.NewDec(10).Power(18)) - windowLimitInZeta = blockLimitInZeta.Mul(sdk.NewDec(rateLimitFlags.Window)) + // initiate block limit and window limit in azeta + blockLimitInAzeta = sdkmath.NewIntFromBigInt(rateLimitFlags.Rate.BigInt()) + windowLimitInAzeta = blockLimitInAzeta.Mul(sdkmath.NewInt(rateLimitFlags.Window)) } // the criteria to stop adding cctxs to the rpc response @@ -132,14 +133,14 @@ func (k Keeper) ListPendingCctxWithinRateLimit(c context.Context, req *types.Que // invariant: for period of time >= `rateLimitFlags.Window`, the zetaclient-side average withdraw rate should be <= `blockLimitInZeta` // otherwise, this query should return empty result and wait for the average rate to drop below `blockLimitInZeta` withdrawWindow := rateLimitFlags.Window - withdrawLimitInZeta := windowLimitInZeta + withdrawLimitInAzeta := windowLimitInAzeta if lowestPendingCctxHeight != 0 { // `pendingCctxWindow` is the width of [lowestPendingCctxHeight, height] window // if the window can be wider than `rateLimitFlags.Window`, we should adjust the total withdraw limit proportionally pendingCctxWindow := height - lowestPendingCctxHeight + 1 if pendingCctxWindow > rateLimitFlags.Window { withdrawWindow = pendingCctxWindow - withdrawLimitInZeta = blockLimitInZeta.Mul(sdk.NewDec(pendingCctxWindow)) + withdrawLimitInAzeta = blockLimitInAzeta.Mul(sdk.NewInt(pendingCctxWindow)) } } @@ -170,7 +171,7 @@ func (k Keeper) ListPendingCctxWithinRateLimit(c context.Context, req *types.Que break } // skip the cctx if rate limit is exceeded but still accumulate the total withdraw value - if inWindow && rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap, &totalWithdrawInZeta, withdrawLimitInZeta) { + if inWindow && rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap, &totalWithdrawInAzeta, withdrawLimitInAzeta) { limitExceeded = true continue } @@ -203,7 +204,7 @@ func (k Keeper) ListPendingCctxWithinRateLimit(c context.Context, req *types.Que } // skip the cctx if rate limit is exceeded but still accumulate the total withdraw value - if rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap, &totalWithdrawInZeta, withdrawLimitInZeta) { + if rateLimitExceeded(chain.ChainId, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap, &totalWithdrawInAzeta, withdrawLimitInAzeta) { limitExceeded = true continue } @@ -232,26 +233,25 @@ func (k Keeper) ListPendingCctxWithinRateLimit(c context.Context, req *types.Que CrossChainTx: cctxs, TotalPending: totalPending, CurrentWithdrawWindow: withdrawWindow, - CurrentWithdrawRate: totalWithdrawInZeta.Mul(sdk.NewDec(10).Power(18)).Quo(sdk.NewDec(withdrawWindow)).String(), + CurrentWithdrawRate: totalWithdrawInAzeta.Quo(sdk.NewInt(withdrawWindow)).String(), RateLimitExceeded: limitExceeded, }, nil } -// ConvertCctxValue converts the value of the cctx in ZETA using given conversion rates +// ConvertCctxValue converts the value of the cctx to azeta using given conversion rates func ConvertCctxValue( chainID int64, cctx *types.CrossChainTx, gasCoinRates map[int64]sdk.Dec, erc20CoinRates map[int64]map[string]sdk.Dec, foreignCoinMap map[int64]map[string]fungibletypes.ForeignCoins, -) sdk.Dec { +) sdkmath.Int { var rate sdk.Dec var decimals uint64 switch cctx.InboundTxParams.CoinType { case coin.CoinType_Zeta: // no conversion needed for ZETA - amountCctx := sdk.NewDecFromBigInt(cctx.GetCurrentOutTxParam().Amount.BigInt()) - return amountCctx.Quo(sdk.NewDec(10).Power(18)) + return sdkmath.NewIntFromBigInt(cctx.GetCurrentOutTxParam().Amount.BigInt()) case coin.CoinType_Gas: rate = gasCoinRates[chainID] case coin.CoinType_ERC20: @@ -259,43 +259,43 @@ func ConvertCctxValue( _, found := erc20CoinRates[chainID] if !found { // skip if no rate found for this chainID - return sdk.NewDec(0) + return sdkmath.NewInt(0) } rate = erc20CoinRates[chainID][strings.ToLower(cctx.InboundTxParams.Asset)] default: // skip CoinType_Cmd - return sdk.NewDec(0) + return sdkmath.NewInt(0) } // should not happen, return 0 to skip if it happens if rate.IsNil() || rate.LTE(sdk.NewDec(0)) { - return sdk.NewDec(0) + return sdkmath.NewInt(0) } // get foreign coin decimals foreignCoinFromChainMap, found := foreignCoinMap[chainID] if !found { // skip if no coin found for this chainID - return sdk.NewDec(0) + return sdkmath.NewInt(0) } foreignCoin, found := foreignCoinFromChainMap[strings.ToLower(cctx.InboundTxParams.Asset)] if !found { // skip if no coin found for this Asset - return sdk.NewDec(0) + return sdkmath.NewInt(0) } decimals = uint64(foreignCoin.Decimals) - // given decimals = 6, the `oneZrc20` amount will be 10^6 = 1000000 + // the whole coin amounts of zeta and zrc20 + // given decimals = 6, the amount will be 10^6 = 1000000 + oneZeta := coin.AzetaPerZeta() oneZrc20 := sdk.NewDec(10).Power(decimals) - // convert asset amount into ZETA - // step 1: convert the amount into ZRC20 integer amount - // step 2: convert the ZRC20 integer amount into decimal amount + // convert cctx asset amount into azeta amount // given amountCctx = 2000000, rate = 0.8, decimals = 6 - // the amountZrc20 = 2000000 * 0.8 = 1600000, the amountZeta = 1600000 / 1000000 = 1.6 - amountCctx := sdk.NewDecFromBigInt(cctx.GetCurrentOutTxParam().Amount.BigInt()) - amountZrc20 := amountCctx.Mul(rate) - amountZeta := amountZrc20.Quo(oneZrc20) - return amountZeta + // amountCctxDec: 2000000 * 0.8 = 1600000.0 + // amountAzetaDec: 1600000.0 * 10e18 / 10e6 = 1600000000000000000.0 + amountCctxDec := sdk.NewDecFromBigInt(cctx.GetCurrentOutTxParam().Amount.BigInt()) + amountAzetaDec := amountCctxDec.Mul(rate).Mul(oneZeta).Quo(oneZrc20) + return amountAzetaDec.TruncateInt() } // rateLimitExceeded accumulates the cctx value and then checks if the rate limit is exceeded @@ -306,10 +306,10 @@ func rateLimitExceeded( gasCoinRates map[int64]sdk.Dec, erc20CoinRates map[int64]map[string]sdk.Dec, foreignCoinMap map[int64]map[string]fungibletypes.ForeignCoins, - currentCctxValue *sdk.Dec, - withdrawLimitInZeta sdk.Dec, + currentCctxValue *sdkmath.Int, + withdrawLimitInZeta sdkmath.Int, ) bool { - amountZeta := ConvertCctxValue(chainID, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap) - *currentCctxValue = currentCctxValue.Add(amountZeta) + cctxValueAzeta := ConvertCctxValue(chainID, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap) + *currentCctxValue = currentCctxValue.Add(cctxValueAzeta) return currentCctxValue.GT(withdrawLimitInZeta) } diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go index 71a31ce2f7..6418e57c03 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go @@ -161,7 +161,7 @@ func Test_ConvertCctxValue(t *testing.T) { // convert cctx value value := keeper.ConvertCctxValue(ethChainID, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap) - require.Equal(t, sdk.MustNewDecFromStr("0.3"), value) + require.Equal(t, sdk.NewInt(3e17), value) }) t.Run("should convert cctx ETH value correctly", func(t *testing.T) { // create cctx with 0.003 ETH @@ -172,7 +172,7 @@ func Test_ConvertCctxValue(t *testing.T) { // convert cctx value: 0.003 ETH * 2500 = 7.5 ZETA value := keeper.ConvertCctxValue(ethChainID, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap) - require.Equal(t, sdk.MustNewDecFromStr("7.5"), value) + require.Equal(t, sdk.NewInt(75e17), value) }) t.Run("should convert cctx BTC value correctly", func(t *testing.T) { // create cctx with 0.0007 BTC @@ -183,7 +183,7 @@ func Test_ConvertCctxValue(t *testing.T) { // convert cctx value: 0.0007 BTC * 50000 = 35.0 ZETA value := keeper.ConvertCctxValue(btcChainID, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap) - require.Equal(t, sdk.MustNewDecFromStr("35.0"), value) + require.Equal(t, sdk.NewInt(35).Mul(sdk.NewInt(1e18)), value) }) t.Run("should convert cctx USDT value correctly", func(t *testing.T) { // create cctx with 3 USDT @@ -194,7 +194,7 @@ func Test_ConvertCctxValue(t *testing.T) { // convert cctx value: 3 USDT * 0.8 = 2.4 ZETA value := keeper.ConvertCctxValue(ethChainID, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap) - require.Equal(t, sdk.MustNewDecFromStr("2.4"), value) + require.Equal(t, sdk.NewInt(24e17), value) }) t.Run("should return 0 if no rate found for chainID", func(t *testing.T) { cctx := sample.CrossChainTx(t, fmt.Sprintf("%d-%d", ethChainID, 1)) @@ -203,7 +203,7 @@ func Test_ConvertCctxValue(t *testing.T) { // use nil erc20CoinRates map to convert cctx value value := keeper.ConvertCctxValue(ethChainID, cctx, gasCoinRates, nil, foreignCoinMap) - require.Equal(t, sdk.NewDec(0), value) + require.Equal(t, sdk.NewInt(0), value) }) t.Run("should return 0 if coinType is CoinType_Cmd", func(t *testing.T) { cctx := sample.CrossChainTx(t, fmt.Sprintf("%d-%d", ethChainID, 1)) @@ -212,7 +212,7 @@ func Test_ConvertCctxValue(t *testing.T) { // convert cctx value value := keeper.ConvertCctxValue(ethChainID, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap) - require.Equal(t, sdk.NewDec(0), value) + require.Equal(t, sdk.NewInt(0), value) }) t.Run("should return 0 on nil rate or rate <= 0", func(t *testing.T) { cctx := sample.CrossChainTx(t, fmt.Sprintf("%d-%d", ethChainID, 1)) @@ -221,7 +221,7 @@ func Test_ConvertCctxValue(t *testing.T) { // use nil gasCoinRates map to convert cctx value value := keeper.ConvertCctxValue(ethChainID, cctx, nil, erc20CoinRates, foreignCoinMap) - require.Equal(t, sdk.NewDec(0), value) + require.Equal(t, sdk.NewInt(0), value) // set rate to 0 zeroCoinRates, _ := k.GetRateLimiterRates(ctx) @@ -229,7 +229,7 @@ func Test_ConvertCctxValue(t *testing.T) { // convert cctx value value = keeper.ConvertCctxValue(ethChainID, cctx, zeroCoinRates, erc20CoinRates, foreignCoinMap) - require.Equal(t, sdk.NewDec(0), value) + require.Equal(t, sdk.NewInt(0), value) // set rate to -1 negativeCoinRates, _ := k.GetRateLimiterRates(ctx) @@ -237,7 +237,7 @@ func Test_ConvertCctxValue(t *testing.T) { // convert cctx value value = keeper.ConvertCctxValue(ethChainID, cctx, negativeCoinRates, erc20CoinRates, foreignCoinMap) - require.Equal(t, sdk.NewDec(0), value) + require.Equal(t, sdk.NewInt(0), value) }) t.Run("should return 0 if no coin found for chainID", func(t *testing.T) { cctx := sample.CrossChainTx(t, fmt.Sprintf("%d-%d", ethChainID, 1)) @@ -246,7 +246,7 @@ func Test_ConvertCctxValue(t *testing.T) { // use empty foreignCoinMap to convert cctx value value := keeper.ConvertCctxValue(ethChainID, cctx, gasCoinRates, erc20CoinRates, nil) - require.Equal(t, sdk.NewDec(0), value) + require.Equal(t, sdk.NewInt(0), value) }) t.Run("should return 0 if no coin found for asset", func(t *testing.T) { cctx := sample.CrossChainTx(t, fmt.Sprintf("%d-%d", ethChainID, 1)) @@ -260,7 +260,7 @@ func Test_ConvertCctxValue(t *testing.T) { // convert cctx value value := keeper.ConvertCctxValue(ethChainID, cctx, gasCoinRates, erc20CoinRates, tempCoinMap) - require.Equal(t, sdk.NewDec(0), value) + require.Equal(t, sdk.NewInt(0), value) }) } @@ -384,7 +384,7 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs...), btcPendingCctxs...), expectedTotalPending: 400, expectedWithdrawWindow: 500, // the sliding window - expectedWithdrawRate: sdk.NewDec(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block + expectedWithdrawRate: sdk.NewInt(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block rateLimitExceeded: false, }, { @@ -411,7 +411,7 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs...), btcPendingCctxs...), expectedTotalPending: 400, expectedWithdrawWindow: 500, // the sliding window - expectedWithdrawRate: sdk.NewDec(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block + expectedWithdrawRate: sdk.NewInt(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block rateLimitExceeded: false, }, { @@ -439,7 +439,7 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs[0:100]...), btcPendingCctxs[0:100]...), expectedTotalPending: 400, expectedWithdrawWindow: 500, // the sliding window - expectedWithdrawRate: sdk.NewDec(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block + expectedWithdrawRate: sdk.NewInt(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block rateLimitExceeded: true, }, { @@ -466,7 +466,7 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs[0:100]...), btcPendingCctxs...), expectedTotalPending: 400, expectedWithdrawWindow: 500, // the sliding window - expectedWithdrawRate: sdk.NewDec(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block + expectedWithdrawRate: sdk.NewInt(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block rateLimitExceeded: false, }, { @@ -494,7 +494,7 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs[0:100]...), btcPendingCctxs[0:100]...), expectedTotalPending: 400, expectedWithdrawWindow: 500, // the sliding window - expectedWithdrawRate: sdk.NewDec(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block + expectedWithdrawRate: sdk.NewInt(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block rateLimitExceeded: true, }, { @@ -526,7 +526,7 @@ func TestKeeper_ListPendingCctxWithinRateLimit(t *testing.T) { expectedCctxs: append(append([]*types.CrossChainTx{}, ethPendingCctxs[0:100]...), btcPendingCctxs[0:100]...), expectedTotalPending: 400, expectedWithdrawWindow: 100, // 100 > sliding window 50 - expectedWithdrawRate: sdk.NewDec(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block + expectedWithdrawRate: sdk.NewInt(3e18).String(), // 3 ZETA, (2.5 + 0.5) per block rateLimitExceeded: true, }, } From 289ec624c5b150c757aa0e20b56c7703f26ee711 Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Mon, 29 Apr 2024 19:52:19 +0200 Subject: [PATCH 28/33] test: disable header proof test in local upgrade test E2E test (#2051) * add skip header option * use option for migration test * move bitcoin addresses tests to advanced * show cctx in logs * update version * fix verification flags error --- Dockerfile-upgrade | 4 +-- app/setup_handlers.go | 2 +- cmd/zetae2e/local/local.go | 27 +++++++++++++------ .../localnet/orchestrator/start-zetae2e.sh | 8 +++--- contrib/localnet/scripts/start-zetaclientd.sh | 2 +- e2e/utils/zetacore.go | 12 +++++++-- zetaclient/zetabridge/zetacore_bridge.go | 26 +++++++++++------- 7 files changed, 54 insertions(+), 27 deletions(-) diff --git a/Dockerfile-upgrade b/Dockerfile-upgrade index e53b766256..f0ffab02fd 100644 --- a/Dockerfile-upgrade +++ b/Dockerfile-upgrade @@ -20,8 +20,8 @@ WORKDIR /go/delivery/zeta-node RUN mkdir -p $GOPATH/bin/old RUN mkdir -p $GOPATH/bin/new -ARG OLD_VERSION=v14.0.0 -ENV NEW_VERSION=v15 +ARG OLD_VERSION=v15.0.0 +ENV NEW_VERSION=v16 # Build new release from the current source COPY go.mod /go/delivery/zeta-node/ diff --git a/app/setup_handlers.go b/app/setup_handlers.go index 19fcc96860..c746597bb9 100644 --- a/app/setup_handlers.go +++ b/app/setup_handlers.go @@ -10,7 +10,7 @@ import ( observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) -const releaseVersion = "v15" +const releaseVersion = "v16" func SetupHandlers(app *App) { app.UpgradeKeeper.SetUpgradeHandler(releaseVersion, func(ctx sdk.Context, _ types.Plan, vm module.VersionMap) (module.VersionMap, error) { diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index 62e0182ecf..ed89dd8a5f 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -30,6 +30,7 @@ const ( flagSetupOnly = "setup-only" flagSkipSetup = "skip-setup" flagSkipBitcoinSetup = "skip-bitcoin-setup" + flagSkipHeaderProof = "skip-header-proof" ) var ( @@ -57,6 +58,7 @@ func NewLocalCmd() *cobra.Command { cmd.Flags().String(flagConfigOut, "", "config file to write the deployed contracts from the setup") cmd.Flags().Bool(flagSkipSetup, false, "set to true to skip setup") cmd.Flags().Bool(flagSkipBitcoinSetup, false, "set to true to skip bitcoin wallet setup") + cmd.Flags().Bool(flagSkipHeaderProof, false, "set to true to skip header proof tests") return cmd } @@ -111,6 +113,10 @@ func localE2ETest(cmd *cobra.Command, _ []string) { if err != nil { panic(err) } + skipHeaderProof, err := cmd.Flags().GetBool(flagSkipHeaderProof) + if err != nil { + panic(err) + } logger := runner.NewLogger(verbose, color.FgWhite, "setup") @@ -189,8 +195,10 @@ func localE2ETest(cmd *cobra.Command, _ []string) { logger.Print("⚙️ setting up networks") startTime := time.Now() - if err := deployerRunner.EnableVerificationFlags(); err != nil { - panic(err) + if !skipHeaderProof { + if err := deployerRunner.EnableVerificationFlags(); err != nil { + panic(err) + } } deployerRunner.SetupEVM(contractsDeployed, true) @@ -262,15 +270,15 @@ func localE2ETest(cmd *cobra.Command, _ []string) { } bitcoinTests := []string{ e2etests.TestBitcoinWithdrawSegWitName, - e2etests.TestBitcoinWithdrawTaprootName, - e2etests.TestBitcoinWithdrawLegacyName, - e2etests.TestBitcoinWithdrawP2SHName, - e2etests.TestBitcoinWithdrawP2WSHName, e2etests.TestBitcoinWithdrawInvalidAddressName, e2etests.TestZetaWithdrawBTCRevertName, e2etests.TestCrosschainSwapName, } bitcoinAdvancedTests := []string{ + e2etests.TestBitcoinWithdrawTaprootName, + e2etests.TestBitcoinWithdrawLegacyName, + e2etests.TestBitcoinWithdrawP2SHName, + e2etests.TestBitcoinWithdrawP2WSHName, e2etests.TestBitcoinWithdrawRestrictedName, } ethereumTests := []string{ @@ -290,10 +298,13 @@ func localE2ETest(cmd *cobra.Command, _ []string) { ethereumTests = append(ethereumTests, ethereumAdvancedTests...) } + // skip the header proof test if we run light test or skipHeaderProof is enabled + testHeader := !light && !skipHeaderProof + eg.Go(erc20TestRoutine(conf, deployerRunner, verbose, erc20Tests...)) eg.Go(zetaTestRoutine(conf, deployerRunner, verbose, zetaTests...)) - eg.Go(bitcoinTestRoutine(conf, deployerRunner, verbose, !skipBitcoinSetup, !light, bitcoinTests...)) - eg.Go(ethereumTestRoutine(conf, deployerRunner, verbose, !light, ethereumTests...)) + eg.Go(bitcoinTestRoutine(conf, deployerRunner, verbose, !skipBitcoinSetup, testHeader, bitcoinTests...)) + eg.Go(ethereumTestRoutine(conf, deployerRunner, verbose, testHeader, ethereumTests...)) } if testAdmin { eg.Go(adminTestRoutine(conf, deployerRunner, verbose, diff --git a/contrib/localnet/orchestrator/start-zetae2e.sh b/contrib/localnet/orchestrator/start-zetae2e.sh index a893c689ee..4f07e162a2 100644 --- a/contrib/localnet/orchestrator/start-zetae2e.sh +++ b/contrib/localnet/orchestrator/start-zetae2e.sh @@ -57,12 +57,12 @@ if [ "$OPTION" == "upgrade" ]; then # Run zetae2e, if the upgrade height is lower than 100, we use the setup-only flag if [ "$UPGRADE_HEIGHT" -lt 100 ]; then echo "running E2E command to setup the networks..." - zetae2e "$ZETAE2E_CMD" --setup-only --config-out deployed.yml + zetae2e "$ZETAE2E_CMD" --setup-only --config-out deployed.yml --skip-header-proof else echo "running E2E command to setup the networks and populate the state..." # Use light flag to ensure tests can complete before the upgrade height - zetae2e "$ZETAE2E_CMD" --config-out deployed.yml --light + zetae2e "$ZETAE2E_CMD" --config-out deployed.yml --light --skip-header-proof fi ZETAE2E_EXIT_CODE=$? @@ -86,9 +86,9 @@ if [ "$OPTION" == "upgrade" ]; then # When the upgrade height is greater than 100 for upgrade test, the Bitcoin tests have been run once, therefore the Bitcoin wallet is already set up # Use light flag to skip advanced tests if [ "$UPGRADE_HEIGHT" -lt 100 ]; then - zetae2e "$ZETAE2E_CMD" --skip-setup --config deployed.yml --light + zetae2e "$ZETAE2E_CMD" --skip-setup --config deployed.yml --light --skip-header-proof else - zetae2e "$ZETAE2E_CMD" --skip-setup --config deployed.yml --skip-bitcoin-setup --light + zetae2e "$ZETAE2E_CMD" --skip-setup --config deployed.yml --skip-bitcoin-setup --light --skip-header-proof fi ZETAE2E_EXIT_CODE=$? diff --git a/contrib/localnet/scripts/start-zetaclientd.sh b/contrib/localnet/scripts/start-zetaclientd.sh index a43e8e120f..89c691d52b 100755 --- a/contrib/localnet/scripts/start-zetaclientd.sh +++ b/contrib/localnet/scripts/start-zetaclientd.sh @@ -34,7 +34,7 @@ if [ $HOSTNAME == "zetaclient0" ] then rm ~/.tss/* MYIP=$(/sbin/ip -o -4 addr list eth0 | awk '{print $4}' | cut -d/ -f1) - zetaclientd init --zetacore-url zetacore0 --chain-id athens_101-1 --operator "$operatorAddress" --log-format=text --public-ip "$MYIP" --keyring-backend "$BACKEND" + zetaclientd init --zetacore-url zetacore0 --chain-id athens_101-1 --operator "$operatorAddress" --log-format=text --public-ip "$MYIP" --keyring-backend "$BACKEND" # check if the option is additional-evm # in this case, the additional evm is represented with the sepolia chain, we set manually the eth2 endpoint to the sepolia chain (11155111 -> http://eth2:8545) diff --git a/e2e/utils/zetacore.go b/e2e/utils/zetacore.go index 9abaea7284..d30af9f321 100644 --- a/e2e/utils/zetacore.go +++ b/e2e/utils/zetacore.go @@ -49,8 +49,16 @@ func WaitCctxsMinedByInTxHash( // fetch cctxs by inTxHash for i := 0; ; i++ { + // declare cctxs here so we can print the last fetched one if we reach timeout + var cctxs []*crosschaintypes.CrossChainTx + if time.Since(startTime) > timeout { - panic(fmt.Sprintf("waiting cctx timeout, cctx not mined, inTxHash: %s", inTxHash)) + cctxMessage := "" + if len(cctxs) > 0 { + cctxMessage = fmt.Sprintf(", last cctx: %v", cctxs[0].String()) + } + + panic(fmt.Sprintf("waiting cctx timeout, cctx not mined, inTxHash: %s%s", inTxHash, cctxMessage)) } time.Sleep(1 * time.Second) @@ -77,7 +85,7 @@ func WaitCctxsMinedByInTxHash( } continue } - cctxs := make([]*crosschaintypes.CrossChainTx, 0, len(res.CrossChainTxs)) + cctxs = make([]*crosschaintypes.CrossChainTx, 0, len(res.CrossChainTxs)) allFound := true for j, cctx := range res.CrossChainTxs { cctx := cctx diff --git a/zetaclient/zetabridge/zetacore_bridge.go b/zetaclient/zetabridge/zetacore_bridge.go index 3899d51d82..107a40ade7 100644 --- a/zetaclient/zetabridge/zetacore_bridge.go +++ b/zetaclient/zetabridge/zetacore_bridge.go @@ -17,6 +17,7 @@ import ( "github.com/zeta-chain/zetacore/pkg/authz" "github.com/zeta-chain/zetacore/pkg/chains" crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" + lightclienttypes "github.com/zeta-chain/zetacore/x/lightclient/types" observertypes "github.com/zeta-chain/zetacore/x/observer/types" "github.com/zeta-chain/zetacore/zetaclient/config" corecontext "github.com/zeta-chain/zetacore/zetaclient/core_context" @@ -200,12 +201,12 @@ func (b *ZetaCoreBridge) GetKeys() *keys.Keys { func (b *ZetaCoreBridge) UpdateZetaCoreContext(coreContext *corecontext.ZetaCoreContext, init bool, sampledLogger zerolog.Logger) error { bn, err := b.GetZetaBlockHeight() if err != nil { - return err + return fmt.Errorf("failed to get zetablock height: %w", err) } plan, err := b.GetUpgradePlan() - // if there is no active upgrade plan, plan will be nil, err will be nil as well. if err != nil { - return err + // if there is no active upgrade plan, plan will be nil, err will be nil as well. + return fmt.Errorf("failed to get upgrade plan: %w", err) } if plan != nil && bn == plan.Height-1 { // stop zetaclients; notify operator to upgrade and restart b.logger.Warn().Msgf("Active upgrade plan detected and upgrade height reached: %s at height %d; ZetaClient is stopped;"+ @@ -215,7 +216,7 @@ func (b *ZetaCoreBridge) UpdateZetaCoreContext(coreContext *corecontext.ZetaCore chainParams, err := b.GetChainParams() if err != nil { - return err + return fmt.Errorf("failed to get chain params: %w", err) } newEVMParams := make(map[int64]*observertypes.ChainParams) @@ -241,7 +242,7 @@ func (b *ZetaCoreBridge) UpdateZetaCoreContext(coreContext *corecontext.ZetaCore supportedChains, err := b.GetSupportedChains() if err != nil { - return err + return fmt.Errorf("failed to get supported chains: %w", err) } newChains := make([]chains.Chain, len(supportedChains)) for i, chain := range supportedChains { @@ -250,26 +251,33 @@ func (b *ZetaCoreBridge) UpdateZetaCoreContext(coreContext *corecontext.ZetaCore keyGen, err := b.GetKeyGen() if err != nil { b.logger.Info().Msg("Unable to fetch keygen from zetabridge") - return err + return fmt.Errorf("failed to get keygen: %w", err) } tss, err := b.GetCurrentTss() if err != nil { b.logger.Info().Err(err).Msg("Unable to fetch TSS from zetabridge") - return err + return fmt.Errorf("failed to get current tss: %w", err) } tssPubKey := tss.GetTssPubkey() crosschainFlags, err := b.GetCrosschainFlags() if err != nil { b.logger.Info().Msg("Unable to fetch cross-chain flags from zetabridge") - return err + return fmt.Errorf("failed to get crosschain flags: %w", err) } verificationFlags, err := b.GetVerificationFlags() if err != nil { b.logger.Info().Msg("Unable to fetch verification flags from zetabridge") - return err + + // The block header functionality is currently disabled on the ZetaCore side + // The verification flags might not exist and we should not return an error here to prevent the ZetaClient from starting + // TODO: Uncomment this line when the block header functionality is enabled and we need to get the verification flags + // https://github.com/zeta-chain/node/issues/1717 + // return fmt.Errorf("failed to get verification flags: %w", err) + + verificationFlags = lightclienttypes.VerificationFlags{} } coreContext.Update( From bd13759ede05ec752b4d7900af546b3f83df5574 Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Mon, 29 Apr 2024 20:03:15 +0200 Subject: [PATCH 29/33] test(e2e): add rate limiter admin E2E test (#2063) * refactor and create Withdraw ZETA general function * new rate limiter test * use rate limiter for admin test * fix the test: single approval and add liquidity * make generate * fix liquidity * fix uniswap pool * change localnet chain params * fix lint * add cli query * add nil check * fix nil point * modify tests * eliminate nil pending nonce issue * fix query * set flags * Update e2e/runner/evm.go Co-authored-by: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> * add back other advanced tests * make generate * add comment * fix eth liquidity cap test * fix withdraw count --------- Co-authored-by: Charlie Chen Co-authored-by: Charlie Chen <34498985+ws4charlie@users.noreply.github.com> --- cmd/zetae2e/local/local.go | 1 + .../localnet/orchestrator/start-zetae2e.sh | 32 +-- .../zetacored/zetacored_query_crosschain.md | 1 + ...ain_list_pending_cctx_within_rate_limit.md | 33 +++ e2e/e2etests/e2etests.go | 7 + e2e/e2etests/test_eth_deposit.go | 4 +- e2e/e2etests/test_migrate_chain_support.go | 15 +- e2e/e2etests/test_rate_limiter.go | 203 ++++++++++++++++++ .../test_update_bytecode_connector.go | 35 ++- e2e/e2etests/test_zeta_withdraw.go | 71 +----- e2e/runner/evm.go | 3 +- e2e/runner/zeta.go | 74 +++++++ e2e/utils/evm.go | 2 +- x/crosschain/client/cli/query.go | 1 + .../client/cli/query_cctx_rate_limit.go | 35 +++ .../keeper/grpc_query_cctx_rate_limit.go | 8 +- x/observer/types/chain_params.go | 6 +- 17 files changed, 434 insertions(+), 97 deletions(-) create mode 100644 docs/cli/zetacored/zetacored_query_crosschain_list_pending_cctx_within_rate_limit.md create mode 100644 e2e/e2etests/test_rate_limiter.go create mode 100644 x/crosschain/client/cli/query_cctx_rate_limit.go diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index 62e0182ecf..c061f4479b 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -301,6 +301,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) { e2etests.TestUpdateBytecodeZRC20Name, e2etests.TestUpdateBytecodeConnectorName, e2etests.TestDepositEtherLiquidityCapName, + e2etests.TestRateLimiterName, // TestMigrateChainSupportName tests EVM chain migration. Currently this test doesn't work with Anvil because pre-EIP1559 txs are not supported // See issue below for details diff --git a/contrib/localnet/orchestrator/start-zetae2e.sh b/contrib/localnet/orchestrator/start-zetae2e.sh index a893c689ee..228ee297ff 100644 --- a/contrib/localnet/orchestrator/start-zetae2e.sh +++ b/contrib/localnet/orchestrator/start-zetae2e.sh @@ -14,36 +14,36 @@ sleep 2 ### Create the accounts and fund them with Ether on local Ethereum network # unlock the deployer account -echo "funding deployer address 0xE5C5367B8224807Ac2207d350E60e1b6F27a7ecC with 100 Ether" -geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0xE5C5367B8224807Ac2207d350E60e1b6F27a7ecC", value: web3.toWei(100,"ether")})' attach http://eth:8545 +echo "funding deployer address 0xE5C5367B8224807Ac2207d350E60e1b6F27a7ecC with 10000 Ether" +geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0xE5C5367B8224807Ac2207d350E60e1b6F27a7ecC", value: web3.toWei(10000,"ether")})' attach http://eth:8545 # unlock erc20 tester accounts -echo "funding deployer address 0x6F57D5E7c6DBb75e59F1524a3dE38Fc389ec5Fd6 with 100 Ether" -geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0x6F57D5E7c6DBb75e59F1524a3dE38Fc389ec5Fd6", value: web3.toWei(100,"ether")})' attach http://eth:8545 +echo "funding deployer address 0x6F57D5E7c6DBb75e59F1524a3dE38Fc389ec5Fd6 with 10000 Ether" +geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0x6F57D5E7c6DBb75e59F1524a3dE38Fc389ec5Fd6", value: web3.toWei(10000,"ether")})' attach http://eth:8545 # unlock zeta tester accounts -echo "funding deployer address 0x5cC2fBb200A929B372e3016F1925DcF988E081fd with 100 Ether" -geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0x5cC2fBb200A929B372e3016F1925DcF988E081fd", value: web3.toWei(100,"ether")})' attach http://eth:8545 +echo "funding deployer address 0x5cC2fBb200A929B372e3016F1925DcF988E081fd with 10000 Ether" +geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0x5cC2fBb200A929B372e3016F1925DcF988E081fd", value: web3.toWei(10000,"ether")})' attach http://eth:8545 # unlock bitcoin tester accounts -echo "funding deployer address 0x283d810090EdF4043E75247eAeBcE848806237fD with 100 Ether" -geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0x283d810090EdF4043E75247eAeBcE848806237fD", value: web3.toWei(100,"ether")})' attach http://eth:8545 +echo "funding deployer address 0x283d810090EdF4043E75247eAeBcE848806237fD with 10000 Ether" +geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0x283d810090EdF4043E75247eAeBcE848806237fD", value: web3.toWei(10000,"ether")})' attach http://eth:8545 # unlock ethers tester accounts -echo "funding deployer address 0x8D47Db7390AC4D3D449Cc20D799ce4748F97619A with 100 Ether" -geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0x8D47Db7390AC4D3D449Cc20D799ce4748F97619A", value: web3.toWei(100,"ether")})' attach http://eth:8545 +echo "funding deployer address 0x8D47Db7390AC4D3D449Cc20D799ce4748F97619A with 10000 Ether" +geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0x8D47Db7390AC4D3D449Cc20D799ce4748F97619A", value: web3.toWei(10000,"ether")})' attach http://eth:8545 # unlock miscellaneous tests accounts -echo "funding deployer address 0x90126d02E41c9eB2a10cfc43aAb3BD3460523Cdf with 100 Ether" -geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0x90126d02E41c9eB2a10cfc43aAb3BD3460523Cdf", value: web3.toWei(100,"ether")})' attach http://eth:8545 +echo "funding deployer address 0x90126d02E41c9eB2a10cfc43aAb3BD3460523Cdf with 10000 Ether" +geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0x90126d02E41c9eB2a10cfc43aAb3BD3460523Cdf", value: web3.toWei(10000,"ether")})' attach http://eth:8545 # unlock admin erc20 tests accounts -echo "funding deployer address 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 with 100 Ether" -geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", value: web3.toWei(100,"ether")})' attach http://eth:8545 +echo "funding deployer address 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 with 10000 Ether" +geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", value: web3.toWei(10000,"ether")})' attach http://eth:8545 # unlock the TSS account -echo "funding TSS address 0xF421292cb0d3c97b90EEEADfcD660B893592c6A2 with 100 Ether" -geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0xF421292cb0d3c97b90EEEADfcD660B893592c6A2", value: web3.toWei(100,"ether")})' attach http://eth:8545 +echo "funding TSS address 0xF421292cb0d3c97b90EEEADfcD660B893592c6A2 with 10000 Ether" +geth --exec 'eth.sendTransaction({from: eth.coinbase, to: "0xF421292cb0d3c97b90EEEADfcD660B893592c6A2", value: web3.toWei(10000,"ether")})' attach http://eth:8545 ### Run zetae2e command depending on the option passed diff --git a/docs/cli/zetacored/zetacored_query_crosschain.md b/docs/cli/zetacored/zetacored_query_crosschain.md index 48345c136d..467cce1f25 100644 --- a/docs/cli/zetacored/zetacored_query_crosschain.md +++ b/docs/cli/zetacored/zetacored_query_crosschain.md @@ -35,6 +35,7 @@ zetacored query crosschain [flags] * [zetacored query crosschain list-in-tx-tracker](zetacored_query_crosschain_list-in-tx-tracker.md) - shows a list of in tx tracker by chainId * [zetacored query crosschain list-out-tx-tracker](zetacored_query_crosschain_list-out-tx-tracker.md) - list all OutTxTracker * [zetacored query crosschain list-pending-cctx](zetacored_query_crosschain_list-pending-cctx.md) - shows pending CCTX +* [zetacored query crosschain list_pending_cctx_within_rate_limit](zetacored_query_crosschain_list_pending_cctx_within_rate_limit.md) - list all pending CCTX within rate limit * [zetacored query crosschain show-cctx](zetacored_query_crosschain_show-cctx.md) - shows a CCTX * [zetacored query crosschain show-gas-price](zetacored_query_crosschain_show-gas-price.md) - shows a gasPrice * [zetacored query crosschain show-in-tx-hash-to-cctx](zetacored_query_crosschain_show-in-tx-hash-to-cctx.md) - shows a inTxHashToCctx diff --git a/docs/cli/zetacored/zetacored_query_crosschain_list_pending_cctx_within_rate_limit.md b/docs/cli/zetacored/zetacored_query_crosschain_list_pending_cctx_within_rate_limit.md new file mode 100644 index 0000000000..aeb3fa12f1 --- /dev/null +++ b/docs/cli/zetacored/zetacored_query_crosschain_list_pending_cctx_within_rate_limit.md @@ -0,0 +1,33 @@ +# query crosschain list_pending_cctx_within_rate_limit + +list all pending CCTX within rate limit + +``` +zetacored query crosschain list_pending_cctx_within_rate_limit [flags] +``` + +### Options + +``` + --grpc-addr string the gRPC endpoint to use for this chain + --grpc-insecure allow gRPC over insecure channels, if not TLS the server must use TLS + --height int Use a specific height to query state at (this can error if the node is pruning state) + -h, --help help for list_pending_cctx_within_rate_limit + --node string [host]:[port] to Tendermint RPC interface for this chain + -o, --output string Output format (text|json) +``` + +### Options inherited from parent commands + +``` + --chain-id string The network chain ID + --home string directory for config and data + --log_format string The logging format (json|plain) + --log_level string The logging level (trace|debug|info|warn|error|fatal|panic) + --trace print out full stack trace on errors +``` + +### SEE ALSO + +* [zetacored query crosschain](zetacored_query_crosschain.md) - Querying commands for the crosschain module + diff --git a/e2e/e2etests/e2etests.go b/e2e/e2etests/e2etests.go index 583606ec50..e822d9c74a 100644 --- a/e2e/e2etests/e2etests.go +++ b/e2e/e2etests/e2etests.go @@ -59,6 +59,7 @@ const ( TestPauseZRC20Name = "pause_zrc20" TestUpdateBytecodeZRC20Name = "update_bytecode_zrc20" TestUpdateBytecodeConnectorName = "update_bytecode_connector" + TestRateLimiterName = "rate_limiter" ) // AllE2ETests is an ordered list of all e2e tests @@ -386,6 +387,12 @@ var AllE2ETests = []runner.E2ETest{ []runner.ArgDefinition{}, TestUpdateBytecodeConnector, ), + runner.NewE2ETest( + TestRateLimiterName, + "test sending cctxs with rate limiter enabled and show logs when processing cctxs", + []runner.ArgDefinition{}, + TestRateLimiter, + ), runner.NewE2ETest( TestMessagePassingZEVMToEVMName, "zevm -> evm message passing contract call", diff --git a/e2e/e2etests/test_eth_deposit.go b/e2e/e2etests/test_eth_deposit.go index 65a79f9c15..b4382b7740 100644 --- a/e2e/e2etests/test_eth_deposit.go +++ b/e2e/e2etests/test_eth_deposit.go @@ -268,8 +268,8 @@ func TestDepositEtherLiquidityCap(r *runner.E2ERunner, args []string) { } liquidityCap := math.NewUintFromBigInt(supply).Add(liquidityCapArg) - amountLessThanCap := liquidityCap.BigInt().Div(liquidityCap.BigInt(), big.NewInt(10)) // 1/10 of the cap - amountMoreThanCap := liquidityCap.BigInt().Mul(liquidityCap.BigInt(), big.NewInt(10)) // 10 times the cap + amountLessThanCap := liquidityCapArg.BigInt().Div(liquidityCapArg.BigInt(), big.NewInt(10)) // 1/10 of the cap + amountMoreThanCap := liquidityCapArg.BigInt().Mul(liquidityCapArg.BigInt(), big.NewInt(10)) // 10 times the cap msg := fungibletypes.NewMsgUpdateZRC20LiquidityCap( r.ZetaTxServer.GetAccountAddress(0), r.ETHZRC20Addr.Hex(), diff --git a/e2e/e2etests/test_migrate_chain_support.go b/e2e/e2etests/test_migrate_chain_support.go index 75bdb29d0e..0bbb754771 100644 --- a/e2e/e2etests/test_migrate_chain_support.go +++ b/e2e/e2etests/test_migrate_chain_support.go @@ -157,7 +157,20 @@ func TestMigrateChainSupport(r *runner.E2ERunner, _ []string) { newRunner.WaitForMinedCCTX(txEtherDeposit) // perform withdrawals on the new chain - TestZetaWithdraw(newRunner, []string{"10000000000000000000"}) + amount := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(10)) + newRunner.DepositAndApproveWZeta(amount) + tx := newRunner.WithdrawZeta(amount, true) + cctx := utils.WaitCctxMinedByInTxHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) + r.Logger.CCTX(*cctx, "zeta withdraw") + if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_OutboundMined { + panic(fmt.Errorf( + "expected cctx status to be %s; got %s, message %s", + crosschaintypes.CctxStatus_OutboundMined, + cctx.CctxStatus.Status.String(), + cctx.CctxStatus.StatusMessage, + )) + } + TestEtherWithdraw(newRunner, []string{"50000000000000000"}) // finally try to deposit Zeta back diff --git a/e2e/e2etests/test_rate_limiter.go b/e2e/e2etests/test_rate_limiter.go new file mode 100644 index 0000000000..e28c627574 --- /dev/null +++ b/e2e/e2etests/test_rate_limiter.go @@ -0,0 +1,203 @@ +package e2etests + +import ( + "context" + "fmt" + "math/big" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/zeta-chain/zetacore/e2e/runner" + "github.com/zeta-chain/zetacore/e2e/utils" + crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" + "golang.org/x/sync/errgroup" +) + +const RateLimiterWithdrawNumber = 5 + +// rateLimiterFlags are the rate limiter flags for the test +var rateLimiterFlags = crosschaintypes.RateLimiterFlags{ + Enabled: true, + Rate: sdk.NewUint(1e17).MulUint64(5), // this value is used so rate is reached + Window: 10, +} + +func TestRateLimiter(r *runner.E2ERunner, _ []string) { + r.Logger.Info("TestRateLimiter") + + // deposit and approve 50 WZETA for the tests + r.DepositAndApproveWZeta(big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(50))) + + // add liquidity in the pool to prevent high slippage in WZETA/gas pair + if err := addZetaGasLiquidity(r); err != nil { + panic(err) + } + + // Set the rate limiter to 0.5ZETA per 10 blocks + // These rate limiter flags will only allow to process 1 withdraw per 10 blocks + r.Logger.Info("setting up rate limiter flags") + if err := setupRateLimiterFlags(r, rateLimiterFlags); err != nil { + panic(err) + } + + // Test with rate limiter + // TODO: define proper assertion to check the rate limiter is working + // https://github.com/zeta-chain/node/issues/2090 + r.Logger.Print("rate limiter enabled") + if err := createAndWaitWithdraws(r); err != nil { + panic(err) + } + + // Disable rate limiter + r.Logger.Info("disabling rate limiter") + if err := setupRateLimiterFlags(r, crosschaintypes.RateLimiterFlags{Enabled: false}); err != nil { + panic(err) + } + + // Test without rate limiter again + r.Logger.Print("rate limiter disabled") + if err := createAndWaitWithdraws(r); err != nil { + panic(err) + } +} + +// setupRateLimiterFlags sets up the rate limiter flags with flags defined in the test +func setupRateLimiterFlags(r *runner.E2ERunner, flags crosschaintypes.RateLimiterFlags) error { + adminAddr, err := r.ZetaTxServer.GetAccountAddressFromName(utils.FungibleAdminName) + if err != nil { + return err + } + _, err = r.ZetaTxServer.BroadcastTx(utils.FungibleAdminName, crosschaintypes.NewMsgUpdateRateLimiterFlags( + adminAddr, + flags, + )) + if err != nil { + return err + } + + return nil +} + +// createAndWaitWithdraws performs RateLimiterWithdrawNumber withdraws +func createAndWaitWithdraws(r *runner.E2ERunner) error { + startTime := time.Now() + + r.Logger.Print("starting %d withdraws", RateLimiterWithdrawNumber) + + // Perform RateLimiterWithdrawNumber withdraws to log time for completion + txs := make([]*ethtypes.Transaction, RateLimiterWithdrawNumber) + for i := 0; i < RateLimiterWithdrawNumber; i++ { + amount := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(3)) + txs[i] = r.WithdrawZeta(amount, true) + } + + // start a error group to wait for all the withdraws to be mined + g, ctx := errgroup.WithContext(r.Ctx) + for i, tx := range txs { + // capture the loop variables + tx, i := tx, i + + // start a goroutine to wait for the withdraw to be mined + g.Go(func() error { + return waitForZetaWithdrawMined(ctx, r, tx, i, startTime) + }) + } + + // wait for all the withdraws to be mined + if err := g.Wait(); err != nil { + return err + } + + duration := time.Now().Sub(startTime).Seconds() + block, err := r.ZEVMClient.BlockNumber(r.Ctx) + if err != nil { + return fmt.Errorf("error getting block number: %w", err) + } + r.Logger.Print("all withdraws completed in %vs at block %d", duration, block) + + return nil +} + +// waitForZetaWithdrawMined waits for a zeta withdraw to be mined +// we first wait to get the receipt +// NOTE: this could be a more general function but we define it here for this test because we emit in the function logs specific to this test +func waitForZetaWithdrawMined(ctx context.Context, r *runner.E2ERunner, tx *ethtypes.Transaction, index int, startTime time.Time) error { + // wait for the cctx to be mined + cctx := utils.WaitCctxMinedByInTxHash(ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) + r.Logger.CCTX(*cctx, "zeta withdraw") + if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_OutboundMined { + return fmt.Errorf( + "expected cctx status to be %s; got %s, message %s", + crosschaintypes.CctxStatus_OutboundMined, + cctx.CctxStatus.Status.String(), + cctx.CctxStatus.StatusMessage, + ) + } + + // record the time for completion + duration := time.Now().Sub(startTime).Seconds() + block, err := r.ZEVMClient.BlockNumber(ctx) + if err != nil { + return err + } + r.Logger.Print("cctx %d mined in %vs at block %d", index, duration, block) + + return nil +} + +// addZetaGasLiquidity adds liquidity to the ZETA/gas pool +func addZetaGasLiquidity(r *runner.E2ERunner) error { + // use 10 ZETA and 10 ETH for the liquidity + // this will be sufficient for the tests + amount := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(10)) + approveAmount := big.NewInt(0).Mul(amount, big.NewInt(10)) + + // approve uniswap router to spend gas + txETHZRC20Approve, err := r.ETHZRC20.Approve(r.ZEVMAuth, r.UniswapV2RouterAddr, approveAmount) + if err != nil { + return fmt.Errorf("error approving ZETA: %w", err) + } + + // wait for the tx to be mined + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, txETHZRC20Approve, r.Logger, r.ReceiptTimeout) + if receipt.Status != 1 { + return fmt.Errorf("approve failed") + } + + // approve uniswap router to spend ZETA + txZETAApprove, err := r.WZeta.Approve(r.ZEVMAuth, r.UniswapV2RouterAddr, approveAmount) + if err != nil { + return fmt.Errorf("error approving ZETA: %w", err) + } + + // wait for the tx to be mined + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, txZETAApprove, r.Logger, r.ReceiptTimeout) + if receipt.Status != 1 { + return fmt.Errorf("approve failed") + } + + // add liquidity in the pool to prevent high slippage in WZETA/gas pair + r.ZEVMAuth.Value = amount + txAddLiquidity, err := r.UniswapV2Router.AddLiquidityETH( + r.ZEVMAuth, + r.ETHZRC20Addr, + amount, + big.NewInt(1e18), + big.NewInt(1e18), + r.DeployerAddress, + big.NewInt(time.Now().Add(10*time.Minute).Unix()), + ) + if err != nil { + return fmt.Errorf("error adding liquidity: %w", err) + } + r.ZEVMAuth.Value = big.NewInt(0) + + // wait for the tx to be mined + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, txAddLiquidity, r.Logger, r.ReceiptTimeout) + if receipt.Status != 1 { + return fmt.Errorf("add liquidity failed") + } + + return nil +} diff --git a/e2e/e2etests/test_update_bytecode_connector.go b/e2e/e2etests/test_update_bytecode_connector.go index 0770e80dc4..e961c1c074 100644 --- a/e2e/e2etests/test_update_bytecode_connector.go +++ b/e2e/e2etests/test_update_bytecode_connector.go @@ -1,17 +1,33 @@ package e2etests import ( + "fmt" + "math/big" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/zeta-chain/zetacore/e2e/contracts/testconnectorzevm" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" + crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" ) // TestUpdateBytecodeConnector tests updating the bytecode of a connector and interact with it func TestUpdateBytecodeConnector(r *runner.E2ERunner, _ []string) { - // Can withdraw 0.1ZETA - TestZetaWithdraw(r, []string{"10000000000000000000"}) + // Can withdraw 10ZETA + amount := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(10)) + r.DepositAndApproveWZeta(amount) + tx := r.WithdrawZeta(amount, true) + cctx := utils.WaitCctxMinedByInTxHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) + r.Logger.CCTX(*cctx, "zeta withdraw") + if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_OutboundMined { + panic(fmt.Errorf( + "expected cctx status to be %s; got %s, message %s", + crosschaintypes.CctxStatus_OutboundMined, + cctx.CctxStatus.Status.String(), + cctx.CctxStatus.StatusMessage, + )) + } // Deploy the test contract newTestConnectorAddr, tx, _, err := testconnectorzevm.DeployTestZetaConnectorZEVM( @@ -65,6 +81,17 @@ func TestUpdateBytecodeConnector(r *runner.E2ERunner, _ []string) { panic("unexpected response") } - // Can continue to interact with the connector: withdraw 0.1ZETA - TestZetaWithdraw(r, []string{"10000000000000000000"}) + // Can continue to interact with the connector: withdraw 10ZETA + r.DepositAndApproveWZeta(amount) + tx = r.WithdrawZeta(amount, true) + cctx = utils.WaitCctxMinedByInTxHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) + r.Logger.CCTX(*cctx, "zeta withdraw") + if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_OutboundMined { + panic(fmt.Errorf( + "expected cctx status to be %s; got %s, message %s", + crosschaintypes.CctxStatus_OutboundMined, + cctx.CctxStatus.Status.String(), + cctx.CctxStatus.StatusMessage, + )) + } } diff --git a/e2e/e2etests/test_zeta_withdraw.go b/e2e/e2etests/test_zeta_withdraw.go index 6dfc664813..a51da4c6f5 100644 --- a/e2e/e2etests/test_zeta_withdraw.go +++ b/e2e/e2etests/test_zeta_withdraw.go @@ -5,12 +5,11 @@ import ( "math/big" - ethcommon "github.com/ethereum/go-ethereum/common" connectorzevm "github.com/zeta-chain/protocol-contracts/pkg/contracts/zevm/zetaconnectorzevm.sol" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" "github.com/zeta-chain/zetacore/pkg/chains" - cctxtypes "github.com/zeta-chain/zetacore/x/crosschain/types" + crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" ) func TestZetaWithdraw(r *runner.E2ERunner, args []string) { @@ -20,76 +19,18 @@ func TestZetaWithdraw(r *runner.E2ERunner, args []string) { amount, ok := big.NewInt(0).SetString(args[0], 10) if !ok { - panic("Invalid amount specified for TestZetaWithdraw.") + panic("invalid amount specified") } - r.ZEVMAuth.Value = amount - tx, err := r.WZeta.Deposit(r.ZEVMAuth) - if err != nil { - panic(err) - } - r.ZEVMAuth.Value = big.NewInt(0) - r.Logger.Info("wzeta deposit tx hash: %s", tx.Hash().Hex()) - - receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - r.Logger.EVMReceipt(*receipt, "wzeta deposit") - if receipt.Status == 0 { - panic("deposit failed") - } - - chainID, err := r.EVMClient.ChainID(r.Ctx) - if err != nil { - panic(err) - } - - tx, err = r.WZeta.Approve(r.ZEVMAuth, r.ConnectorZEVMAddr, amount) - if err != nil { - panic(err) - } - r.Logger.Info("wzeta approve tx hash: %s", tx.Hash().Hex()) - - receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - r.Logger.EVMReceipt(*receipt, "wzeta approve") - if receipt.Status == 0 { - panic(fmt.Sprintf("approve failed, logs: %+v", receipt.Logs)) - } - - tx, err = r.ConnectorZEVM.Send(r.ZEVMAuth, connectorzevm.ZetaInterfacesSendInput{ - DestinationChainId: chainID, - DestinationAddress: r.DeployerAddress.Bytes(), - DestinationGasLimit: big.NewInt(400_000), - Message: nil, - ZetaValueAndGas: amount, - ZetaParams: nil, - }) - if err != nil { - panic(err) - } - r.Logger.Info("send tx hash: %s", tx.Hash().Hex()) - receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - r.Logger.EVMReceipt(*receipt, "send") - if receipt.Status == 0 { - panic(fmt.Sprintf("send failed, logs: %+v", receipt.Logs)) - } - - r.Logger.Info(" Logs:") - for _, log := range receipt.Logs { - sentLog, err := r.ConnectorZEVM.ParseZetaSent(*log) - if err == nil { - r.Logger.Info(" Dest Addr: %s", ethcommon.BytesToAddress(sentLog.DestinationAddress).Hex()) - r.Logger.Info(" Dest Chain: %d", sentLog.DestinationChainId) - r.Logger.Info(" Dest Gas: %d", sentLog.DestinationGasLimit) - r.Logger.Info(" Zeta Value: %d", sentLog.ZetaValueAndGas) - } - } - r.Logger.Info("waiting for cctx status to change to final...") + r.DepositAndApproveWZeta(amount) + tx := r.WithdrawZeta(amount, true) cctx := utils.WaitCctxMinedByInTxHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) r.Logger.CCTX(*cctx, "zeta withdraw") - if cctx.CctxStatus.Status != cctxtypes.CctxStatus_OutboundMined { + if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_OutboundMined { panic(fmt.Errorf( "expected cctx status to be %s; got %s, message %s", - cctxtypes.CctxStatus_OutboundMined, + crosschaintypes.CctxStatus_OutboundMined, cctx.CctxStatus.Status.String(), cctx.CctxStatus.StatusMessage, )) diff --git a/e2e/runner/evm.go b/e2e/runner/evm.go index 0bc6d77070..e878de97e7 100644 --- a/e2e/runner/evm.go +++ b/e2e/runner/evm.go @@ -127,7 +127,8 @@ func (runner *E2ERunner) DepositERC20WithAmountAndMessage(to ethcommon.Address, // DepositEther sends Ethers into ZEVM func (runner *E2ERunner) DepositEther(testHeader bool) ethcommon.Hash { - return runner.DepositEtherWithAmount(testHeader, big.NewInt(1000000000000000000)) // in wei (1 eth) + amount := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(100)) // 100 eth + return runner.DepositEtherWithAmount(testHeader, amount) } // DepositEtherWithAmount sends Ethers into ZEVM diff --git a/e2e/runner/zeta.go b/e2e/runner/zeta.go index d7fdbdcdf4..58a4513923 100644 --- a/e2e/runner/zeta.go +++ b/e2e/runner/zeta.go @@ -7,6 +7,7 @@ import ( ethcommon "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" zetaconnectoreth "github.com/zeta-chain/protocol-contracts/pkg/contracts/evm/zetaconnector.eth.sol" + connectorzevm "github.com/zeta-chain/protocol-contracts/pkg/contracts/zevm/zetaconnectorzevm.sol" "github.com/zeta-chain/zetacore/e2e/utils" "github.com/zeta-chain/zetacore/x/crosschain/types" ) @@ -138,3 +139,76 @@ func (runner *E2ERunner) DepositZetaWithAmount(to ethcommon.Address, amount *big return tx.Hash() } + +// DepositAndApproveWZeta deposits and approves WZETA on ZetaChain from the ZETA smart contract on ZEVM +func (runner *E2ERunner) DepositAndApproveWZeta(amount *big.Int) { + runner.ZEVMAuth.Value = amount + tx, err := runner.WZeta.Deposit(runner.ZEVMAuth) + if err != nil { + panic(err) + } + runner.ZEVMAuth.Value = big.NewInt(0) + runner.Logger.Info("wzeta deposit tx hash: %s", tx.Hash().Hex()) + + receipt := utils.MustWaitForTxReceipt(runner.Ctx, runner.ZEVMClient, tx, runner.Logger, runner.ReceiptTimeout) + runner.Logger.EVMReceipt(*receipt, "wzeta deposit") + if receipt.Status == 0 { + panic("deposit failed") + } + + tx, err = runner.WZeta.Approve(runner.ZEVMAuth, runner.ConnectorZEVMAddr, amount) + if err != nil { + panic(err) + } + runner.Logger.Info("wzeta approve tx hash: %s", tx.Hash().Hex()) + + receipt = utils.MustWaitForTxReceipt(runner.Ctx, runner.ZEVMClient, tx, runner.Logger, runner.ReceiptTimeout) + runner.Logger.EVMReceipt(*receipt, "wzeta approve") + if receipt.Status == 0 { + panic(fmt.Sprintf("approve failed, logs: %+v", receipt.Logs)) + } +} + +// WithdrawZeta withdraws ZETA from ZetaChain to the ZETA smart contract on EVM +// waitReceipt specifies whether to wait for the tx receipt and check if the tx was successful +func (runner *E2ERunner) WithdrawZeta(amount *big.Int, waitReceipt bool) *ethtypes.Transaction { + chainID, err := runner.EVMClient.ChainID(runner.Ctx) + if err != nil { + panic(err) + } + + tx, err := runner.ConnectorZEVM.Send(runner.ZEVMAuth, connectorzevm.ZetaInterfacesSendInput{ + DestinationChainId: chainID, + DestinationAddress: runner.DeployerAddress.Bytes(), + DestinationGasLimit: big.NewInt(400_000), + Message: nil, + ZetaValueAndGas: amount, + ZetaParams: nil, + }) + if err != nil { + panic(err) + } + runner.Logger.Info("send tx hash: %s", tx.Hash().Hex()) + + if waitReceipt { + receipt := utils.MustWaitForTxReceipt(runner.Ctx, runner.ZEVMClient, tx, runner.Logger, runner.ReceiptTimeout) + runner.Logger.EVMReceipt(*receipt, "send") + if receipt.Status == 0 { + panic(fmt.Sprintf("send failed, logs: %+v", receipt.Logs)) + + } + + runner.Logger.Info(" Logs:") + for _, log := range receipt.Logs { + sentLog, err := runner.ConnectorZEVM.ParseZetaSent(*log) + if err == nil { + runner.Logger.Info(" Dest Addr: %s", ethcommon.BytesToAddress(sentLog.DestinationAddress).Hex()) + runner.Logger.Info(" Dest Chain: %d", sentLog.DestinationChainId) + runner.Logger.Info(" Dest Gas: %d", sentLog.DestinationGasLimit) + runner.Logger.Info(" Zeta Value: %d", sentLog.ZetaValueAndGas) + } + } + } + + return tx +} diff --git a/e2e/utils/evm.go b/e2e/utils/evm.go index d3f34f818c..fc6792d617 100644 --- a/e2e/utils/evm.go +++ b/e2e/utils/evm.go @@ -55,7 +55,7 @@ func MustWaitForTxReceipt( receipt, err := client.TransactionReceipt(ctx, tx.Hash()) if err != nil { if !errors.Is(err, ethereum.NotFound) && i%10 == 0 { - logger.Info("fetching tx receipt error: ", err.Error()) + logger.Info("fetching tx %s receipt error: %s ", tx.Hash().Hex(), err.Error()) } time.Sleep(1 * time.Second) continue diff --git a/x/crosschain/client/cli/query.go b/x/crosschain/client/cli/query.go index 9f9ae29752..22085bfb68 100644 --- a/x/crosschain/client/cli/query.go +++ b/x/crosschain/client/cli/query.go @@ -36,6 +36,7 @@ func GetQueryCmd(_ string) *cobra.Command { CmdListInTxTrackerByChain(), CmdListInTxTrackers(), CmdGetZetaAccounting(), + CmdListPendingCCTXWithinRateLimit(), CmdShowUpdateRateLimiterFlags(), ) diff --git a/x/crosschain/client/cli/query_cctx_rate_limit.go b/x/crosschain/client/cli/query_cctx_rate_limit.go new file mode 100644 index 0000000000..251a3897de --- /dev/null +++ b/x/crosschain/client/cli/query_cctx_rate_limit.go @@ -0,0 +1,35 @@ +package cli + +import ( + "context" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/spf13/cobra" + "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +func CmdListPendingCCTXWithinRateLimit() *cobra.Command { + cmd := &cobra.Command{ + Use: "list_pending_cctx_within_rate_limit", + Short: "list all pending CCTX within rate limit", + RunE: func(cmd *cobra.Command, _ []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) + + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.ListPendingCctxWithinRateLimit( + context.Background(), &types.QueryListPendingCctxWithinRateLimitRequest{}, + ) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go index 57ce375048..176a3dcee4 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go @@ -17,7 +17,7 @@ import ( // ListPendingCctxWithinRateLimit returns a list of pending cctxs that do not exceed the outbound rate limit // a limit for the number of cctxs to return can be specified or the default is MaxPendingCctxs -func (k Keeper) ListPendingCctxWithinRateLimit(c context.Context, req *types.QueryListPendingCctxWithinRateLimitRequest) (*types.QueryListPendingCctxWithinRateLimitResponse, error) { +func (k Keeper) ListPendingCctxWithinRateLimit(c context.Context, req *types.QueryListPendingCctxWithinRateLimitRequest) (res *types.QueryListPendingCctxWithinRateLimitResponse, err error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } @@ -108,16 +108,16 @@ func (k Keeper) ListPendingCctxWithinRateLimit(c context.Context, req *types.Que // query pending nonces for each foreign chain and get the lowest height of the pending cctxs // Note: The pending nonces could change during the RPC call, so query them beforehand lowestPendingCctxHeight := int64(0) - pendingNoncesMap := make(map[int64]*observertypes.PendingNonces) + pendingNoncesMap := make(map[int64]observertypes.PendingNonces) for _, chain := range chains { pendingNonces, found := k.GetObserverKeeper().GetPendingNonces(ctx, tss.TssPubkey, chain.ChainId) if !found { return nil, status.Error(codes.Internal, "pending nonces not found") } + pendingNoncesMap[chain.ChainId] = pendingNonces // insert pending nonces and update lowest height if pendingNonces.NonceLow < pendingNonces.NonceHigh { - pendingNoncesMap[chain.ChainId] = &pendingNonces cctx, err := getCctxByChainIDAndNonce(k, ctx, tss.TssPubkey, chain.ChainId, pendingNonces.NonceLow) if err != nil { return nil, err @@ -191,12 +191,12 @@ func (k Keeper) ListPendingCctxWithinRateLimit(c context.Context, req *types.Que // query forwards for pending cctxs for each foreign chain for _, chain := range chains { - // query the pending cctxs in range [NonceLow, NonceHigh) pendingNonces := pendingNoncesMap[chain.ChainId] // #nosec G701 always in range totalPending += uint64(pendingNonces.NonceHigh - pendingNonces.NonceLow) + // query the pending cctxs in range [NonceLow, NonceHigh) for nonce := pendingNonces.NonceLow; nonce < pendingNonces.NonceHigh; nonce++ { cctx, err := getCctxByChainIDAndNonce(k, ctx, tss.TssPubkey, chain.ChainId, nonce) if err != nil { diff --git a/x/observer/types/chain_params.go b/x/observer/types/chain_params.go index e32ee9e597..5664decc51 100644 --- a/x/observer/types/chain_params.go +++ b/x/observer/types/chain_params.go @@ -291,11 +291,11 @@ func GetDefaultGoerliLocalnetChainParams() *ChainParams { ConnectorContractAddress: "0xD28D6A0b8189305551a0A8bd247a6ECa9CE781Ca", Erc20CustodyContractAddress: "0xff3135df4F2775f4091b81f4c7B6359CfA07862a", InTxTicker: 2, - OutTxTicker: 2, + OutTxTicker: 1, WatchUtxoTicker: 0, GasPriceTicker: 5, - OutboundTxScheduleInterval: 2, - OutboundTxScheduleLookahead: 5, + OutboundTxScheduleInterval: 1, + OutboundTxScheduleLookahead: 50, BallotThreshold: DefaultBallotThreshold, MinObserverDelegation: DefaultMinObserverDelegation, IsSupported: false, From 4be83fb075a8f2b72a2a53f9a0bfcdf63e2855d7 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Mon, 29 Apr 2024 13:07:28 -0500 Subject: [PATCH 30/33] removed incorrect Note --- x/crosschain/keeper/grpc_query_cctx_rate_limit.go | 1 - 1 file changed, 1 deletion(-) diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go index 176a3dcee4..fb5779fa5d 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go @@ -106,7 +106,6 @@ func (k Keeper) ListPendingCctxWithinRateLimit(c context.Context, req *types.Que } // query pending nonces for each foreign chain and get the lowest height of the pending cctxs - // Note: The pending nonces could change during the RPC call, so query them beforehand lowestPendingCctxHeight := int64(0) pendingNoncesMap := make(map[int64]observertypes.PendingNonces) for _, chain := range chains { From 23b7930f7326bd2cd2d91279b297939225803f55 Mon Sep 17 00:00:00 2001 From: Charlie Chen Date: Mon, 29 Apr 2024 14:39:16 -0500 Subject: [PATCH 31/33] improved variable name --- x/crosschain/keeper/grpc_query_cctx_rate_limit.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go index fb5779fa5d..b1aa54c46a 100644 --- a/x/crosschain/keeper/grpc_query_cctx_rate_limit.go +++ b/x/crosschain/keeper/grpc_query_cctx_rate_limit.go @@ -306,9 +306,9 @@ func rateLimitExceeded( erc20CoinRates map[int64]map[string]sdk.Dec, foreignCoinMap map[int64]map[string]fungibletypes.ForeignCoins, currentCctxValue *sdkmath.Int, - withdrawLimitInZeta sdkmath.Int, + withdrawLimitInAzeta sdkmath.Int, ) bool { cctxValueAzeta := ConvertCctxValue(chainID, cctx, gasCoinRates, erc20CoinRates, foreignCoinMap) *currentCctxValue = currentCctxValue.Add(cctxValueAzeta) - return currentCctxValue.GT(withdrawLimitInZeta) + return currentCctxValue.GT(withdrawLimitInAzeta) } From 7136f31070b533aa7b8802c2fd74683179ece429 Mon Sep 17 00:00:00 2001 From: lumtis Date: Tue, 30 Apr 2024 18:31:54 +0200 Subject: [PATCH 32/33] add E2E test for rate limiter gas and erc20 --- cmd/zetae2e/local/local.go | 2 +- e2e/e2etests/test_erc20_withdraw.go | 22 +--- e2e/e2etests/test_eth_withdraw.go | 15 +-- e2e/e2etests/test_rate_limiter.go | 160 +++++++++++++++++++++------- e2e/runner/zeta.go | 46 ++++++++ 5 files changed, 172 insertions(+), 73 deletions(-) diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index c983194d8f..3103810305 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -308,11 +308,11 @@ func localE2ETest(cmd *cobra.Command, _ []string) { } if testAdmin { eg.Go(adminTestRoutine(conf, deployerRunner, verbose, + e2etests.TestRateLimiterName, e2etests.TestPauseZRC20Name, e2etests.TestUpdateBytecodeZRC20Name, e2etests.TestUpdateBytecodeConnectorName, e2etests.TestDepositEtherLiquidityCapName, - e2etests.TestRateLimiterName, // TestMigrateChainSupportName tests EVM chain migration. Currently this test doesn't work with Anvil because pre-EIP1559 txs are not supported // See issue below for details diff --git a/e2e/e2etests/test_erc20_withdraw.go b/e2e/e2etests/test_erc20_withdraw.go index 26959c0eac..0d9e99c7c5 100644 --- a/e2e/e2etests/test_erc20_withdraw.go +++ b/e2e/e2etests/test_erc20_withdraw.go @@ -36,28 +36,10 @@ func TestERC20Withdraw(r *runner.E2ERunner, args []string) { r.Logger.Info("eth zrc20 approve receipt: status %d", receipt.Status) // withdraw - tx, err = r.ERC20ZRC20.Withdraw(r.ZEVMAuth, r.DeployerAddress.Bytes(), withdrawalAmount) - if err != nil { - panic(err) - } - receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - r.Logger.Info("Receipt txhash %s status %d", receipt.TxHash, receipt.Status) - for _, log := range receipt.Logs { - event, err := r.ERC20ZRC20.ParseWithdrawal(*log) - if err != nil { - continue - } - r.Logger.Info( - " logs: from %s, to %x, value %d, gasfee %d", - event.From.Hex(), - event.To, - event.Value, - event.Gasfee, - ) - } + tx = r.WithdrawERC20(withdrawalAmount) // verify the withdraw value - cctx := utils.WaitCctxMinedByInTxHash(r.Ctx, receipt.TxHash.Hex(), r.CctxClient, r.Logger, r.CctxTimeout) + cctx := utils.WaitCctxMinedByInTxHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) verifyTransferAmountFromCCTX(r, cctx, withdrawalAmount.Int64()) } diff --git a/e2e/e2etests/test_eth_withdraw.go b/e2e/e2etests/test_eth_withdraw.go index e9a4211461..998567419f 100644 --- a/e2e/e2etests/test_eth_withdraw.go +++ b/e2e/e2etests/test_eth_withdraw.go @@ -42,21 +42,10 @@ func TestEtherWithdraw(r *runner.E2ERunner, args []string) { r.Logger.EVMReceipt(*receipt, "approve") // withdraw - tx, err = r.ETHZRC20.Withdraw(r.ZEVMAuth, r.DeployerAddress.Bytes(), withdrawalAmount) - if err != nil { - panic(err) - } - r.Logger.EVMTransaction(*tx, "withdraw") - - receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) - if receipt.Status == 0 { - panic("withdraw failed") - } - r.Logger.EVMReceipt(*receipt, "withdraw") - r.Logger.ZRC20Withdrawal(r.ETHZRC20, *receipt, "withdraw") + tx = r.WithdrawEther(withdrawalAmount) // verify the withdraw value - cctx := utils.WaitCctxMinedByInTxHash(r.Ctx, receipt.TxHash.Hex(), r.CctxClient, r.Logger, r.CctxTimeout) + cctx := utils.WaitCctxMinedByInTxHash(r.Ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) r.Logger.CCTX(*cctx, "withdraw") if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_OutboundMined { panic("cctx status is not outbound mined") diff --git a/e2e/e2etests/test_rate_limiter.go b/e2e/e2etests/test_rate_limiter.go index e28c627574..4c4055f2b8 100644 --- a/e2e/e2etests/test_rate_limiter.go +++ b/e2e/e2etests/test_rate_limiter.go @@ -14,20 +14,50 @@ import ( "golang.org/x/sync/errgroup" ) -const RateLimiterWithdrawNumber = 5 +// WithdrawType is the type of withdraw to perform in the test +type withdrawType string -// rateLimiterFlags are the rate limiter flags for the test -var rateLimiterFlags = crosschaintypes.RateLimiterFlags{ - Enabled: true, - Rate: sdk.NewUint(1e17).MulUint64(5), // this value is used so rate is reached - Window: 10, -} +const ( + withdrawTypeZETA withdrawType = "ZETA" + withdrawTypeETH withdrawType = "ETH" + withdrawTypeERC20 withdrawType = "ERC20" + + rateLimiterWithdrawNumber = 5 +) func TestRateLimiter(r *runner.E2ERunner, _ []string) { r.Logger.Info("TestRateLimiter") - // deposit and approve 50 WZETA for the tests - r.DepositAndApproveWZeta(big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(50))) + // rateLimiterFlags are the rate limiter flags for the test + rateLimiterFlags := crosschaintypes.RateLimiterFlags{ + Enabled: true, + Rate: sdk.NewUint(1e17).MulUint64(5), // 0.5 ZETA this value is used so rate is reached + Window: 10, + Conversions: []crosschaintypes.Conversion{ + { + Zrc20: r.ETHZRC20Addr.Hex(), + Rate: sdk.NewDec(2), // 1 ETH = 2 ZETA + }, + { + Zrc20: r.ERC20ZRC20Addr.Hex(), + Rate: sdk.NewDec(1).QuoInt64(2), // 2 USDC = 1 ZETA + }, + }, + } + + // these are the amounts for the withdraws for the different types + // currently these are arbitrary values that can be fine-tuned for manual testing of rate limiter + // the current values are defined such as: ZETA takes more time than usual, ETH takes a bit less time and ERC20 are processed immediately + // TODO: define more rigorous assertions with proper values + // https://github.com/zeta-chain/node/issues/2090 + zetaAmount := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(3)) + ethAmount := big.NewInt(1e18) + erc20Amount := big.NewInt(1e6) + + // approve tokens for the tests + if err := approveTokens(r); err != nil { + panic(err) + } // add liquidity in the pool to prevent high slippage in WZETA/gas pair if err := addZetaGasLiquidity(r); err != nil { @@ -45,7 +75,13 @@ func TestRateLimiter(r *runner.E2ERunner, _ []string) { // TODO: define proper assertion to check the rate limiter is working // https://github.com/zeta-chain/node/issues/2090 r.Logger.Print("rate limiter enabled") - if err := createAndWaitWithdraws(r); err != nil { + if err := createAndWaitWithdraws(r, withdrawTypeZETA, zetaAmount); err != nil { + panic(err) + } + if err := createAndWaitWithdraws(r, withdrawTypeETH, ethAmount); err != nil { + panic(err) + } + if err := createAndWaitWithdraws(r, withdrawTypeERC20, erc20Amount); err != nil { panic(err) } @@ -55,41 +91,34 @@ func TestRateLimiter(r *runner.E2ERunner, _ []string) { panic(err) } - // Test without rate limiter again + // Test without rate limiter again and try again ZETA withdraws r.Logger.Print("rate limiter disabled") - if err := createAndWaitWithdraws(r); err != nil { + if err := createAndWaitWithdraws(r, withdrawTypeZETA, zetaAmount); err != nil { panic(err) } } -// setupRateLimiterFlags sets up the rate limiter flags with flags defined in the test -func setupRateLimiterFlags(r *runner.E2ERunner, flags crosschaintypes.RateLimiterFlags) error { - adminAddr, err := r.ZetaTxServer.GetAccountAddressFromName(utils.FungibleAdminName) - if err != nil { - return err - } - _, err = r.ZetaTxServer.BroadcastTx(utils.FungibleAdminName, crosschaintypes.NewMsgUpdateRateLimiterFlags( - adminAddr, - flags, - )) - if err != nil { - return err - } - - return nil -} - // createAndWaitWithdraws performs RateLimiterWithdrawNumber withdraws -func createAndWaitWithdraws(r *runner.E2ERunner) error { +func createAndWaitWithdraws(r *runner.E2ERunner, withdrawType withdrawType, withdrawAmount *big.Int) error { startTime := time.Now() - r.Logger.Print("starting %d withdraws", RateLimiterWithdrawNumber) + r.Logger.Print("starting %d %s withdraws", rateLimiterWithdrawNumber, withdrawType) // Perform RateLimiterWithdrawNumber withdraws to log time for completion - txs := make([]*ethtypes.Transaction, RateLimiterWithdrawNumber) - for i := 0; i < RateLimiterWithdrawNumber; i++ { - amount := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(3)) - txs[i] = r.WithdrawZeta(amount, true) + txs := make([]*ethtypes.Transaction, rateLimiterWithdrawNumber) + for i := 0; i < rateLimiterWithdrawNumber; i++ { + + // create a new withdraw depending on the type + switch withdrawType { + case withdrawTypeZETA: + txs[i] = r.WithdrawZeta(withdrawAmount, true) + case withdrawTypeETH: + txs[i] = r.WithdrawEther(withdrawAmount) + case withdrawTypeERC20: + txs[i] = r.WithdrawERC20(withdrawAmount) + default: + return fmt.Errorf("invalid withdraw type: %s", withdrawType) + } } // start a error group to wait for all the withdraws to be mined @@ -100,7 +129,7 @@ func createAndWaitWithdraws(r *runner.E2ERunner) error { // start a goroutine to wait for the withdraw to be mined g.Go(func() error { - return waitForZetaWithdrawMined(ctx, r, tx, i, startTime) + return waitForWithdrawMined(ctx, r, tx, i, startTime) }) } @@ -119,13 +148,13 @@ func createAndWaitWithdraws(r *runner.E2ERunner) error { return nil } -// waitForZetaWithdrawMined waits for a zeta withdraw to be mined +// waitForWithdrawMined waits for a withdraw to be mined // we first wait to get the receipt // NOTE: this could be a more general function but we define it here for this test because we emit in the function logs specific to this test -func waitForZetaWithdrawMined(ctx context.Context, r *runner.E2ERunner, tx *ethtypes.Transaction, index int, startTime time.Time) error { +func waitForWithdrawMined(ctx context.Context, r *runner.E2ERunner, tx *ethtypes.Transaction, index int, startTime time.Time) error { // wait for the cctx to be mined cctx := utils.WaitCctxMinedByInTxHash(ctx, tx.Hash().Hex(), r.CctxClient, r.Logger, r.CctxTimeout) - r.Logger.CCTX(*cctx, "zeta withdraw") + r.Logger.CCTX(*cctx, "withdraw") if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_OutboundMined { return fmt.Errorf( "expected cctx status to be %s; got %s, message %s", @@ -146,6 +175,23 @@ func waitForZetaWithdrawMined(ctx context.Context, r *runner.E2ERunner, tx *etht return nil } +// setupRateLimiterFlags sets up the rate limiter flags with flags defined in the test +func setupRateLimiterFlags(r *runner.E2ERunner, flags crosschaintypes.RateLimiterFlags) error { + adminAddr, err := r.ZetaTxServer.GetAccountAddressFromName(utils.FungibleAdminName) + if err != nil { + return err + } + _, err = r.ZetaTxServer.BroadcastTx(utils.FungibleAdminName, crosschaintypes.NewMsgUpdateRateLimiterFlags( + adminAddr, + flags, + )) + if err != nil { + return err + } + + return nil +} + // addZetaGasLiquidity adds liquidity to the ZETA/gas pool func addZetaGasLiquidity(r *runner.E2ERunner) error { // use 10 ZETA and 10 ETH for the liquidity @@ -201,3 +247,39 @@ func addZetaGasLiquidity(r *runner.E2ERunner) error { return nil } + +// approveTokens approves the tokens for the tests +func approveTokens(r *runner.E2ERunner) error { + // deposit and approve 50 WZETA for the tests + approveAmount := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(50)) + r.DepositAndApproveWZeta(approveAmount) + + // approve ETH for withdraws + tx, err := r.ETHZRC20.Approve(r.ZEVMAuth, r.ETHZRC20Addr, approveAmount) + if err != nil { + return fmt.Errorf("error approving ETH: %w", err) + } + r.Logger.EVMTransaction(*tx, "approve") + + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + if receipt.Status == 0 { + return fmt.Errorf("eth approve failed") + } + r.Logger.EVMReceipt(*receipt, "approve") + + // approve ETH for ERC20 withdraws (this is for the gas fees) + tx, err = r.ETHZRC20.Approve(r.ZEVMAuth, r.ERC20ZRC20Addr, approveAmount) + if err != nil { + return fmt.Errorf("error approving ERC20: %w", err) + } + + r.Logger.EVMTransaction(*tx, "approve") + + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + if receipt.Status == 0 { + return fmt.Errorf("erc 20 approve failed") + } + r.Logger.EVMReceipt(*receipt, "approve") + + return nil +} diff --git a/e2e/runner/zeta.go b/e2e/runner/zeta.go index 58a4513923..20c31ff043 100644 --- a/e2e/runner/zeta.go +++ b/e2e/runner/zeta.go @@ -212,3 +212,49 @@ func (runner *E2ERunner) WithdrawZeta(amount *big.Int, waitReceipt bool) *ethtyp return tx } + +// WithdrawEther withdraws Ether from ZetaChain to the ZETA smart contract on EVM +func (runner *E2ERunner) WithdrawEther(amount *big.Int) *ethtypes.Transaction { + // withdraw + tx, err := runner.ETHZRC20.Withdraw(runner.ZEVMAuth, runner.DeployerAddress.Bytes(), amount) + if err != nil { + panic(err) + } + runner.Logger.EVMTransaction(*tx, "withdraw") + + receipt := utils.MustWaitForTxReceipt(runner.Ctx, runner.ZEVMClient, tx, runner.Logger, runner.ReceiptTimeout) + if receipt.Status == 0 { + panic("withdraw failed") + } + runner.Logger.EVMReceipt(*receipt, "withdraw") + runner.Logger.ZRC20Withdrawal(runner.ETHZRC20, *receipt, "withdraw") + + return tx +} + +// WithdrawERC20 withdraws an ERC20 token from ZetaChain to the ZETA smart contract on EVM +func (runner *E2ERunner) WithdrawERC20(amount *big.Int) *ethtypes.Transaction { + tx, err := runner.ERC20ZRC20.Withdraw(runner.ZEVMAuth, runner.DeployerAddress.Bytes(), amount) + if err != nil { + panic(err) + } + runner.Logger.EVMTransaction(*tx, "withdraw") + + receipt := utils.MustWaitForTxReceipt(runner.Ctx, runner.ZEVMClient, tx, runner.Logger, runner.ReceiptTimeout) + runner.Logger.Info("Receipt txhash %s status %d", receipt.TxHash, receipt.Status) + for _, log := range receipt.Logs { + event, err := runner.ERC20ZRC20.ParseWithdrawal(*log) + if err != nil { + continue + } + runner.Logger.Info( + " logs: from %s, to %x, value %d, gasfee %d", + event.From.Hex(), + event.To, + event.Value, + event.Gasfee, + ) + } + + return tx +} From fd861d5cbe9b66fde5a020c3c0133550775234bc Mon Sep 17 00:00:00 2001 From: lumtis Date: Tue, 30 Apr 2024 19:07:05 +0200 Subject: [PATCH 33/33] remove outdated comment --- e2e/e2etests/test_rate_limiter.go | 1 - 1 file changed, 1 deletion(-) diff --git a/e2e/e2etests/test_rate_limiter.go b/e2e/e2etests/test_rate_limiter.go index 4c4055f2b8..f40c4d6b9f 100644 --- a/e2e/e2etests/test_rate_limiter.go +++ b/e2e/e2etests/test_rate_limiter.go @@ -47,7 +47,6 @@ func TestRateLimiter(r *runner.E2ERunner, _ []string) { // these are the amounts for the withdraws for the different types // currently these are arbitrary values that can be fine-tuned for manual testing of rate limiter - // the current values are defined such as: ZETA takes more time than usual, ETH takes a bit less time and ERC20 are processed immediately // TODO: define more rigorous assertions with proper values // https://github.com/zeta-chain/node/issues/2090 zetaAmount := big.NewInt(0).Mul(big.NewInt(1e18), big.NewInt(3))