Skip to content

Commit

Permalink
refactor: move rate limiter to zetaclient and add metrics (#2110)
Browse files Browse the repository at this point in the history
* initial commit of grpc pending cctx query with rate limiter

* replace big.Float with sdk.Dec and update mock rate limiter flags

* split big loop into backwards loop and forwards loop to be more accurate

* adjust zetaclient code to query pending cctx with rate limit

* update change log and add one more rate limiter flag test

* use outboun amount for calculation

* some minimum code refactor

* created separate file for cctx query with rate limit

* improved a few error handlling

* use old cctx query as fallback when rate limiter is disabled; some renaming

* fixed unit test compile

* added unit test for fallback query

* added unit tests for cctx value conversion

* add changelog entry

* added unit tests for query pending cctxs within rate limit

* added total value in rate limiter window for monitoring purpose

* Update x/crosschain/keeper/grpc_query_cctx_rate_limit.go

Co-authored-by: Lucas Bertrand <[email protected]>

* change variable name fCoin to foreignCoin

* Update x/fungible/keeper/foreign_coins.go

Co-authored-by: Lucas Bertrand <[email protected]>

* Update x/crosschain/keeper/grpc_query_cctx_rate_limit_test.go

Co-authored-by: Lucas Bertrand <[email protected]>

* converted rate limiter query unit tests to table test

* handle edge case when pending cctxs span wider block range than sliding window

* added zero rate check; added comment to make unit test clearer

* added unit test and note for method GetAllForeignCoinMap

* treat Rate as average block rate; stop outbound when current rate limit exceeds Rate; updated metrics

* refactor: allow zeta deposits to new zevm address (#2076)

* allow zevm coin deposit to unknow addresses

* add e2e tests

* add changelog

* add comments

* add commented unit tests back

* replace sdk.Dec with sdkmath.Int to represent cctx value in azeta

* 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 <[email protected]>

* add back other advanced tests

* make generate

* add comment

* fix eth liquidity cap test

* fix withdraw count

---------

Co-authored-by: Charlie Chen <[email protected]>
Co-authored-by: Charlie Chen <[email protected]>

* removed incorrect Note

* initiated rate limiter refactor and added metrics

* added more unit tests and updated changelog

* print more details from rate limiter output

* reorder observer methods declaration

* fix unit test

* moved state irrelevant methods to types; renaming and cleaning

* code indentation and update variable

* replace  with

* fix unit test

* added extra unit tests and improved func name

---------

Co-authored-by: Lucas Bertrand <[email protected]>
Co-authored-by: Tanmay <[email protected]>
  • Loading branch information
3 people authored May 7, 2024
1 parent b460556 commit 7c98376
Show file tree
Hide file tree
Showing 31 changed files with 3,359 additions and 620 deletions.
4 changes: 1 addition & 3 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@
### Refactor

* [2094](https://github.com/zeta-chain/node/pull/2094) - upgrade go-tss to use cosmos v0.47

### Refactor

* [2110](https://github.com/zeta-chain/node/pull/2110) - move non-query rate limiter logic to zetaclient side and code refactor.
* [2032](https://github.com/zeta-chain/node/pull/2032) - improve some general structure of the ZetaClient codebase
* [2071](https://github.com/zeta-chain/node/pull/2071) - Modify chains struct to add all chain related information
* [2124](https://github.com/zeta-chain/node/pull/2124) - removed unused variables and method
Expand Down
52 changes: 52 additions & 0 deletions docs/openapi/openapi.swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29015,6 +29015,32 @@ paths:
$ref: '#/definitions/googlerpcStatus'
tags:
- Query
/zeta-chain/crosschain/rateLimiterInput:
get:
summary: Queries the input data of rate limiter.
operationId: Query_RateLimiterInput
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/crosschainQueryRateLimiterInputResponse'
default:
description: An unexpected error response.
schema:
$ref: '#/definitions/googlerpcStatus'
parameters:
- name: limit
in: query
required: false
type: integer
format: int64
- name: window
in: query
required: false
type: string
format: int64
tags:
- Query
/zeta-chain/crosschain/zetaAccounting:
get:
operationId: Query_ZetaAccounting
Expand Down Expand Up @@ -56829,6 +56855,32 @@ definitions:
properties:
rateLimiterFlags:
$ref: '#/definitions/crosschainRateLimiterFlags'
crosschainQueryRateLimiterInputResponse:
type: object
properties:
height:
type: string
format: int64
cctxs_missed:
type: array
items:
type: object
$ref: '#/definitions/crosschainCrossChainTx'
cctxs_pending:
type: array
items:
type: object
$ref: '#/definitions/crosschainCrossChainTx'
total_pending:
type: string
format: uint64
past_cctxs_value:
type: string
pending_cctxs_value:
type: string
lowest_pending_cctx_height:
type: string
format: int64
crosschainQueryZetaAccountingResponse:
type: object
properties:
Expand Down
28 changes: 28 additions & 0 deletions pkg/math/float.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package math

import (
"math/big"
)

// Percentage calculates the percentage of A over B.
func Percentage(a, b *big.Int) *big.Float {
// cannot calculate if either a or b is nil
if a == nil || b == nil {
return nil
}

// if a is zero, return nil to avoid division by zero
if b.Cmp(big.NewInt(0)) == 0 {
return nil
}

// convert a and b to big.Float
floatA := new(big.Float).SetInt(a)
floatB := new(big.Float).SetInt(b)

// calculate the percentage of a over b
percentage := new(big.Float).Quo(floatA, floatB)
percentage.Mul(percentage, big.NewFloat(100))

return percentage
}
68 changes: 68 additions & 0 deletions pkg/math/float_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package math

import (
"fmt"
"math/big"
"testing"

"github.com/stretchr/testify/require"
)

func TestPercentage(t *testing.T) {
testCases := []struct {
name string
numerator *big.Int
denominator *big.Int
percentage *big.Float
fail bool
}{
{
name: "positive percentage",
numerator: big.NewInt(165),
denominator: big.NewInt(1000),
percentage: big.NewFloat(16.5),
fail: false,
},
{
name: "negative percentage",
numerator: big.NewInt(-165),
denominator: big.NewInt(1000),
percentage: big.NewFloat(-16.5),
fail: false,
},
{
name: "zero denominator",
numerator: big.NewInt(1),
denominator: big.NewInt(0),
percentage: nil,
fail: true,
},
{
name: "nil numerator",
numerator: nil,
denominator: big.NewInt(1000),
percentage: nil,
fail: true,
},
{
name: "nil denominator",
numerator: big.NewInt(165),
denominator: nil,
percentage: nil,
fail: true,
},
}

for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
percentage := Percentage(tc.numerator, tc.denominator)
fmt.Printf("percentage: %v\n", percentage)
if tc.fail {
require.Nil(t, percentage)
} else {
require.True(t, percentage.Cmp(tc.percentage) == 0)
}
})
}
}
21 changes: 21 additions & 0 deletions proto/zetachain/zetacore/crosschain/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ service Query {
returns (QueryRateLimiterFlagsResponse) {
option (google.api.http).get = "/zeta-chain/crosschain/rateLimiterFlags";
}

// Queries the input data of rate limiter.
rpc RateLimiterInput(QueryRateLimiterInputRequest)
returns (QueryRateLimiterInputResponse) {
option (google.api.http).get = "/zeta-chain/crosschain/rateLimiterInput";
}
}

message QueryZetaAccountingRequest {}
Expand Down Expand Up @@ -270,6 +276,21 @@ message QueryListPendingCctxResponse {
uint64 totalPending = 2;
}

message QueryRateLimiterInputRequest {
uint32 limit = 1;
int64 window = 2;
}

message QueryRateLimiterInputResponse {
int64 height = 1;
repeated CrossChainTx cctxs_missed = 2;
repeated CrossChainTx cctxs_pending = 3;
uint64 total_pending = 4;
string past_cctxs_value = 5;
string pending_cctxs_value = 6;
int64 lowest_pending_cctx_height = 7;
}

message QueryListPendingCctxWithinRateLimitRequest { uint32 limit = 1; }

message QueryListPendingCctxWithinRateLimitResponse {
Expand Down
12 changes: 12 additions & 0 deletions proto/zetachain/zetacore/crosschain/rate_limiter_flags.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ syntax = "proto3";
package zetachain.zetacore.crosschain;

import "gogoproto/gogo.proto";
import "zetachain/zetacore/pkg/coin/coin.proto";

option go_package = "github.com/zeta-chain/zetacore/x/crosschain/types";

Expand All @@ -28,3 +29,14 @@ message Conversion {
(gogoproto.nullable) = false
];
}

message AssetRate {
int64 chainId = 1;
string asset = 2;
uint32 decimals = 3;
pkg.coin.CoinType coin_type = 4;
string rate = 5 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}
62 changes: 62 additions & 0 deletions testutil/sample/crosschain.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package sample
import (
"encoding/base64"
"encoding/json"
"fmt"
"math/rand"
"strings"
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -49,6 +51,39 @@ func RateLimiterFlags() types.RateLimiterFlags {
}
}

// CustomRateLimiterFlags creates a custom rate limiter flags with the given parameters
func CustomRateLimiterFlags(enabled bool, window int64, rate math.Uint, conversions []types.Conversion) types.RateLimiterFlags {
return types.RateLimiterFlags{
Enabled: enabled,
Window: window,
Rate: rate,
Conversions: conversions,
}
}

func AssetRate() types.AssetRate {
r := Rand()

return types.AssetRate{
ChainId: r.Int63(),
Asset: EthAddress().Hex(),
Decimals: uint32(r.Uint64()),
CoinType: coin.CoinType_ERC20,
Rate: sdk.NewDec(r.Int63()),
}
}

// CustomAssetRate creates a custom asset rate with the given parameters
func CustomAssetRate(chainID int64, asset string, decimals uint32, coinType coin.CoinType, rate sdk.Dec) types.AssetRate {
return types.AssetRate{
ChainId: chainID,
Asset: strings.ToLower(asset),
Decimals: decimals,
CoinType: coinType,
Rate: rate,
}
}

func OutTxTracker(t *testing.T, index string) types.OutTxTracker {
r := newRandFromStringSeed(t, index)

Expand Down Expand Up @@ -173,6 +208,33 @@ func CrossChainTx(t *testing.T, index string) *types.CrossChainTx {
}
}

// CustomCctxsInBlockRange create 1 cctx per block in block range [lowBlock, highBlock] (inclusive)
func CustomCctxsInBlockRange(
t *testing.T,
lowBlock uint64,
highBlock uint64,
chainID int64,
coinType coin.CoinType,
asset string,
amount uint64,
status types.CctxStatus,
) (cctxs []*types.CrossChainTx) {
// create 1 cctx per block
for i := lowBlock; i <= highBlock; i++ {
nonce := i - 1
cctx := CrossChainTx(t, fmt.Sprintf("%d-%d", chainID, nonce))
cctx.CctxStatus.Status = status
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
cctxs = append(cctxs, cctx)
}
return cctxs
}

func LastBlockHeight(t *testing.T, index string) *types.LastBlockHeight {
r := newRandFromStringSeed(t, index)

Expand Down
Loading

0 comments on commit 7c98376

Please sign in to comment.