From 606c1b525bc44165d359cd6e42fd5226b5459e78 Mon Sep 17 00:00:00 2001 From: oren-lava Date: Mon, 27 Nov 2023 15:18:33 +0200 Subject: [PATCH 01/85] CNS-715: implement create validator better by making bonded val --- testutil/common/tester.go | 30 +++++++++++++++++-- .../keeper/msg_server_detection_test.go | 3 +- x/pairing/keeper/helpers_test.go | 3 +- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/testutil/common/tester.go b/testutil/common/tester.go index 20aba16cae..4f8ed885ea 100644 --- a/testutil/common/tester.go +++ b/testutil/common/tester.go @@ -557,8 +557,9 @@ func (ts *Tester) TxPairingUnfreezeProvider(addr, chainID string) (*pairingtypes return ts.Servers.PairingServer.UnfreezeProvider(ts.GoCtx, msg) } -// TxCreateValidator: implement 'tx staking createvalidator' -func (ts *Tester) TxCreateValidator(validator sigs.Account, amount math.Int) (*stakingtypes.MsgCreateValidatorResponse, error) { +// TxCreateValidator: implement 'tx staking createvalidator' and bond its tokens +func (ts *Tester) TxCreateValidator(validator sigs.Account, amount math.Int) { + // create a validator msg, err := stakingtypes.NewMsgCreateValidator( sdk.ValAddress(validator.Addr), validator.PubKey, @@ -568,7 +569,30 @@ func (ts *Tester) TxCreateValidator(validator sigs.Account, amount math.Int) (*s sdk.ZeroInt(), ) require.Nil(ts.T, err) - return ts.Servers.StakingServer.CreateValidator(ts.GoCtx, msg) + _, err = ts.Servers.StakingServer.CreateValidator(ts.GoCtx, msg) + require.Nil(ts.T, err) + + // move validator's coins from unbonded pool to bonded + val, found := ts.Keepers.StakingKeeper.GetValidator(ts.Ctx, sdk.ValAddress(validator.Addr)) + require.True(ts.T, found) + valTokens := sdk.NewCoins(sdk.NewCoin(epochstoragetypes.TokenDenom, amount)) + err = ts.Keepers.BankKeeper.SendCoinsFromModuleToModule(ts.Ctx, stakingtypes.NotBondedPoolName, stakingtypes.BondedPoolName, valTokens) + require.Nil(ts.T, err) + + // before changing the validaor's state, run the BeforeValidatorModified hook manually + err = ts.Keepers.StakingKeeper.Hooks().BeforeValidatorModified(ts.Ctx, val.GetOperator()) + require.Nil(ts.T, err) + + // update the validator status to "bonded" and apply + val = val.UpdateStatus(stakingtypes.Bonded) + ts.Keepers.StakingKeeper.SetValidator(ts.Ctx, val) + ts.Keepers.StakingKeeper.SetValidatorByPowerIndex(ts.Ctx, val) + + // run the AfterValidatorBonded hook manually + consAddr, err := val.GetConsAddr() + require.Nil(ts.T, err) + err = ts.Keepers.StakingKeeper.Hooks().AfterValidatorBonded(ts.Ctx, consAddr, val.GetOperator()) + require.Nil(ts.T, err) } // TxDelegateValidator: implement 'tx staking delegate' diff --git a/x/conflict/keeper/msg_server_detection_test.go b/x/conflict/keeper/msg_server_detection_test.go index 056992c964..10a1e8ef12 100644 --- a/x/conflict/keeper/msg_server_detection_test.go +++ b/x/conflict/keeper/msg_server_detection_test.go @@ -30,8 +30,7 @@ type tester struct { func newTester(t *testing.T) *tester { ts := &tester{Tester: *common.NewTester(t)} val, _ := ts.AddAccount(common.VALIDATOR, 0, 1000000) - _, err := ts.TxCreateValidator(val, math.NewIntFromUint64(uint64(10000))) - require.Nil(t, err) + ts.TxCreateValidator(val, math.NewIntFromUint64(uint64(10000))) ts.AddPlan("free", common.CreateMockPlan()) ts.AddSpec("mock", common.CreateMockSpec()) diff --git a/x/pairing/keeper/helpers_test.go b/x/pairing/keeper/helpers_test.go index c719f0c2db..08d15d444e 100644 --- a/x/pairing/keeper/helpers_test.go +++ b/x/pairing/keeper/helpers_test.go @@ -53,8 +53,7 @@ func (ts *tester) addValidators(count int) { start := len(ts.Accounts(common.VALIDATOR)) for i := 0; i < count; i++ { acc, _ := ts.AddAccount(common.VALIDATOR, start+i, testBalance) - _, err := ts.TxCreateValidator(acc, math.NewInt(testBalance)) - require.Nil(ts.T, err) + ts.TxCreateValidator(acc, math.NewInt(testBalance)) } } From 6348f2dd3467709dc5396962a1f17f61269b4a0d Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Mon, 27 Nov 2023 19:11:52 +0200 Subject: [PATCH 02/85] Change all use of epochstorage.denom - replace with StakingKeeper.BondDenom func - STILL BROKEN - FOR YAROM --- app/app.go | 3 +++ protocol/chainlib/common_test_utils.go | 3 +-- protocol/statetracker/tx_sender.go | 10 ++++---- testutil/common/common.go | 4 ++-- testutil/common/consts/token.go | 4 ++++ testutil/common/mock.go | 6 ++--- testutil/common/tester.go | 24 +++++++++---------- testutil/e2e/paymentE2E.go | 4 +++- testutil/e2e/protocolE2E.go | 3 +++ testutil/e2e/sdkE2E.go | 2 ++ testutil/keeper/conflict.go | 1 + testutil/keeper/dualstaking.go | 2 +- testutil/keeper/epochstorage.go | 1 + testutil/keeper/keepers_init.go | 9 +++---- testutil/keeper/pairing.go | 2 +- testutil/keeper/plan.go | 2 +- testutil/keeper/projects.go | 2 +- testutil/keeper/subscription.go | 4 +++- x/conflict/keeper/keeper.go | 23 +++++++++++++----- x/conflict/keeper/vote.go | 9 ++++--- x/conflict/types/expected_keepers.go | 4 ++++ x/dualstaking/keeper/delegate.go | 2 +- x/dualstaking/keeper/delegator_reward.go | 12 +++++----- .../grpc_query_delegator_providers_test.go | 23 +++++++++--------- .../grpc_query_provider_delegators_test.go | 23 +++++++++--------- x/dualstaking/keeper/hooks.go | 9 ++++--- x/dualstaking/keeper/hooks_test.go | 13 +++++----- x/dualstaking/keeper/migrations.go | 9 ++++--- x/dualstaking/types/delegate.go | 5 ++-- x/epochstorage/keeper/keeper.go | 19 ++++++++++----- x/epochstorage/keeper/migrations.go | 5 ++-- x/epochstorage/types/expected_keepers.go | 4 ++++ x/epochstorage/types/types.go | 2 -- x/pairing/client/cli/tx_modify_provider.go | 6 +++++ x/pairing/client/cli/tx_stake_provider.go | 11 +++++++++ x/pairing/keeper/delegator_rewards_test.go | 21 ++++++++-------- x/pairing/keeper/discipline.go | 3 +-- x/pairing/keeper/msg_server_stake_provider.go | 6 +++++ .../keeper/msg_server_stake_provider_test.go | 2 +- x/pairing/keeper/pairing_test.go | 10 ++++---- x/pairing/keeper/staking.go | 4 ++-- x/pairing/keeper/unstaking.go | 3 +-- x/pairing/types/expected_keepers.go | 1 + x/pairing/types/message_stake_provider.go | 4 ---- x/plans/keeper/plan_test.go | 4 ++-- x/plans/types/plan.go | 8 ++++--- x/projects/keeper/project_test.go | 7 +++--- x/spec/keeper/keeper.go | 2 ++ x/spec/keeper/spec.go | 6 +++++ x/spec/keeper/spec_test.go | 4 ++-- x/spec/types/expected_keepers.go | 4 ++++ x/spec/types/spec.go | 5 ++-- x/subscription/keeper/keeper.go | 3 +++ x/subscription/keeper/subscription.go | 3 +-- x/subscription/keeper/subscription_test.go | 4 ++-- x/subscription/types/expected_keepers.go | 4 ++++ 56 files changed, 221 insertions(+), 152 deletions(-) create mode 100644 testutil/common/consts/token.go diff --git a/app/app.go b/app/app.go index e001875a00..3576a6010a 100644 --- a/app/app.go +++ b/app/app.go @@ -424,6 +424,7 @@ func New( app.BankKeeper, app.AccountKeeper, app.SpecKeeper, + app.StakingKeeper, ) epochstorageModule := epochstoragemodule.NewAppModule(appCodec, app.EpochstorageKeeper, app.AccountKeeper, app.BankKeeper) @@ -484,6 +485,7 @@ func New( app.DualstakingKeeper, app.FixationStoreKeeper, app.TimerStoreKeeper, + app.StakingKeeper, ) subscriptionModule := subscriptionmodule.NewAppModule(appCodec, app.SubscriptionKeeper, app.AccountKeeper, app.BankKeeper) @@ -569,6 +571,7 @@ func New( app.PairingKeeper, app.EpochstorageKeeper, app.SpecKeeper, + app.StakingKeeper, ) conflictModule := conflictmodule.NewAppModule(appCodec, app.ConflictKeeper, app.AccountKeeper, app.BankKeeper) diff --git a/protocol/chainlib/common_test_utils.go b/protocol/chainlib/common_test_utils.go index 14d7320cc9..bc48e73523 100644 --- a/protocol/chainlib/common_test_utils.go +++ b/protocol/chainlib/common_test_utils.go @@ -22,7 +22,6 @@ import ( "github.com/lavanet/lava/protocol/lavasession" testcommon "github.com/lavanet/lava/testutil/common" keepertest "github.com/lavanet/lava/testutil/keeper" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" plantypes "github.com/lavanet/lava/x/plans/types" spectypes "github.com/lavanet/lava/x/spec/types" "github.com/stretchr/testify/require" @@ -179,7 +178,7 @@ func SetupForTests(t *testing.T, numOfProviders int, specID string, getToTopMost msg, err := stakingtypes.NewMsgCreateValidator( sdk.ValAddress(ts.Validator.Addr), ts.Validator.PubKey, - sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewIntFromUint64(uint64(balance))), + sdk.NewCoin(ts.Keepers.StakingKeeper.BondDenom(sdk.UnwrapSDKContext(ts.Ctx)), sdk.NewIntFromUint64(uint64(balance))), stakingtypes.Description{}, stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1)), sdk.ZeroInt(), diff --git a/protocol/statetracker/tx_sender.go b/protocol/statetracker/tx_sender.go index 1fd9a82373..ecb66c1aa8 100644 --- a/protocol/statetracker/tx_sender.go +++ b/protocol/statetracker/tx_sender.go @@ -18,12 +18,12 @@ import ( "github.com/lavanet/lava/protocol/rpcprovider/reliabilitymanager" "github.com/lavanet/lava/utils" conflicttypes "github.com/lavanet/lava/x/conflict/types" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" pairingtypes "github.com/lavanet/lava/x/pairing/types" ) const ( - defaultGasPrice = "0.000000001" + epochstoragetypes.TokenDenom + tokenDenom = "ulava" + defaultGasPrice = "0.000000001" + tokenDenom defaultGasAdjustment = 3 // same account can continue failing the more providers you have under the same account // for example if you have a provider staked at 20 chains you will ask for 20 payments per epoch. @@ -45,7 +45,7 @@ func NewTxSender(ctx context.Context, clientCtx client.Context, txFactory tx.Fac func (ts *TxSender) checkProfitability(simResult *typestx.SimulateResponse, gasUsed uint64, txFactory tx.Factory) error { txEvents := simResult.GetResult().Events - lavaReward := sdk.NewCoin("ulava", sdk.NewInt(0)) + lavaReward := sdk.NewCoin(tokenDenom, sdk.NewInt(0)) for _, txEvent := range txEvents { if txEvent.Type == utils.EventPrefix+pairingtypes.RelayPaymentEventName { for _, attribute := range txEvent.Attributes { @@ -313,7 +313,7 @@ func (pts *ProviderTxSender) SendVoteCommitment(voteID string, vote *reliability func parseInsufficientFeesError(msg string, gasUsed uint64) error { feesPart := strings.Split(msg, "insufficient fees; got: ")[1] - prices := strings.Split(feesPart, epochstoragetypes.TokenDenom) + prices := strings.Split(feesPart, tokenDenom) var required int var err error for _, p := range prices { @@ -331,7 +331,7 @@ func parseInsufficientFeesError(msg string, gasUsed uint64) error { minimumGasPricesGot := (float64(gasUsed) / float64(required)) utils.LavaFormatError("Bad Lava Node Configuration detected, Gas fees inconsistencies can be related to the app.toml configuration of the lava node you are using under 'minimum-gas-prices', Please remove the field or set it to the required amount or change rpc to a different lava node", nil, utils.Attribute{Key: "Required Minimum Gas Prices", Value: defaultGasPrice}, - utils.Attribute{Key: "Current (estimated) Minimum Gas Prices", Value: strconv.FormatFloat(minimumGasPricesGot, 'f', -1, 64) + epochstoragetypes.TokenDenom}, + utils.Attribute{Key: "Current (estimated) Minimum Gas Prices", Value: strconv.FormatFloat(minimumGasPricesGot, 'f', -1, 64) + tokenDenom}, ) return nil diff --git a/testutil/common/common.go b/testutil/common/common.go index bce039d79e..b3b7c6a381 100644 --- a/testutil/common/common.go +++ b/testutil/common/common.go @@ -19,7 +19,7 @@ import ( func CreateNewAccount(ctx context.Context, keepers testkeeper.Keepers, balance int64) (acc sigs.Account) { acc = sigs.GenerateDeterministicFloatingKey(testkeeper.Randomizer) testkeeper.Randomizer.Inc() - coins := sdk.NewCoins(sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(balance))) + coins := sdk.NewCoins(sdk.NewCoin(keepers.StakingKeeper.BondDenom(sdk.UnwrapSDKContext(ctx)), sdk.NewInt(balance))) keepers.BankKeeper.SetBalance(sdk.UnwrapSDKContext(ctx), acc.Addr, coins) return } @@ -29,7 +29,7 @@ func StakeAccount(t *testing.T, ctx context.Context, keepers testkeeper.Keepers, for _, collection := range spec.ApiCollections { endpoints = append(endpoints, epochstoragetypes.Endpoint{IPPORT: "123", ApiInterfaces: []string{collection.CollectionData.ApiInterface}, Geolocation: 1}) } - _, err := servers.PairingServer.StakeProvider(ctx, &types.MsgStakeProvider{Creator: acc.Addr.String(), ChainID: spec.Index, Amount: sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(stake)), Geolocation: 1, Endpoints: endpoints, Moniker: "prov", DelegateLimit: sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.ZeroInt()), DelegateCommission: 100, Validator: sdk.ValAddress(validator.Addr).String()}) + _, err := servers.PairingServer.StakeProvider(ctx, &types.MsgStakeProvider{Creator: acc.Addr.String(), ChainID: spec.Index, Amount: sdk.NewCoin(keepers.StakingKeeper.BondDenom(sdk.UnwrapSDKContext(ctx)), sdk.NewInt(stake)), Geolocation: 1, Endpoints: endpoints, Moniker: "prov", DelegateLimit: sdk.NewCoin(keepers.StakingKeeper.BondDenom(sdk.UnwrapSDKContext(ctx)), sdk.ZeroInt()), DelegateCommission: 100, Validator: sdk.ValAddress(validator.Addr).String()}) require.Nil(t, err) } diff --git a/testutil/common/consts/token.go b/testutil/common/consts/token.go new file mode 100644 index 0000000000..be1d1dbf60 --- /dev/null +++ b/testutil/common/consts/token.go @@ -0,0 +1,4 @@ +package consts + +// This for tests. Use StakingKeeper.BondDenom() for production. +const TestTokenDenom = "ulava" diff --git a/testutil/common/mock.go b/testutil/common/mock.go index d11be7f727..6185137c5b 100644 --- a/testutil/common/mock.go +++ b/testutil/common/mock.go @@ -2,7 +2,7 @@ package common import ( sdk "github.com/cosmos/cosmos-sdk/types" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" + commonconsts "github.com/lavanet/lava/testutil/common/consts" plantypes "github.com/lavanet/lava/x/plans/types" spectypes "github.com/lavanet/lava/x/spec/types" ) @@ -16,7 +16,7 @@ func CreateMockSpec() spectypes.Spec { spec.ReliabilityThreshold = 4294967295 spec.BlockDistanceForFinalizedData = 0 spec.DataReliabilityEnabled = true - spec.MinStakeProvider = sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(1000)) + spec.MinStakeProvider = sdk.NewCoin(commonconsts.TestTokenDenom, sdk.NewInt(1000)) spec.ApiCollections = []*spectypes.ApiCollection{{Enabled: true, CollectionData: spectypes.CollectionData{ApiInterface: "stub", Type: "GET"}, Apis: []*spectypes.Api{{Name: specName + "API", ComputeUnits: 100, Enabled: true}}}} spec.BlockDistanceForFinalizedData = 0 return spec @@ -28,7 +28,7 @@ func CreateMockPlan() plantypes.Plan { Description: "plan for testing", Type: "rpc", Block: 100, - Price: sdk.NewCoin("ulava", sdk.NewInt(100)), + Price: sdk.NewCoin(commonconsts.TestTokenDenom, sdk.NewInt(100)), AllowOveruse: true, OveruseRate: 10, AnnualDiscountPercentage: 20, diff --git a/testutil/common/tester.go b/testutil/common/tester.go index 20aba16cae..0a2cf3ca6d 100644 --- a/testutil/common/tester.go +++ b/testutil/common/tester.go @@ -171,7 +171,7 @@ func (ts *Tester) StakeProviderExtra( } } - stake := sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(amount)) + stake := sdk.NewCoin(ts.Keepers.StakingKeeper.BondDenom(ts.Ctx), sdk.NewInt(amount)) _, err := ts.TxPairingStakeProvider(addr, spec.Name, stake, endpoints, geoloc, moniker) return err @@ -217,7 +217,7 @@ func (ts *Tester) Policy(name string) planstypes.Policy { } func (ts *Tester) TokenDenom() string { - return epochstoragetypes.TokenDenom + return ts.Keepers.StakingKeeper.BondDenom(ts.Ctx) } func (ts *Tester) AddProjectData(name string, pd projectstypes.ProjectData) *Tester { @@ -249,18 +249,18 @@ func (ts *Tester) Spec(name string) spectypes.Spec { // misc shortcuts -func NewCoin(amount int64) sdk.Coin { - return sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(amount)) +func NewCoin(tokenDenom string, amount int64) sdk.Coin { + return sdk.NewCoin(tokenDenom, sdk.NewInt(amount)) } -func NewCoins(amount ...int64) []sdk.Coin { - return slices.Map(amount, NewCoin) +func NewCoins(tokenDenom string, amount ...int64) []sdk.Coin { + return slices.Map(amount, func(a int64) sdk.Coin { return NewCoin(tokenDenom, a) }) } // keeper helpers func (ts *Tester) GetBalance(accAddr sdk.AccAddress) int64 { - denom := epochstoragetypes.TokenDenom + denom := ts.Keepers.StakingKeeper.BondDenom(ts.Ctx) return ts.Keepers.BankKeeper.GetBalance(ts.Ctx, accAddr, denom).Amount.Int64() } @@ -510,7 +510,7 @@ func (ts *Tester) TxPairingStakeProvider( Geolocation: geoloc, Endpoints: endpoints, Moniker: moniker, - DelegateLimit: sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.ZeroInt()), + DelegateLimit: sdk.NewCoin(ts.Keepers.StakingKeeper.BondDenom(ts.Ctx), sdk.ZeroInt()), DelegateCommission: 100, } return ts.Servers.PairingServer.StakeProvider(ts.GoCtx, msg) @@ -562,7 +562,7 @@ func (ts *Tester) TxCreateValidator(validator sigs.Account, amount math.Int) (*s msg, err := stakingtypes.NewMsgCreateValidator( sdk.ValAddress(validator.Addr), validator.PubKey, - sdk.NewCoin(epochstoragetypes.TokenDenom, amount), + sdk.NewCoin(ts.Keepers.StakingKeeper.BondDenom(ts.Ctx), amount), stakingtypes.Description{}, stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1)), sdk.ZeroInt(), @@ -576,7 +576,7 @@ func (ts *Tester) TxDelegateValidator(delegator, validator sigs.Account, amount msg := stakingtypes.NewMsgDelegate( delegator.Addr, sdk.ValAddress(validator.Addr), - sdk.NewCoin(epochstoragetypes.TokenDenom, amount), + sdk.NewCoin(ts.Keepers.StakingKeeper.BondDenom(ts.Ctx), amount), ) return ts.Servers.StakingServer.Delegate(ts.GoCtx, msg) } @@ -587,7 +587,7 @@ func (ts *Tester) TxReDelegateValidator(delegator, fromValidator, toValidator si delegator.Addr, sdk.ValAddress(fromValidator.Addr), sdk.ValAddress(toValidator.Addr), - sdk.NewCoin(epochstoragetypes.TokenDenom, amount), + sdk.NewCoin(ts.Keepers.StakingKeeper.BondDenom(ts.Ctx), amount), ) return ts.Servers.StakingServer.BeginRedelegate(ts.GoCtx, msg) } @@ -597,7 +597,7 @@ func (ts *Tester) TxUnbondValidator(delegator, validator sigs.Account, amount ma msg := stakingtypes.NewMsgUndelegate( delegator.Addr, sdk.ValAddress(validator.Addr), - sdk.NewCoin(epochstoragetypes.TokenDenom, amount), + sdk.NewCoin(ts.Keepers.StakingKeeper.BondDenom(ts.Ctx), amount), ) return ts.Servers.StakingServer.Undelegate(ts.GoCtx, msg) } diff --git a/testutil/e2e/paymentE2E.go b/testutil/e2e/paymentE2E.go index 06b3eee13a..14b36581b5 100644 --- a/testutil/e2e/paymentE2E.go +++ b/testutil/e2e/paymentE2E.go @@ -13,6 +13,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" bankTypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/lavanet/lava/cmd/lavad/cmd" + commonconsts "github.com/lavanet/lava/testutil/common/consts" "github.com/lavanet/lava/utils" epochStorageTypes "github.com/lavanet/lava/x/epochstorage/types" pairingTypes "github.com/lavanet/lava/x/pairing/types" @@ -108,7 +109,7 @@ func (lt *lavaTest) getBalances(addresses []string) ([]sdk.Coin, error) { return nil, fmt.Errorf("could not get balance of address %s. err: %s", addr, err.Error()) } - balanceRequest := bankTypes.NewQueryBalanceRequest(sdkAddr, epochStorageTypes.TokenDenom) + balanceRequest := bankTypes.NewQueryBalanceRequest(sdkAddr, lt.tokenDenom) res, err := bankQueryClient.Balance(context.Background(), balanceRequest) if err != nil { return nil, fmt.Errorf("could not get balance of address %s. err: %s", sdkAddr.String(), err.Error()) @@ -198,6 +199,7 @@ func runPaymentE2E(timeout time.Duration) { commands: make(map[string]*exec.Cmd), providerType: make(map[string][]epochStorageTypes.Endpoint), logPath: protocolLogsFolder, + tokenDenom: commonconsts.TestTokenDenom, } // use defer to save logs in case the tests fail defer func() { diff --git a/testutil/e2e/protocolE2E.go b/testutil/e2e/protocolE2E.go index b852408a6b..8a3704bac9 100644 --- a/testutil/e2e/protocolE2E.go +++ b/testutil/e2e/protocolE2E.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" + commonconsts "github.com/lavanet/lava/testutil/common/consts" "github.com/lavanet/lava/utils" epochStorageTypes "github.com/lavanet/lava/x/epochstorage/types" pairingTypes "github.com/lavanet/lava/x/pairing/types" @@ -65,6 +66,7 @@ type lavaTest struct { providerType map[string][]epochStorageTypes.Endpoint wg sync.WaitGroup logPath string + tokenDenom string } var providerBalances = make(map[string]*bankTypes.QueryBalanceResponse) @@ -1146,6 +1148,7 @@ func runProtocolE2E(timeout time.Duration) { commands: make(map[string]*exec.Cmd), providerType: make(map[string][]epochStorageTypes.Endpoint), logPath: protocolLogsFolder, + tokenDenom: commonconsts.TestTokenDenom, } // use defer to save logs in case the tests fail defer func() { diff --git a/testutil/e2e/sdkE2E.go b/testutil/e2e/sdkE2E.go index fefc875c74..2738de22f7 100644 --- a/testutil/e2e/sdkE2E.go +++ b/testutil/e2e/sdkE2E.go @@ -11,6 +11,7 @@ import ( "strings" "time" + commonconsts "github.com/lavanet/lava/testutil/common/consts" "github.com/lavanet/lava/testutil/e2e/sdk" "github.com/lavanet/lava/utils" epochStorageTypes "github.com/lavanet/lava/x/epochstorage/types" @@ -97,6 +98,7 @@ func runSDKE2E(timeout time.Duration) { commands: make(map[string]*exec.Cmd), providerType: make(map[string][]epochStorageTypes.Endpoint), logPath: sdkLogsFolder, + tokenDenom: commonconsts.TestTokenDenom, } // use defer to save logs in case the tests fail defer func() { diff --git a/testutil/keeper/conflict.go b/testutil/keeper/conflict.go index 6d6ba72d22..d915d94edb 100644 --- a/testutil/keeper/conflict.go +++ b/testutil/keeper/conflict.go @@ -46,6 +46,7 @@ func ConflictKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { nil, epochstorage, nil, + nil, ) ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) diff --git a/testutil/keeper/dualstaking.go b/testutil/keeper/dualstaking.go index 1d23ee6f44..f2a81aaaf9 100644 --- a/testutil/keeper/dualstaking.go +++ b/testutil/keeper/dualstaking.go @@ -56,7 +56,7 @@ func DualstakingKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { ) tsKeeper := timerstorekeeper.NewKeeper(cdc) - epochstorageKeeper := epochstoragekeeper.NewKeeper(cdc, nil, nil, paramsSubspaceEpochstorage, nil, nil, nil) + epochstorageKeeper := epochstoragekeeper.NewKeeper(cdc, nil, nil, paramsSubspaceEpochstorage, nil, nil, nil, nil) k := keeper.NewKeeper( cdc, diff --git a/testutil/keeper/epochstorage.go b/testutil/keeper/epochstorage.go index 20e8726345..ab47cd5b17 100644 --- a/testutil/keeper/epochstorage.go +++ b/testutil/keeper/epochstorage.go @@ -43,6 +43,7 @@ func EpochstorageKeeperWithDB(t testing.TB) (*keeper.Keeper, storetypes.CommitMu nil, nil, nil, + nil, ) return k, stateStore, db diff --git a/testutil/keeper/keepers_init.go b/testutil/keeper/keepers_init.go index 8bd2123a2a..40e4cfe276 100644 --- a/testutil/keeper/keepers_init.go +++ b/testutil/keeper/keepers_init.go @@ -27,6 +27,7 @@ import ( slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + commonconsts "github.com/lavanet/lava/testutil/common/consts" "github.com/lavanet/lava/utils/sigs" conflictkeeper "github.com/lavanet/lava/x/conflict/keeper" conflicttypes "github.com/lavanet/lava/x/conflict/types" @@ -225,24 +226,24 @@ func InitAllKeepers(t testing.TB) (*Servers, *Keepers, context.Context) { ks.StakingKeeper = *stakingkeeper.NewKeeper(cdc, stakingStoreKey, ks.AccountKeeper, ks.BankKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String()) ks.SlashingKeeper = slashingkeeper.NewKeeper(cdc, legacyCdc, slashingStoreKey, ks.StakingKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String()) ks.Spec = *speckeeper.NewKeeper(cdc, specStoreKey, specMemStoreKey, specparamsSubspace) - ks.Epochstorage = *epochstoragekeeper.NewKeeper(cdc, epochStoreKey, epochMemStoreKey, epochparamsSubspace, &ks.BankKeeper, &ks.AccountKeeper, ks.Spec) + ks.Epochstorage = *epochstoragekeeper.NewKeeper(cdc, epochStoreKey, epochMemStoreKey, epochparamsSubspace, &ks.BankKeeper, &ks.AccountKeeper, ks.Spec, ks.StakingKeeper) ks.FixationStoreKeeper = fixationkeeper.NewKeeper(cdc, ks.TimerStoreKeeper, ks.Epochstorage.BlocksToSaveRaw) ks.Dualstaking = *dualstakingkeeper.NewKeeper(cdc, dualstakingStoreKey, dualstakingMemStoreKey, dualstakingparamsSubspace, &ks.BankKeeper, &ks.StakingKeeper, &ks.AccountKeeper, ks.Epochstorage, ks.Spec, ks.FixationStoreKeeper) ks.Plans = *planskeeper.NewKeeper(cdc, plansStoreKey, plansMemStoreKey, plansparamsSubspace, ks.Epochstorage, ks.Spec, ks.FixationStoreKeeper) ks.Projects = *projectskeeper.NewKeeper(cdc, projectsStoreKey, projectsMemStoreKey, projectsparamsSubspace, ks.Epochstorage, ks.FixationStoreKeeper) ks.Protocol = *protocolkeeper.NewKeeper(cdc, protocolStoreKey, protocolMemStoreKey, protocolparamsSubspace) - ks.Subscription = *subscriptionkeeper.NewKeeper(cdc, subscriptionStoreKey, subscriptionMemStoreKey, subscriptionparamsSubspace, &ks.BankKeeper, &ks.AccountKeeper, &ks.Epochstorage, ks.Projects, ks.Plans, ks.Dualstaking, ks.FixationStoreKeeper, ks.TimerStoreKeeper) + ks.Subscription = *subscriptionkeeper.NewKeeper(cdc, subscriptionStoreKey, subscriptionMemStoreKey, subscriptionparamsSubspace, &ks.BankKeeper, &ks.AccountKeeper, &ks.Epochstorage, ks.Projects, ks.Plans, ks.Dualstaking, ks.FixationStoreKeeper, ks.TimerStoreKeeper, ks.StakingKeeper) ks.Downtime = downtimekeeper.NewKeeper(cdc, downtimeKey, downtimeParamsSubspace, ks.Epochstorage) ks.Pairing = *pairingkeeper.NewKeeper(cdc, pairingStoreKey, pairingMemStoreKey, pairingparamsSubspace, &ks.BankKeeper, &ks.AccountKeeper, ks.Spec, &ks.Epochstorage, ks.Projects, ks.Subscription, ks.Plans, ks.Downtime, ks.Dualstaking, &ks.StakingKeeper, ks.FixationStoreKeeper, ks.TimerStoreKeeper) ks.ParamsKeeper = paramsKeeper - ks.Conflict = *conflictkeeper.NewKeeper(cdc, conflictStoreKey, conflictMemStoreKey, conflictparamsSubspace, &ks.BankKeeper, &ks.AccountKeeper, ks.Pairing, ks.Epochstorage, ks.Spec) + ks.Conflict = *conflictkeeper.NewKeeper(cdc, conflictStoreKey, conflictMemStoreKey, conflictparamsSubspace, &ks.BankKeeper, &ks.AccountKeeper, ks.Pairing, ks.Epochstorage, ks.Spec, ks.StakingKeeper) ks.BlockStore = MockBlockStore{height: 0, blockHistory: make(map[int64]*tenderminttypes.Block)} ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) // Initialize params stakingparams := stakingtypes.DefaultParams() - stakingparams.BondDenom = epochstoragetypes.TokenDenom + stakingparams.BondDenom = commonconsts.TestTokenDenom ks.StakingKeeper.SetParams(ctx, stakingparams) slashingParams := slashingtypes.DefaultParams() ks.SlashingKeeper.SetParams(ctx, slashingParams) diff --git a/testutil/keeper/pairing.go b/testutil/keeper/pairing.go index fc3e2a9106..a816bc4d0e 100644 --- a/testutil/keeper/pairing.go +++ b/testutil/keeper/pairing.go @@ -48,7 +48,7 @@ func PairingKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { ) tsKeeper := timerstorekeeper.NewKeeper(cdc) - epochstorageKeeper := epochstoragekeeper.NewKeeper(cdc, nil, nil, paramsSubspaceEpochstorage, nil, nil, nil) + epochstorageKeeper := epochstoragekeeper.NewKeeper(cdc, nil, nil, paramsSubspaceEpochstorage, nil, nil, nil, nil) k := keeper.NewKeeper( cdc, storeKey, diff --git a/testutil/keeper/plan.go b/testutil/keeper/plan.go index 53e2b47fc2..5a682cf184 100644 --- a/testutil/keeper/plan.go +++ b/testutil/keeper/plan.go @@ -55,7 +55,7 @@ func PlanKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { "SpecParams", ) - epochstorageKeeper := epochstoragekeeper.NewKeeper(cdc, nil, nil, paramsSubspaceEpochstorage, nil, nil, nil) + epochstorageKeeper := epochstoragekeeper.NewKeeper(cdc, nil, nil, paramsSubspaceEpochstorage, nil, nil, nil, nil) k := keeper.NewKeeper( cdc, diff --git a/testutil/keeper/projects.go b/testutil/keeper/projects.go index f4fde382bd..9d1cb191cb 100644 --- a/testutil/keeper/projects.go +++ b/testutil/keeper/projects.go @@ -47,7 +47,7 @@ func ProjectsKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { "EpochStorageParams", ) - epochstorageKeeper := epochstoragekeeper.NewKeeper(cdc, nil, nil, paramsSubspaceEpochstorage, nil, nil, nil) + epochstorageKeeper := epochstoragekeeper.NewKeeper(cdc, nil, nil, paramsSubspaceEpochstorage, nil, nil, nil, nil) k := keeper.NewKeeper( cdc, storeKey, diff --git a/testutil/keeper/subscription.go b/testutil/keeper/subscription.go index ea5b947fbd..2ee1abaf44 100644 --- a/testutil/keeper/subscription.go +++ b/testutil/keeper/subscription.go @@ -12,6 +12,7 @@ import ( storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" typesparams "github.com/cosmos/cosmos-sdk/x/params/types" + stakgingKeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" dualstakingkeeper "github.com/lavanet/lava/x/dualstaking/keeper" epochstoragekeeper "github.com/lavanet/lava/x/epochstorage/keeper" fixationkeeper "github.com/lavanet/lava/x/fixationstore/keeper" @@ -63,7 +64,7 @@ func SubscriptionKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { memStoreKey, "PlansParams", ) - epochstorageKeeper := epochstoragekeeper.NewKeeper(cdc, nil, nil, paramsSubspaceEpochstorage, nil, nil, nil) + epochstorageKeeper := epochstoragekeeper.NewKeeper(cdc, nil, nil, paramsSubspaceEpochstorage, nil, nil, nil, nil) tsKeeper := timerstorekeeper.NewKeeper(cdc) fsKeeper := fixationkeeper.NewKeeper(cdc, tsKeeper, epochstorageKeeper.BlocksToSaveRaw) @@ -80,6 +81,7 @@ func SubscriptionKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { dualstakingkeeper.NewKeeper(cdc, nil, nil, paramsSubspace, nil, nil, mockAccountKeeper{}, nil, nil, fsKeeper), fsKeeper, tsKeeper, + stakgingKeeper.NewKeeper(cdc, nil, nil, nil, ""), ) ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) diff --git a/x/conflict/keeper/keeper.go b/x/conflict/keeper/keeper.go index 2c9961a131..5887d5c053 100644 --- a/x/conflict/keeper/keeper.go +++ b/x/conflict/keeper/keeper.go @@ -25,6 +25,7 @@ type ( pairingKeeper types.PairingKeeper epochstorageKeeper types.EpochstorageKeeper specKeeper types.SpecKeeper + stakingKeeper types.StakingKeeper } ) @@ -34,7 +35,12 @@ func NewKeeper( memKey storetypes.StoreKey, ps paramtypes.Subspace, - bankKeeper types.BankKeeper, accountKeeper types.AccountKeeper, pairingKeeper types.PairingKeeper, epochstorageKeeper types.EpochstorageKeeper, specKeeper types.SpecKeeper, + bankKeeper types.BankKeeper, + accountKeeper types.AccountKeeper, + pairingKeeper types.PairingKeeper, + epochstorageKeeper types.EpochstorageKeeper, + specKeeper types.SpecKeeper, + stakingKeeper types.StakingKeeper, ) *Keeper { // set KeyTable if it has not already been set if !ps.HasKeyTable() { @@ -42,11 +48,16 @@ func NewKeeper( } return &Keeper{ - cdc: cdc, - storeKey: storeKey, - memKey: memKey, - paramstore: ps, - bankKeeper: bankKeeper, accountKeeper: accountKeeper, pairingKeeper: pairingKeeper, epochstorageKeeper: epochstorageKeeper, specKeeper: specKeeper, + cdc: cdc, + storeKey: storeKey, + memKey: memKey, + paramstore: ps, + bankKeeper: bankKeeper, + accountKeeper: accountKeeper, + pairingKeeper: pairingKeeper, + epochstorageKeeper: epochstorageKeeper, + specKeeper: specKeeper, + stakingKeeper: stakingKeeper, } } diff --git a/x/conflict/keeper/vote.go b/x/conflict/keeper/vote.go index c301fae0d1..f9b7fe31a7 100644 --- a/x/conflict/keeper/vote.go +++ b/x/conflict/keeper/vote.go @@ -8,7 +8,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/utils" "github.com/lavanet/lava/x/conflict/types" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" "golang.org/x/exp/slices" ) @@ -58,7 +57,7 @@ func (k Keeper) HandleAndCloseVote(ctx sdk.Context, conflictVote types.ConflictV secondProviderVotes := sdk.ZeroInt() noneProviderVotes := sdk.ZeroInt() var providersWithoutVote []string - rewardPool := sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.ZeroInt()) + rewardPool := sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), sdk.ZeroInt()) rewardCount := math.ZeroInt() votersStake := map[string]math.Int{} // this is needed in order to give rewards for each voter according to their stake(so we dont take this data twice from the keeper) ConsensusVote := true @@ -123,7 +122,7 @@ func (k Keeper) HandleAndCloseVote(ctx sdk.Context, conflictVote types.ConflictV providersWithoutVote = append(providersWithoutVote, vote.Address) bail := stake bail.Quo(sdk.NewIntFromUint64(BailStakeDiv)) - k.pairingKeeper.JailEntry(ctx, accAddress, conflictVote.ChainID, conflictVote.VoteStartBlock, blocksToSave, sdk.NewCoin(epochstoragetypes.TokenDenom, bail)) + k.pairingKeeper.JailEntry(ctx, accAddress, conflictVote.ChainID, conflictVote.VoteStartBlock, blocksToSave, sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), bail)) slashed, err := k.pairingKeeper.SlashEntry(ctx, accAddress, conflictVote.ChainID, SlashStakePercent) rewardPool = rewardPool.Add(slashed) if err != nil { @@ -222,7 +221,7 @@ func (k Keeper) HandleAndCloseVote(ctx sdk.Context, conflictVote types.ConflictV utils.Attribute{Key: "voteAddress", Value: winnersAddr}, ) } else { - ok, err := k.pairingKeeper.CreditStakeEntry(ctx, conflictVote.ChainID, accWinnerAddress, sdk.NewCoin(epochstoragetypes.TokenDenom, winnerReward.TruncateInt())) + ok, err := k.pairingKeeper.CreditStakeEntry(ctx, conflictVote.ChainID, accWinnerAddress, sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), winnerReward.TruncateInt())) if !ok { utils.LavaFormatWarning("failed to credit client", err) } @@ -249,7 +248,7 @@ func (k Keeper) HandleAndCloseVote(ctx sdk.Context, conflictVote types.ConflictV ) continue } - ok, err := k.pairingKeeper.CreditStakeEntry(ctx, conflictVote.ChainID, accAddress, sdk.NewCoin(epochstoragetypes.TokenDenom, rewardVoter.TruncateInt())) + ok, err := k.pairingKeeper.CreditStakeEntry(ctx, conflictVote.ChainID, accAddress, sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), rewardVoter.TruncateInt())) if !ok { details := map[string]string{} if err != nil { diff --git a/x/conflict/types/expected_keepers.go b/x/conflict/types/expected_keepers.go index 1cc477cab2..ed7cbce585 100644 --- a/x/conflict/types/expected_keepers.go +++ b/x/conflict/types/expected_keepers.go @@ -50,3 +50,7 @@ type BankKeeper interface { SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins // Methods imported from bank should be defined here } + +type StakingKeeper interface { + BondDenom(ctx sdk.Context) string +} diff --git a/x/dualstaking/keeper/delegate.go b/x/dualstaking/keeper/delegate.go index 786c540c5c..8c041fedc5 100644 --- a/x/dualstaking/keeper/delegate.go +++ b/x/dualstaking/keeper/delegate.go @@ -57,7 +57,7 @@ func (k Keeper) increaseDelegation(ctx sdk.Context, delegator, provider, chainID found := k.delegationFS.FindEntry(ctx, index, nextEpoch, &delegationEntry) if !found { // new delegation (i.e. not increase of existing one) - delegationEntry = types.NewDelegation(delegator, provider, chainID) + delegationEntry = types.NewDelegation(delegator, provider, chainID, k.stakingKeeper.BondDenom(ctx)) } delegationEntry.AddAmount(amount) diff --git a/x/dualstaking/keeper/delegator_reward.go b/x/dualstaking/keeper/delegator_reward.go index 6753da951e..92efc0f292 100644 --- a/x/dualstaking/keeper/delegator_reward.go +++ b/x/dualstaking/keeper/delegator_reward.go @@ -128,7 +128,7 @@ func (k Keeper) ClaimRewards(ctx sdk.Context, delegator string, provider string) continue } - rewardCoins := sdk.Coins{sdk.Coin{Denom: epochstoragetypes.TokenDenom, Amount: reward.Amount.Amount}} + rewardCoins := sdk.Coins{sdk.Coin{Denom: k.stakingKeeper.BondDenom(ctx), Amount: reward.Amount.Amount}} // not minting new coins because they're minted when the provider // asked for payment (and the delegator reward map was updated) @@ -195,7 +195,7 @@ func (k Keeper) RewardProvidersAndDelegators(ctx sdk.Context, providerAddr sdk.A if !calcOnly { if fullProviderReward.GT(math.ZeroInt()) { - fullProviderRewardCoins := sdk.Coins{sdk.NewCoin(epochstoragetypes.TokenDenom, fullProviderReward)} + fullProviderRewardCoins := sdk.Coins{sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), fullProviderReward)} err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, senderModule, providerAddr, fullProviderRewardCoins) if err != nil { // panic:ok: reward transfer should never fail @@ -224,7 +224,7 @@ func (k Keeper) updateDelegatorsReward(ctx sdk.Context, totalDelegations math.In delegatorReward.Provider = delegation.Provider delegatorReward.Delegator = delegation.Delegator delegatorReward.ChainId = delegation.ChainID - delegatorReward.Amount = sdk.NewCoin(epochstoragetypes.TokenDenom, delegatorRewardAmount) + delegatorReward.Amount = sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), delegatorRewardAmount) } else { delegatorReward.Amount = delegatorReward.Amount.AddAmount(delegatorRewardAmount) } @@ -244,7 +244,7 @@ func (k Keeper) PayContributors(ctx sdk.Context, senderModule string, contributo return nil } rewardPerContributor := contributorReward.QuoRaw(int64(len(contributorAddresses))) - rewardCoins := sdk.Coins{sdk.NewCoin(epochstoragetypes.TokenDenom, rewardPerContributor)} + rewardCoins := sdk.Coins{sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), rewardPerContributor)} details := map[string]string{ "rewardCoins": rewardCoins.String(), "specId": specId, @@ -252,10 +252,10 @@ func (k Keeper) PayContributors(ctx sdk.Context, senderModule string, contributo leftRewards := contributorReward for i, contributorAddress := range contributorAddresses { details["address."+strconv.Itoa(i)] = contributorAddress.String() - if leftRewards.LT(rewardCoins.AmountOf(epochstoragetypes.TokenDenom)) { + if leftRewards.LT(rewardCoins.AmountOf(k.stakingKeeper.BondDenom(ctx))) { return utils.LavaFormatError("trying to pay contributors more than their allowed amount", nil, utils.LogAttr("rewardCoins", rewardCoins.String()), utils.LogAttr("contributorReward", contributorReward.String()), utils.LogAttr("leftRewards", leftRewards.String())) } - leftRewards = leftRewards.Sub(rewardCoins.AmountOf(epochstoragetypes.TokenDenom)) + leftRewards = leftRewards.Sub(rewardCoins.AmountOf(k.stakingKeeper.BondDenom(ctx))) err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, senderModule, contributorAddress, rewardCoins) if err != nil { return err diff --git a/x/dualstaking/keeper/grpc_query_delegator_providers_test.go b/x/dualstaking/keeper/grpc_query_delegator_providers_test.go index 6d6630613e..5e0fa0afc2 100644 --- a/x/dualstaking/keeper/grpc_query_delegator_providers_test.go +++ b/x/dualstaking/keeper/grpc_query_delegator_providers_test.go @@ -6,7 +6,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/testutil/common" "github.com/lavanet/lava/x/dualstaking/types" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" "github.com/stretchr/testify/require" ) @@ -21,14 +20,14 @@ func TestQueryWithUnbonding(t *testing.T) { spec := ts.Spec("mock") amountUint64 := uint64(100) - amount := sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewIntFromUint64(amountUint64)) + amount := sdk.NewCoin(ts.TokenDenom(), sdk.NewIntFromUint64(amountUint64)) // delegate and query _, err := ts.TxDualstakingDelegate(delegator, provider, spec.Index, amount) require.Nil(t, err) ts.AdvanceEpoch() - delegation := types.NewDelegation(delegator, provider, spec.Index) + delegation := types.NewDelegation(delegator, provider, spec.Index, ts.TokenDenom()) delegation.Amount = amount res, err := ts.QueryDualstakingDelegatorProviders(delegator, false) @@ -37,7 +36,7 @@ func TestQueryWithUnbonding(t *testing.T) { require.True(t, delegation.Equal(&delegationRes)) // partially unbond and query - unbondAmount := amount.Sub(sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.OneInt())) + unbondAmount := amount.Sub(sdk.NewCoin(ts.TokenDenom(), sdk.OneInt())) _, err = ts.TxDualstakingUnbond(delegator, provider, spec.Index, unbondAmount) require.Nil(t, err) ts.AdvanceEpoch() @@ -72,9 +71,9 @@ func TestQueryWithPendingDelegations(t *testing.T) { spec := ts.Spec("mock") amountUint64 := uint64(100) - amount := sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewIntFromUint64(amountUint64)) + amount := sdk.NewCoin(ts.TokenDenom(), sdk.NewIntFromUint64(amountUint64)) - delegation1 := types.NewDelegation(delegator1, provider, spec.Index) + delegation1 := types.NewDelegation(delegator1, provider, spec.Index, ts.TokenDenom()) delegation1.Amount = amount // delegate without advancing an epoch @@ -109,7 +108,7 @@ func TestQueryWithPendingDelegations(t *testing.T) { require.True(t, delegationRes.Equal(&delegation1)) // delegate delegator2 and query again - delegation2 := types.NewDelegation(delegator2, provider, spec.Index) + delegation2 := types.NewDelegation(delegator2, provider, spec.Index, ts.TokenDenom()) delegation2.Amount = amount _, err = ts.TxDualstakingDelegate(delegator2, provider, spec.Index, amount) require.Nil(t, err) @@ -146,7 +145,7 @@ func TestQueryProviderMultipleDelegators(t *testing.T) { require.Nil(t, err) amountUint64 := uint64(100) - amount := sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewIntFromUint64(amountUint64)) + amount := sdk.NewCoin(ts.TokenDenom(), sdk.NewIntFromUint64(amountUint64)) delegations := []types.Delegation{} for i := 0; i < len(delegators); i++ { @@ -159,7 +158,7 @@ func TestQueryProviderMultipleDelegators(t *testing.T) { _, err := ts.TxDualstakingDelegate(delegators[i], provider, chainID, amount) require.Nil(t, err) - delegation := types.NewDelegation(delegators[i], provider, chainID) + delegation := types.NewDelegation(delegators[i], provider, chainID, ts.TokenDenom()) delegation.Amount = amount delegations = append(delegations, delegation) } @@ -190,14 +189,14 @@ func TestQueryDelegatorMultipleProviders(t *testing.T) { spec := ts.Spec("mock") amountUint64 := uint64(100) - amount := sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewIntFromUint64(amountUint64)) + amount := sdk.NewCoin(ts.TokenDenom(), sdk.NewIntFromUint64(amountUint64)) delegations := []types.Delegation{} for i := 0; i < len(providers); i++ { _, err := ts.TxDualstakingDelegate(delegator, providers[i], spec.Index, amount) require.Nil(t, err) - delegation := types.NewDelegation(delegator, providers[i], spec.Index) + delegation := types.NewDelegation(delegator, providers[i], spec.Index, ts.TokenDenom()) delegation.Amount = amount delegations = append(delegations, delegation) } @@ -225,7 +224,7 @@ func TestQueryDelegatorUnstakedProvider(t *testing.T) { spec := ts.Spec("mock") amountUint64 := uint64(100) - amount := sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewIntFromUint64(amountUint64)) + amount := sdk.NewCoin(ts.TokenDenom(), sdk.NewIntFromUint64(amountUint64)) // shouldn't be able to delegate to unstaked provider _, err := ts.TxDualstakingDelegate(delegator, unstakedProvider, spec.Index, amount) diff --git a/x/dualstaking/keeper/grpc_query_provider_delegators_test.go b/x/dualstaking/keeper/grpc_query_provider_delegators_test.go index d5a80b56de..f7b13bb485 100644 --- a/x/dualstaking/keeper/grpc_query_provider_delegators_test.go +++ b/x/dualstaking/keeper/grpc_query_provider_delegators_test.go @@ -6,7 +6,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/testutil/common" "github.com/lavanet/lava/x/dualstaking/types" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" "github.com/stretchr/testify/require" ) @@ -21,14 +20,14 @@ func TestQueryProviderDelegatorsWithUnbonding(t *testing.T) { spec := ts.Spec("mock") amountUint64 := uint64(100) - amount := sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewIntFromUint64(amountUint64)) + amount := sdk.NewCoin(ts.TokenDenom(), sdk.NewIntFromUint64(amountUint64)) // delegate and query _, err := ts.TxDualstakingDelegate(delegator, provider, spec.Index, amount) require.Nil(t, err) ts.AdvanceEpoch() - delegation := types.NewDelegation(delegator, provider, spec.Index) + delegation := types.NewDelegation(delegator, provider, spec.Index, ts.TokenDenom()) delegation.Amount = amount res, err := ts.QueryDualstakingProviderDelegators(provider, false) @@ -43,7 +42,7 @@ func TestQueryProviderDelegatorsWithUnbonding(t *testing.T) { require.True(t, delegation.Equal(&delegationRes)) // partially unbond and query - unbondAmount := amount.Sub(sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.OneInt())) + unbondAmount := amount.Sub(sdk.NewCoin(ts.TokenDenom(), sdk.OneInt())) _, err = ts.TxDualstakingUnbond(delegator, provider, spec.Index, unbondAmount) require.Nil(t, err) ts.AdvanceEpoch() @@ -83,9 +82,9 @@ func TestQueryProviderDelegatorsWithPendingDelegations(t *testing.T) { spec := ts.Spec("mock") amountUint64 := uint64(100) - amount := sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewIntFromUint64(amountUint64)) + amount := sdk.NewCoin(ts.TokenDenom(), sdk.NewIntFromUint64(amountUint64)) - delegation1 := types.NewDelegation(delegator1, provider, spec.Index) + delegation1 := types.NewDelegation(delegator1, provider, spec.Index, ts.TokenDenom()) delegation1.Amount = amount // delegate without advancing an epoch @@ -133,7 +132,7 @@ func TestQueryProviderDelegatorsWithPendingDelegations(t *testing.T) { require.True(t, delegationRes.Equal(&delegation1)) // delegate delegator2 and query again - delegation2 := types.NewDelegation(delegator2, provider, spec.Index) + delegation2 := types.NewDelegation(delegator2, provider, spec.Index, ts.TokenDenom()) delegation2.Amount = amount _, err = ts.TxDualstakingDelegate(delegator2, provider, spec.Index, amount) require.Nil(t, err) @@ -181,7 +180,7 @@ func TestQueryProviderDelegatorsProviderMultipleDelegators(t *testing.T) { require.Nil(t, err) amountUint64 := uint64(100) - amount := sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewIntFromUint64(amountUint64)) + amount := sdk.NewCoin(ts.TokenDenom(), sdk.NewIntFromUint64(amountUint64)) delegations := []types.Delegation{} for i := 0; i < len(delegators); i++ { @@ -194,7 +193,7 @@ func TestQueryProviderDelegatorsProviderMultipleDelegators(t *testing.T) { _, err := ts.TxDualstakingDelegate(delegators[i], provider, chainID, amount) require.Nil(t, err) - delegation := types.NewDelegation(delegators[i], provider, chainID) + delegation := types.NewDelegation(delegators[i], provider, chainID, ts.TokenDenom()) delegation.Amount = amount delegations = append(delegations, delegation) } @@ -227,14 +226,14 @@ func TestQueryProviderDelegatorsDelegatorMultipleProviders(t *testing.T) { spec := ts.Spec("mock") amountUint64 := uint64(100) - amount := sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewIntFromUint64(amountUint64)) + amount := sdk.NewCoin(ts.TokenDenom(), sdk.NewIntFromUint64(amountUint64)) delegations := []types.Delegation{} for i := 0; i < len(providers); i++ { _, err := ts.TxDualstakingDelegate(delegator, providers[i], spec.Index, amount) require.Nil(t, err) - delegation := types.NewDelegation(delegator, providers[i], spec.Index) + delegation := types.NewDelegation(delegator, providers[i], spec.Index, ts.TokenDenom()) delegation.Amount = amount delegations = append(delegations, delegation) } @@ -267,7 +266,7 @@ func TestQueryProviderDelegatorsDelegatorUnstakedProvider(t *testing.T) { spec := ts.Spec("mock") amountUint64 := uint64(100) - amount := sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewIntFromUint64(amountUint64)) + amount := sdk.NewCoin(ts.TokenDenom(), sdk.NewIntFromUint64(amountUint64)) // shouldn't be able to delegate to unstaked provider _, err := ts.TxDualstakingDelegate(delegator, unstakedProvider, spec.Index, amount) diff --git a/x/dualstaking/keeper/hooks.go b/x/dualstaking/keeper/hooks.go index 55a98563fe..ab920d1c51 100644 --- a/x/dualstaking/keeper/hooks.go +++ b/x/dualstaking/keeper/hooks.go @@ -7,7 +7,6 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/lavanet/lava/utils" "github.com/lavanet/lava/x/dualstaking/types" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" ) // Wrapper struct @@ -56,13 +55,13 @@ func (h Hooks) AfterDelegationModified(ctx sdk.Context, delAddr sdk.AccAddress, } else if diff.IsPositive() { // less provider delegations,a delegation operation was done, delegate to empty provider err = h.k.delegate(ctx, delAddr.String(), EMPTY_PROVIDER, EMPTY_PROVIDER_CHAINID, - sdk.NewCoin(epochstoragetypes.TokenDenom, diff)) + sdk.NewCoin(h.k.stakingKeeper.BondDenom(ctx), diff)) if err != nil { return err } } else if diff.IsNegative() { // more provider delegation, unbond operation was done, unbond from providers - err = h.k.UnbondUniformProviders(ctx, delAddr.String(), sdk.NewCoin(epochstoragetypes.TokenDenom, diff.Neg())) + err = h.k.UnbondUniformProviders(ctx, delAddr.String(), sdk.NewCoin(h.k.stakingKeeper.BondDenom(ctx), diff.Neg())) if err != nil { return err } @@ -94,7 +93,7 @@ func (h Hooks) BeforeValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, f delegations := h.k.stakingKeeper.GetValidatorDelegations(ctx, valAddr) for _, d := range delegations { - err := h.k.UnbondUniformProviders(ctx, d.String(), sdk.NewCoin(epochstoragetypes.TokenDenom, slashAmount.TruncateInt())) + err := h.k.UnbondUniformProviders(ctx, d.String(), sdk.NewCoin(h.k.stakingKeeper.BondDenom(ctx), slashAmount.TruncateInt())) if err != nil { return utils.LavaFormatError("slash hook failed", err, utils.Attribute{Key: "validator_address", Value: valAddr.String()}, @@ -134,7 +133,7 @@ func (h Hooks) BeforeDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, return nil } amount := validator.TokensFromSharesRoundUp(delegation.Shares).TruncateInt() - err = h.k.UnbondUniformProviders(ctx, delAddr.String(), sdk.NewCoin(epochstoragetypes.TokenDenom, amount)) + err = h.k.UnbondUniformProviders(ctx, delAddr.String(), sdk.NewCoin(h.k.stakingKeeper.BondDenom(ctx), amount)) if err != nil { return utils.LavaFormatError("delegation removed hook failed", err, utils.Attribute{Key: "validator_address", Value: valAddr.String()}, diff --git a/x/dualstaking/keeper/hooks_test.go b/x/dualstaking/keeper/hooks_test.go index 8bf4ad7feb..9be1e11aec 100644 --- a/x/dualstaking/keeper/hooks_test.go +++ b/x/dualstaking/keeper/hooks_test.go @@ -7,7 +7,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/testutil/common" dualstakingkeeper "github.com/lavanet/lava/x/dualstaking/keeper" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" "github.com/stretchr/testify/require" ) @@ -138,7 +137,7 @@ func TestReDelegateToProvider(t *testing.T) { provider.Addr.String(), dualstakingkeeper.EMPTY_PROVIDER_CHAINID, entry.Chain, - sdk.NewCoin(epochstoragetypes.TokenDenom, amount)) + sdk.NewCoin(ts.TokenDenom(), amount)) require.Nil(t, err) @@ -208,7 +207,7 @@ func TestUnbondUniformProviders(t *testing.T) { provider, dualstakingkeeper.EMPTY_PROVIDER_CHAINID, ts.spec.Index, - sdk.NewCoin(epochstoragetypes.TokenDenom, redelegateAmts[i])) + sdk.NewCoin(ts.TokenDenom(), redelegateAmts[i])) require.Nil(t, err) } @@ -281,19 +280,19 @@ func TestValidatorSlash(t *testing.T) { provider, dualstakingkeeper.EMPTY_PROVIDER_CHAINID, ts.spec.Index, - sdk.NewCoin(epochstoragetypes.TokenDenom, redelegateAmts[i])) + sdk.NewCoin(ts.TokenDenom(), redelegateAmts[i])) require.Nil(t, err) } // sanity check: redelegate from provider0 to provider1 and check delegations balance - _, err = ts.TxDualstakingRedelegate(delegator, providers[0], providers[1], ts.spec.Index, ts.spec.Index, sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(5))) + _, err = ts.TxDualstakingRedelegate(delegator, providers[0], providers[1], ts.spec.Index, ts.spec.Index, sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(5))) require.Nil(t, err) diff, err := ts.Keepers.Dualstaking.VerifyDelegatorBalance(ts.Ctx, delegatorAcc.Addr) require.Nil(t, err) require.True(t, diff.IsZero()) // sanity check: unbond some of provider2's funds and check delegations balance - _, err = ts.TxDualstakingUnbond(delegator, providers[2], ts.spec.Index, sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(5))) + _, err = ts.TxDualstakingUnbond(delegator, providers[2], ts.spec.Index, sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(5))) require.Nil(t, err) diff, err = ts.Keepers.Dualstaking.VerifyDelegatorBalance(ts.Ctx, delegatorAcc.Addr) require.Nil(t, err) @@ -356,7 +355,7 @@ func TestCancelUnbond(t *testing.T) { ts.AdvanceEpoch() // cancel the unbond TX and check for balances - _, err = ts.TxCancelUnbondValidator(delegator, validator, unbondBlock, sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(50))) + _, err = ts.TxCancelUnbondValidator(delegator, validator, unbondBlock, sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(50))) require.Nil(t, err) diff, err := ts.Keepers.Dualstaking.VerifyDelegatorBalance(ts.Ctx, delegator.Addr) diff --git a/x/dualstaking/keeper/migrations.go b/x/dualstaking/keeper/migrations.go index dc8ee8bd73..e2021f63a3 100644 --- a/x/dualstaking/keeper/migrations.go +++ b/x/dualstaking/keeper/migrations.go @@ -6,7 +6,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/utils" dualstakingtypes "github.com/lavanet/lava/x/dualstaking/types" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" "github.com/lavanet/lava/x/pairing/types" ) @@ -62,7 +61,7 @@ func (m Migrator) ConvertProviderStakeToSelfDelegation(ctx sdk.Context) error { } } - moduleBalance := m.keeper.bankKeeper.GetBalance(ctx, m.keeper.accountKeeper.GetModuleAddress(types.ModuleName), epochstoragetypes.TokenDenom) + moduleBalance := m.keeper.bankKeeper.GetBalance(ctx, m.keeper.accountKeeper.GetModuleAddress(types.ModuleName), m.keeper.stakingKeeper.BondDenom(ctx)) if !moduleBalance.IsZero() { err := m.keeper.bankKeeper.BurnCoins(ctx, types.ModuleName, sdk.NewCoins(moduleBalance)) if err != nil { @@ -82,7 +81,7 @@ func (m Migrator) HandleProviderDelegators(ctx sdk.Context) error { nextEpoch := m.keeper.epochstorageKeeper.GetCurrentNextEpoch(ctx) // burn all coins from the pools - moduleBalance := m.keeper.bankKeeper.GetBalance(ctx, m.keeper.accountKeeper.GetModuleAddress(dualstakingtypes.BondedPoolName), epochstoragetypes.TokenDenom) + moduleBalance := m.keeper.bankKeeper.GetBalance(ctx, m.keeper.accountKeeper.GetModuleAddress(dualstakingtypes.BondedPoolName), m.keeper.stakingKeeper.BondDenom(ctx)) if !moduleBalance.IsZero() { err := m.keeper.bankKeeper.BurnCoins(ctx, dualstakingtypes.BondedPoolName, sdk.NewCoins(moduleBalance)) if err != nil { @@ -91,7 +90,7 @@ func (m Migrator) HandleProviderDelegators(ctx sdk.Context) error { } if !moduleBalance.IsZero() { - moduleBalance = m.keeper.bankKeeper.GetBalance(ctx, m.keeper.accountKeeper.GetModuleAddress(dualstakingtypes.NotBondedPoolName), epochstoragetypes.TokenDenom) + moduleBalance = m.keeper.bankKeeper.GetBalance(ctx, m.keeper.accountKeeper.GetModuleAddress(dualstakingtypes.NotBondedPoolName), m.keeper.stakingKeeper.BondDenom(ctx)) err := m.keeper.bankKeeper.BurnCoins(ctx, dualstakingtypes.NotBondedPoolName, sdk.NewCoins(moduleBalance)) if err != nil { return err @@ -120,7 +119,7 @@ func (m Migrator) HandleProviderDelegators(ctx sdk.Context) error { originalAmount := d.Amount // zero the delegation amount in the fixation store - d.Amount = sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.ZeroInt()) + d.Amount = sdk.NewCoin(m.keeper.stakingKeeper.BondDenom(ctx), sdk.ZeroInt()) m.keeper.delegationFS.ModifyEntry(ctx, ind, block, &d) // give money back from the bonded pool diff --git a/x/dualstaking/types/delegate.go b/x/dualstaking/types/delegate.go index 400420c523..33f0cd7045 100644 --- a/x/dualstaking/types/delegate.go +++ b/x/dualstaking/types/delegate.go @@ -3,15 +3,14 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/utils/slices" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" ) -func NewDelegation(delegator, provider, chainID string) Delegation { +func NewDelegation(delegator, provider, chainID, tokenDenom string) Delegation { return Delegation{ Delegator: delegator, Provider: provider, ChainID: chainID, - Amount: sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.ZeroInt()), + Amount: sdk.NewCoin(tokenDenom, sdk.ZeroInt()), } } diff --git a/x/epochstorage/keeper/keeper.go b/x/epochstorage/keeper/keeper.go index a59fe03e4f..f1530472ff 100644 --- a/x/epochstorage/keeper/keeper.go +++ b/x/epochstorage/keeper/keeper.go @@ -24,6 +24,7 @@ type ( bankKeeper types.BankKeeper accountKeeper types.AccountKeeper specKeeper types.SpecKeeper + stakingKeeper types.StakingKeeper fixationRegistries map[string]func(sdk.Context) any } @@ -35,7 +36,10 @@ func NewKeeper( memKey storetypes.StoreKey, ps paramtypes.Subspace, - bankKeeper types.BankKeeper, accountKeeper types.AccountKeeper, specKeeper types.SpecKeeper, + bankKeeper types.BankKeeper, + accountKeeper types.AccountKeeper, + specKeeper types.SpecKeeper, + stakingKeeper types.StakingKeeper, ) *Keeper { // set KeyTable if it has not already been set if !ps.HasKeyTable() { @@ -43,11 +47,14 @@ func NewKeeper( } keeper := &Keeper{ - cdc: cdc, - storeKey: storeKey, - memKey: memKey, - paramstore: ps, - bankKeeper: bankKeeper, accountKeeper: accountKeeper, specKeeper: specKeeper, + cdc: cdc, + storeKey: storeKey, + memKey: memKey, + paramstore: ps, + bankKeeper: bankKeeper, + accountKeeper: accountKeeper, + specKeeper: specKeeper, + stakingKeeper: stakingKeeper, fixationRegistries: make(map[string]func(sdk.Context) any), } diff --git a/x/epochstorage/keeper/migrations.go b/x/epochstorage/keeper/migrations.go index 4fa1d21978..e646f0bd10 100644 --- a/x/epochstorage/keeper/migrations.go +++ b/x/epochstorage/keeper/migrations.go @@ -6,7 +6,6 @@ import ( "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/utils" - "github.com/lavanet/lava/x/epochstorage/types" v3 "github.com/lavanet/lava/x/epochstorage/types/migrations/v3" v4 "github.com/lavanet/lava/x/epochstorage/types/migrations/v4" ) @@ -120,8 +119,8 @@ func (m Migrator) Migrate4to5(ctx sdk.Context) error { StakeStorages := m.keeper.GetAllStakeStorage(ctx) for st := range StakeStorages { for s := range StakeStorages[st].StakeEntries { - StakeStorages[st].StakeEntries[s].DelegateTotal = sdk.NewCoin(types.TokenDenom, sdk.ZeroInt()) - StakeStorages[st].StakeEntries[s].DelegateLimit = sdk.NewCoin(types.TokenDenom, sdk.ZeroInt()) + StakeStorages[st].StakeEntries[s].DelegateTotal = sdk.NewCoin(m.keeper.stakingKeeper.BondDenom(ctx), sdk.ZeroInt()) + StakeStorages[st].StakeEntries[s].DelegateLimit = sdk.NewCoin(m.keeper.stakingKeeper.BondDenom(ctx), sdk.ZeroInt()) StakeStorages[st].StakeEntries[s].DelegateCommission = 100 } m.keeper.SetStakeStorage(ctx, StakeStorages[st]) diff --git a/x/epochstorage/types/expected_keepers.go b/x/epochstorage/types/expected_keepers.go index 1c5eebb88f..c961cdf9db 100644 --- a/x/epochstorage/types/expected_keepers.go +++ b/x/epochstorage/types/expected_keepers.go @@ -24,3 +24,7 @@ type BankKeeper interface { SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error // Methods imported from bank should be defined here } + +type StakingKeeper interface { + BondDenom(ctx sdk.Context) string +} diff --git a/x/epochstorage/types/types.go b/x/epochstorage/types/types.go index 5a65b68803..b0844eb1bf 100644 --- a/x/epochstorage/types/types.go +++ b/x/epochstorage/types/types.go @@ -1,7 +1,5 @@ package types -const TokenDenom = "ulava" - const ( NewEpochEventName = "new_epoch" EarliestEpochEventName = "earliest_epoch" diff --git a/x/pairing/client/cli/tx_modify_provider.go b/x/pairing/client/cli/tx_modify_provider.go index a534c21a6f..46f409cc06 100644 --- a/x/pairing/client/cli/tx_modify_provider.go +++ b/x/pairing/client/cli/tx_modify_provider.go @@ -5,6 +5,7 @@ import ( "strconv" "strings" + sdkerrors "cosmossdk.io/errors" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" @@ -190,6 +191,11 @@ func CmdModifyProvider() *cobra.Command { providerEntry.DelegateLimit, providerEntry.DelegateCommission, ) + + if msg.DelegateLimit.Denom != "ulava" { + return sdkerrors.Wrapf(types.DelegateLimitError, "Coin denomanator is not ulava") + } + if err := msg.ValidateBasic(); err != nil { return err } diff --git a/x/pairing/client/cli/tx_stake_provider.go b/x/pairing/client/cli/tx_stake_provider.go index e3392e0ffe..07ccef53de 100644 --- a/x/pairing/client/cli/tx_stake_provider.go +++ b/x/pairing/client/cli/tx_stake_provider.go @@ -6,6 +6,7 @@ import ( "strconv" "strings" + sdkerrors "cosmossdk.io/errors" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" @@ -97,6 +98,11 @@ func CmdStakeProvider() *cobra.Command { delegationLimit, commission, ) + + if msg.DelegateLimit.Denom != "ulava" { + return sdkerrors.Wrapf(types.DelegateLimitError, "Coin denomanator is not ulava") + } + if err := msg.ValidateBasic(); err != nil { return err } @@ -196,6 +202,11 @@ func CmdBulkStakeProvider() *cobra.Command { delegationLimit, commission, ) + + if msg.DelegateLimit.Denom != "ulava" { + return nil, sdkerrors.Wrapf(types.DelegateLimitError, "Coin denomanator is not ulava") + } + if err := msg.ValidateBasic(); err != nil { return nil, err } diff --git a/x/pairing/keeper/delegator_rewards_test.go b/x/pairing/keeper/delegator_rewards_test.go index ef72db5394..48391e6263 100644 --- a/x/pairing/keeper/delegator_rewards_test.go +++ b/x/pairing/keeper/delegator_rewards_test.go @@ -8,7 +8,6 @@ import ( "github.com/lavanet/lava/testutil/common" "github.com/lavanet/lava/utils/sigs" dualstakingtypes "github.com/lavanet/lava/x/dualstaking/types" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" "github.com/lavanet/lava/x/pairing/types" "github.com/stretchr/testify/require" ) @@ -84,14 +83,14 @@ func TestProviderDelegatorsRewards(t *testing.T) { delegationAmount := testStake // delegate - amount1 := sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(tt.d1Amount*delegationAmount/100)) + amount1 := sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(tt.d1Amount*delegationAmount/100)) if amount1.IsZero() { amount1.Amount = sdk.OneInt() } _, err := ts.TxDualstakingDelegate(delegator1, provider, ts.spec.Index, amount1) require.Nil(t, err) - amount2 := sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(tt.d2Amount*delegationAmount/100)) + amount2 := sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(tt.d2Amount*delegationAmount/100)) _, err = ts.TxDualstakingDelegate(delegator2, provider, ts.spec.Index, amount2) require.Nil(t, err) ts.AdvanceEpoch() // apply delegations @@ -99,7 +98,7 @@ func TestProviderDelegatorsRewards(t *testing.T) { // change delegation traits of stake entry and get the modified one stakeEntry, found, stakeEntryIndex := ts.Keepers.Epochstorage.GetStakeEntryByAddressCurrent(ts.Ctx, ts.spec.Index, providerAcc.Addr) require.True(t, found) - stakeEntry.DelegateLimit = sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(tt.limit*testStake/100)) + stakeEntry.DelegateLimit = sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(tt.limit*testStake/100)) stakeEntry.DelegateCommission = tt.commission ts.Keepers.Epochstorage.ModifyStakeEntryCurrent(ts.Ctx, ts.spec.Index, stakeEntry, stakeEntryIndex) ts.AdvanceEpoch() @@ -193,8 +192,8 @@ func TestDelegationLimitAffectingProviderReward(t *testing.T) { ts.TxSubscriptionBuy(client, client, "free", 1, false) // extend by a month so the sub won't expire - delegationAmount1 := sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewIntFromUint64(uint64(testStake)/2)) - delegationAmount2 := sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewIntFromUint64(uint64(testStake))) + delegationAmount1 := sdk.NewCoin(ts.TokenDenom(), sdk.NewIntFromUint64(uint64(testStake)/2)) + delegationAmount2 := sdk.NewCoin(ts.TokenDenom(), sdk.NewIntFromUint64(uint64(testStake))) _, err := ts.TxDualstakingDelegate(delegator1, provider, ts.spec.Index, delegationAmount1) require.Nil(t, err) @@ -206,7 +205,7 @@ func TestDelegationLimitAffectingProviderReward(t *testing.T) { require.True(t, found) // modify the stake entry to have a delegation limit higher than the total delegations - stakeEntry.DelegateLimit = sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(2*testStake)) + stakeEntry.DelegateLimit = sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(2*testStake)) stakeEntry.DelegateCommission = 50 ts.Keepers.Epochstorage.ModifyStakeEntryCurrent(ts.Ctx, ts.spec.Index, stakeEntry, stakeEntryIndex) ts.AdvanceEpoch() @@ -221,7 +220,7 @@ func TestDelegationLimitAffectingProviderReward(t *testing.T) { ts.payAndVerifyBalance(relayPaymentMessage, clientAcc.Addr, providerAcc.Addr, true, true, 70) // modify the stake entry to have a delegation limit lower than the total delegations - stakeEntry.DelegateLimit = sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(testStake)) + stakeEntry.DelegateLimit = sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(testStake)) ts.Keepers.Epochstorage.ModifyStakeEntryCurrent(ts.Ctx, ts.spec.Index, stakeEntry, stakeEntryIndex) ts.AdvanceEpoch() @@ -243,7 +242,7 @@ func TestProviderRewardWithCommission(t *testing.T) { ts.AdvanceEpoch() // to apply pairing - delegationAmount1 := sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(testStake)) + delegationAmount1 := sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(testStake)) _, err := ts.TxDualstakingDelegate(delegator1, provider, ts.spec.Index, delegationAmount1) require.Nil(t, err) ts.AdvanceEpoch() // apply delegations @@ -355,7 +354,7 @@ func TestQueryDelegatorRewards(t *testing.T) { makeProviderCommissionZero(ts, spec1.Index, provider1Acc.Addr) makeProviderCommissionZero(ts, ts.spec.Index, provider2Acc.Addr) - delegationAmount := sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(testStake)) + delegationAmount := sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(testStake)) _, err = ts.TxDualstakingDelegate(delegator1, provider1, ts.spec.Index, delegationAmount) require.Nil(t, err) _, err = ts.TxDualstakingDelegate(delegator1, provider1, spec1.Index, delegationAmount) @@ -412,7 +411,7 @@ func makeProviderCommissionZero(ts *tester, chainID string, provider sdk.AccAddr stakeEntry, found, stakeEntryIndex := ts.Keepers.Epochstorage.GetStakeEntryByAddressCurrent(ts.Ctx, chainID, provider) require.True(ts.T, found) stakeEntry.DelegateCommission = 0 - stakeEntry.DelegateLimit = sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(testStake)) + stakeEntry.DelegateLimit = sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(testStake)) ts.Keepers.Epochstorage.ModifyStakeEntryCurrent(ts.Ctx, stakeEntry.Chain, stakeEntry, stakeEntryIndex) ts.AdvanceEpoch() } diff --git a/x/pairing/keeper/discipline.go b/x/pairing/keeper/discipline.go index 5ae0fbb311..29e74ba9ea 100644 --- a/x/pairing/keeper/discipline.go +++ b/x/pairing/keeper/discipline.go @@ -2,7 +2,6 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" ) func (k Keeper) JailEntry(ctx sdk.Context, account sdk.AccAddress, chainID string, jailStartBlock, jailBlocks uint64, bail sdk.Coin) error { @@ -17,5 +16,5 @@ func (k Keeper) BailEntry(ctx sdk.Context, account sdk.AccAddress, chainID strin func (k Keeper) SlashEntry(ctx sdk.Context, account sdk.AccAddress, chainID string, percentage sdk.Dec) (sdk.Coin, error) { // TODO: jail user, and count problems - return sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.ZeroInt()), nil + return sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), sdk.ZeroInt()), nil } diff --git a/x/pairing/keeper/msg_server_stake_provider.go b/x/pairing/keeper/msg_server_stake_provider.go index 5598508b07..e5a6b9a0df 100644 --- a/x/pairing/keeper/msg_server_stake_provider.go +++ b/x/pairing/keeper/msg_server_stake_provider.go @@ -3,6 +3,7 @@ package keeper import ( "context" + sdkerrors "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/x/pairing/types" ) @@ -10,6 +11,11 @@ import ( func (k msgServer) StakeProvider(goCtx context.Context, msg *types.MsgStakeProvider) (*types.MsgStakeProviderResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) + if msg.DelegateLimit.Denom != k.stakingKeeper.BondDenom(ctx) { + _, err := sdk.AccAddressFromBech32(msg.Creator) + return &types.MsgStakeProviderResponse{}, sdkerrors.Wrapf(types.DelegateLimitError, "Invalid coin (%s)", err.Error()) + } + if err := msg.ValidateBasic(); err != nil { return &types.MsgStakeProviderResponse{}, err } diff --git a/x/pairing/keeper/msg_server_stake_provider_test.go b/x/pairing/keeper/msg_server_stake_provider_test.go index ea0bbc7a3d..8c567b70ff 100644 --- a/x/pairing/keeper/msg_server_stake_provider_test.go +++ b/x/pairing/keeper/msg_server_stake_provider_test.go @@ -689,7 +689,7 @@ func TestStakeEndpoints(t *testing.T) { }, } - amount := common.NewCoin(testStake) + amount := common.NewCoin(ts.Keepers.StakingKeeper.BondDenom(ts.Ctx), testStake) for _, play := range playbook { t.Run(play.name, func(t *testing.T) { diff --git a/x/pairing/keeper/pairing_test.go b/x/pairing/keeper/pairing_test.go index ad1531b4a6..841ad1f993 100644 --- a/x/pairing/keeper/pairing_test.go +++ b/x/pairing/keeper/pairing_test.go @@ -982,21 +982,21 @@ func TestGeolocationPairingScores(t *testing.T) { freePlan := planstypes.Plan{ Index: "free", Block: ts.BlockHeight(), - Price: sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(1)), + Price: sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(1)), PlanPolicy: freePlanPolicy, } basicPlan := planstypes.Plan{ Index: "basic", Block: ts.BlockHeight(), - Price: sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(1)), + Price: sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(1)), PlanPolicy: basicPlanPolicy, } premiumPlan := planstypes.Plan{ Index: "premium", Block: ts.BlockHeight(), - Price: sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(1)), + Price: sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(1)), PlanPolicy: premiumPlanPolicy, } @@ -1190,7 +1190,7 @@ func TestDuplicateProviders(t *testing.T) { basicPlan := planstypes.Plan{ Index: "basic", Block: ts.BlockHeight(), - Price: sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(1)), + Price: sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(1)), PlanPolicy: basicPlanPolicy, } @@ -1238,7 +1238,7 @@ func TestNoRequiredGeo(t *testing.T) { freePlan := planstypes.Plan{ Index: "free", Block: ts.BlockHeight(), - Price: sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(1)), + Price: sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(1)), PlanPolicy: freePlanPolicy, } diff --git a/x/pairing/keeper/staking.go b/x/pairing/keeper/staking.go index 482245b83e..23ff4ae0a2 100644 --- a/x/pairing/keeper/staking.go +++ b/x/pairing/keeper/staking.go @@ -132,14 +132,14 @@ func (k Keeper) StakeNewEntry(ctx sdk.Context, validator, creator, chainID strin } stakeEntry := epochstoragetypes.StakeEntry{ - Stake: sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.ZeroInt()), // we set this to 0 since the delegate will take care of this + Stake: sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), sdk.ZeroInt()), // we set this to 0 since the delegate will take care of this Address: creator, StakeAppliedBlock: stakeAppliedBlock, Endpoints: endpointsVerified, Geolocation: geolocation, Chain: chainID, Moniker: moniker, - DelegateTotal: sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.ZeroInt()), + DelegateTotal: sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), sdk.ZeroInt()), DelegateLimit: delegationLimit, DelegateCommission: delegationCommission, } diff --git a/x/pairing/keeper/unstaking.go b/x/pairing/keeper/unstaking.go index aaefa086e8..4838e6e449 100644 --- a/x/pairing/keeper/unstaking.go +++ b/x/pairing/keeper/unstaking.go @@ -6,7 +6,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/utils" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" "github.com/lavanet/lava/x/pairing/types" spectypes "github.com/lavanet/lava/x/spec/types" ) @@ -123,7 +122,7 @@ func (k Keeper) UnstakeEntryForce(ctx sdk.Context, chainID, provider, unstakeDes amount = totalAmount } totalAmount = totalAmount.Sub(amount) - err = k.dualstakingKeeper.UnbondFull(ctx, existingEntry.GetAddress(), validator.OperatorAddress, existingEntry.GetAddress(), existingEntry.GetChain(), sdk.NewCoin(epochstoragetypes.TokenDenom, amount), true) + err = k.dualstakingKeeper.UnbondFull(ctx, existingEntry.GetAddress(), validator.OperatorAddress, existingEntry.GetAddress(), existingEntry.GetChain(), sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), amount), true) if err != nil { return utils.LavaFormatWarning("can't unbond seld delegation", err, utils.Attribute{Key: "address", Value: existingEntry.Address}, diff --git a/x/pairing/types/expected_keepers.go b/x/pairing/types/expected_keepers.go index d384e2f245..ab9dd7109f 100644 --- a/x/pairing/types/expected_keepers.go +++ b/x/pairing/types/expected_keepers.go @@ -114,4 +114,5 @@ type TimerStoreKeeper interface { type StakingKeeper interface { GetAllDelegatorDelegations(ctx sdk.Context, delegator sdk.AccAddress) []stakingtypes.Delegation GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator stakingtypes.Validator, found bool) + BondDenom(ctx sdk.Context) string } diff --git a/x/pairing/types/message_stake_provider.go b/x/pairing/types/message_stake_provider.go index 0b46a07793..acfe94ac29 100644 --- a/x/pairing/types/message_stake_provider.go +++ b/x/pairing/types/message_stake_provider.go @@ -64,9 +64,5 @@ func (msg *MsgStakeProvider) ValidateBasic() error { return sdkerrors.Wrapf(DelegateLimitError, "Invalid coin (%s)", err.Error()) } - if msg.DelegateLimit.Denom != epochstoragetypes.TokenDenom { - return sdkerrors.Wrapf(DelegateLimitError, "Coin denomanator is not ulava") - } - return nil } diff --git a/x/plans/keeper/plan_test.go b/x/plans/keeper/plan_test.go index 40acd5dd10..14beb9de2e 100644 --- a/x/plans/keeper/plan_test.go +++ b/x/plans/keeper/plan_test.go @@ -57,7 +57,7 @@ func (ts *tester) createTestPlans(count int, withSameIndex bool, startIndex int) Description: "plan to test", Type: "rpc", Block: 100, - Price: common.NewCoin(1), + Price: common.NewCoin(ts.Keepers.StakingKeeper.BondDenom(ts.Ctx), 1), PlanPolicy: policy, AllowOveruse: true, OveruseRate: overuseRate, @@ -152,7 +152,7 @@ func TestAddInvalidPlan(t *testing.T) { switch tt.fieldIndex { case PRICE_FIELD: - plans[0].Price = common.NewCoin(0) + plans[0].Price = common.NewCoin(ts.Keepers.StakingKeeper.BondDenom(ts.Ctx), 0) case OVERUSE_FIELDS: plans[0].AllowOveruse = true plans[0].OveruseRate = 0 diff --git a/x/plans/types/plan.go b/x/plans/types/plan.go index 77fa10d7ed..2191065186 100644 --- a/x/plans/types/plan.go +++ b/x/plans/types/plan.go @@ -7,7 +7,6 @@ import ( sdkerrors "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" ) // Function to validate a plan object fields @@ -15,12 +14,15 @@ func (p Plan) ValidatePlan() error { if p.GetIndex() == "" { return sdkerrors.Wrap(ErrInvalidPlanIndex, "plan's index can't be empty") } + + // TODO: YAROM + // validate denom is ulava - if p.GetPrice().Denom != epochstoragetypes.TokenDenom { + if p.GetPrice().Denom != tokenDenom { return sdkerrors.Wrap(ErrInvalidPlanPrice, "plan's price denom is not in ulava") } // check that the plan's price is non-zero - if p.GetPrice().IsEqual(sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.ZeroInt())) { + if p.GetPrice().IsEqual(sdk.NewCoin(tokenDenom, sdk.ZeroInt())) { return sdkerrors.Wrap(ErrInvalidPlanPrice, "plan's price can't be zero") } diff --git a/x/projects/keeper/project_test.go b/x/projects/keeper/project_test.go index d6c06b560b..16d39918e6 100644 --- a/x/projects/keeper/project_test.go +++ b/x/projects/keeper/project_test.go @@ -9,7 +9,6 @@ import ( "github.com/lavanet/lava/testutil/common" testkeeper "github.com/lavanet/lava/testutil/keeper" "github.com/lavanet/lava/utils/sigs" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" planstypes "github.com/lavanet/lava/x/plans/types" "github.com/lavanet/lava/x/projects/types" "github.com/stretchr/testify/require" @@ -1099,7 +1098,7 @@ func TestSetPolicyByGeolocation(t *testing.T) { freePlan := planstypes.Plan{ Index: "free", Block: uint64(ctx.BlockHeight()), - Price: sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(1)), + Price: sdk.NewCoin(keepers.StakingKeeper.BondDenom(ctx), sdk.NewInt(1)), PlanPolicy: planstypes.Policy{ GeolocationProfile: 4, // USE TotalCuLimit: 10, @@ -1111,7 +1110,7 @@ func TestSetPolicyByGeolocation(t *testing.T) { basicPlan := planstypes.Plan{ Index: "basic", Block: uint64(ctx.BlockHeight()), - Price: sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(1)), + Price: sdk.NewCoin(keepers.StakingKeeper.BondDenom(ctx), sdk.NewInt(1)), PlanPolicy: planstypes.Policy{ GeolocationProfile: 0, // GLS TotalCuLimit: 10, @@ -1123,7 +1122,7 @@ func TestSetPolicyByGeolocation(t *testing.T) { premiumPlan := planstypes.Plan{ Index: "premium", Block: uint64(ctx.BlockHeight()), - Price: sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(1)), + Price: sdk.NewCoin(keepers.StakingKeeper.BondDenom(ctx), sdk.NewInt(1)), PlanPolicy: planstypes.Policy{ GeolocationProfile: 65535, // GL TotalCuLimit: 10, diff --git a/x/spec/keeper/keeper.go b/x/spec/keeper/keeper.go index 8c8b4bd745..68fb720c4f 100644 --- a/x/spec/keeper/keeper.go +++ b/x/spec/keeper/keeper.go @@ -19,6 +19,8 @@ type ( storeKey storetypes.StoreKey memKey storetypes.StoreKey paramstore paramtypes.Subspace + + stakingKeeper types.StakingKeeper } ) diff --git a/x/spec/keeper/spec.go b/x/spec/keeper/spec.go index 60e38fbfda..f2a783b718 100644 --- a/x/spec/keeper/spec.go +++ b/x/spec/keeper/spec.go @@ -3,6 +3,7 @@ package keeper import ( "encoding/binary" "fmt" + "strconv" "strings" "cosmossdk.io/math" @@ -222,6 +223,11 @@ func (k Keeper) ValidateSpec(ctx sdk.Context, spec types.Spec) (map[string]strin return details, err } + if spec.MinStakeProvider.Denom != k.stakingKeeper.BondDenom(ctx) { + details := map[string]string{"spec": spec.Name, "status": strconv.FormatBool(spec.Enabled), "chainID": spec.Index} + return details, fmt.Errorf("MinStakeProvider must have denom of ulava") + } + details, err := spec.ValidateSpec(k.MaxCU(ctx)) if err != nil { return details, err diff --git a/x/spec/keeper/spec_test.go b/x/spec/keeper/spec_test.go index e2977ec6aa..0defddb2e3 100644 --- a/x/spec/keeper/spec_test.go +++ b/x/spec/keeper/spec_test.go @@ -490,7 +490,7 @@ func TestSpecUpdateInherit(t *testing.T) { BlocksInFinalizationProof: 3, AverageBlockTime: 13000, AllowedBlockLagForQosSync: 2, - MinStakeProvider: common.NewCoin(5000), + MinStakeProvider: common.NewCoin(ts.TokenDenom(), 5000), ApiCollections: []*types.ApiCollection{ { Enabled: true, @@ -510,7 +510,7 @@ func TestSpecUpdateInherit(t *testing.T) { BlocksInFinalizationProof: 3, AverageBlockTime: 13000, AllowedBlockLagForQosSync: 2, - MinStakeProvider: common.NewCoin(5000), + MinStakeProvider: common.NewCoin(ts.TokenDenom(), 5000), Imports: []string{"parent"}, } diff --git a/x/spec/types/expected_keepers.go b/x/spec/types/expected_keepers.go index 6aa6e97781..eba5da4250 100644 --- a/x/spec/types/expected_keepers.go +++ b/x/spec/types/expected_keepers.go @@ -16,3 +16,7 @@ type BankKeeper interface { SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins // Methods imported from bank should be defined here } + +type StakingKeeper interface { + BondDenom(ctx sdk.Context) string +} diff --git a/x/spec/types/spec.go b/x/spec/types/spec.go index a1fa4c3b9d..ae25f19be2 100644 --- a/x/spec/types/spec.go +++ b/x/spec/types/spec.go @@ -9,7 +9,6 @@ import ( "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" ) const ( @@ -67,8 +66,8 @@ func (spec Spec) ValidateSpec(maxCU uint64) (map[string]string, error) { return details, fmt.Errorf("AllowedBlockLagForQosSync can't be zero") } - if spec.MinStakeProvider.Denom != epochstoragetypes.TokenDenom || spec.MinStakeProvider.Amount.IsZero() { - return details, fmt.Errorf("MinStakeProvider can't be zero and must have denom of ulava") + if spec.MinStakeProvider.Amount.IsZero() { + return details, fmt.Errorf("MinStakeProvider can't be zero") } for _, apiCollection := range spec.ApiCollections { diff --git a/x/subscription/keeper/keeper.go b/x/subscription/keeper/keeper.go index 7e1c5b00d5..70bb73b921 100644 --- a/x/subscription/keeper/keeper.go +++ b/x/subscription/keeper/keeper.go @@ -28,6 +28,7 @@ type ( projectsKeeper types.ProjectsKeeper plansKeeper types.PlansKeeper dualstakingKeeper types.DualStakingKeeper + stakingKeeper types.StakingKeeper subsFS fixationtypes.FixationStore subsTS timerstoretypes.TimerStore @@ -51,6 +52,7 @@ func NewKeeper( dualstakingKeeper types.DualStakingKeeper, fixationStoreKeeper types.FixationStoreKeeper, timerStoreKeeper types.TimerStoreKeeper, + stakingKeeper types.StakingKeeper, ) *Keeper { // set KeyTable if it has not already been set if !ps.HasKeyTable() { @@ -72,6 +74,7 @@ func NewKeeper( projectsKeeper: projectsKeeper, plansKeeper: plansKeeper, dualstakingKeeper: dualstakingKeeper, + stakingKeeper: stakingKeeper, subsFS: fs, cuTrackerFS: cuTracker, diff --git a/x/subscription/keeper/subscription.go b/x/subscription/keeper/subscription.go index 189dd9e1ce..4a7cb4f277 100644 --- a/x/subscription/keeper/subscription.go +++ b/x/subscription/keeper/subscription.go @@ -8,7 +8,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" legacyerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/lavanet/lava/utils" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" planstypes "github.com/lavanet/lava/x/plans/types" projectstypes "github.com/lavanet/lava/x/projects/types" "github.com/lavanet/lava/x/subscription/types" @@ -204,7 +203,7 @@ func (k Keeper) CreateSubscription( } } - if k.bankKeeper.GetBalance(ctx, creatorAcct, epochstoragetypes.TokenDenom).IsLT(price) { + if k.bankKeeper.GetBalance(ctx, creatorAcct, k.stakingKeeper.BondDenom(ctx)).IsLT(price) { return utils.LavaFormatWarning("create subscription failed", legacyerrors.ErrInsufficientFunds, utils.Attribute{Key: "creator", Value: creator}, utils.Attribute{Key: "price", Value: price}, diff --git a/x/subscription/keeper/subscription_test.go b/x/subscription/keeper/subscription_test.go index d12aa986ff..c44036ee67 100644 --- a/x/subscription/keeper/subscription_test.go +++ b/x/subscription/keeper/subscription_test.go @@ -429,7 +429,7 @@ func TestSubscriptionExpire(t *testing.T) { sub1Acct, sub1Addr := ts.Account("sub1") plan := ts.Plan("free") - coins := common.NewCoins(10000) + coins := common.NewCoins(ts.TokenDenom(), 10000) ts.Keepers.BankKeeper.SetBalance(ts.Ctx, sub1Acct.Addr, coins) _, err := ts.TxSubscriptionBuy(sub1Addr, sub1Addr, plan.Index, 1, false) @@ -487,7 +487,7 @@ func TestPrice(t *testing.T) { plan := ts.Plan("free") plan.AnnualDiscountPercentage = tt.discount - plan.Price = common.NewCoin(tt.price) + plan.Price = common.NewCoin(ts.TokenDenom(), tt.price) err := ts.TxProposalAddPlans(plan) require.Nil(t, err) diff --git a/x/subscription/types/expected_keepers.go b/x/subscription/types/expected_keepers.go index cce4b8b4a9..ec3a97cc0d 100644 --- a/x/subscription/types/expected_keepers.go +++ b/x/subscription/types/expected_keepers.go @@ -61,3 +61,7 @@ type TimerStoreKeeper interface { type DualStakingKeeper interface { RewardProvidersAndDelegators(ctx sdk.Context, providerAddr sdk.AccAddress, chainID string, totalReward math.Int, senderModule string, calcOnly bool) (providerReward math.Int, err error) } + +type StakingKeeper interface { + BondDenom(ctx sdk.Context) string +} From 4e7eac7e87e19a330e4d4bf88b15371efe4e0fd6 Mon Sep 17 00:00:00 2001 From: oren-lava Date: Tue, 28 Nov 2023 18:11:08 +0200 Subject: [PATCH 03/85] CNS-715: add tester helper functions --- testutil/common/tester.go | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/testutil/common/tester.go b/testutil/common/tester.go index 4f8ed885ea..6e0fdddcb3 100644 --- a/testutil/common/tester.go +++ b/testutil/common/tester.go @@ -13,6 +13,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" testkeeper "github.com/lavanet/lava/testutil/keeper" + "github.com/lavanet/lava/utils" "github.com/lavanet/lava/utils/sigs" "github.com/lavanet/lava/utils/slices" dualstakingtypes "github.com/lavanet/lava/x/dualstaking/types" @@ -177,6 +178,27 @@ func (ts *Tester) StakeProviderExtra( return err } +// GetValidator gets a validator object +// Usually, you get the account of your created validator with ts.GetAccount +// so input valAcc.addr to this function +func (ts *Tester) GetValidator(addr sdk.AccAddress) stakingtypes.Validator { + v, found := ts.Keepers.StakingKeeper.GetValidator(ts.Ctx, sdk.ValAddress(addr)) + require.True(ts.T, found) + return v +} + +// SlashValidator slashes a validator and returns the expected amount of burned tokens (of the validator). +// Usually, you get the account of your created validator with ts.GetAccount, so input valAcc to this function +func (ts *Tester) SlashValidator(valAcc sigs.Account, fraction math.LegacyDec, power int64, block int64) math.Int { + // slash + valConsAddr := sdk.GetConsAddress(valAcc.PubKey) + ts.Keepers.SlashingKeeper.Slash(ts.Ctx, valConsAddr, fraction, power, ts.Ctx.BlockHeight()) + + // calculate expected burned tokens + consensusPowerTokens := ts.Keepers.StakingKeeper.TokensFromConsensusPower(ts.Ctx, power) + return fraction.MulInt(consensusPowerTokens).TruncateInt() +} + func (ts *Tester) AccountByAddr(addr string) (sigs.Account, string) { for _, account := range ts.accounts { if account.Addr.String() == addr { @@ -559,6 +581,16 @@ func (ts *Tester) TxPairingUnfreezeProvider(addr, chainID string) (*pairingtypes // TxCreateValidator: implement 'tx staking createvalidator' and bond its tokens func (ts *Tester) TxCreateValidator(validator sigs.Account, amount math.Int) { + consensusPowerTokens := ts.Keepers.StakingKeeper.TokensFromConsensusPower(ts.Ctx, 1) + if amount.LT(consensusPowerTokens) { + utils.LavaFormatWarning(`validator stake should usually be larger than the amount of tokens for one + unit of consensus power`, + fmt.Errorf("validator stake might be too small"), + utils.Attribute{Key: "consensus_power_tokens", Value: consensusPowerTokens.String()}, + utils.Attribute{Key: "validator_stake", Value: amount.String()}, + ) + } + // create a validator msg, err := stakingtypes.NewMsgCreateValidator( sdk.ValAddress(validator.Addr), @@ -572,6 +604,7 @@ func (ts *Tester) TxCreateValidator(validator sigs.Account, amount math.Int) { _, err = ts.Servers.StakingServer.CreateValidator(ts.GoCtx, msg) require.Nil(ts.T, err) + // **** Make validator boded **** // move validator's coins from unbonded pool to bonded val, found := ts.Keepers.StakingKeeper.GetValidator(ts.Ctx, sdk.ValAddress(validator.Addr)) require.True(ts.T, found) From daaa1f4db197e069601c278ad800f2fd72ddcd97 Mon Sep 17 00:00:00 2001 From: oren-lava Date: Tue, 28 Nov 2023 18:22:20 +0200 Subject: [PATCH 04/85] CNS-715: fix staking hooks bug and decrease delegation bug --- testutil/keeper/keepers_init.go | 11 ++++------- x/dualstaking/keeper/delegate.go | 21 ++++++++++----------- x/dualstaking/keeper/hooks.go | 27 +++++++++++++++++++++++---- 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/testutil/keeper/keepers_init.go b/testutil/keeper/keepers_init.go index 8bd2123a2a..9f05007c72 100644 --- a/testutil/keeper/keepers_init.go +++ b/testutil/keeper/keepers_init.go @@ -222,12 +222,14 @@ func InitAllKeepers(t testing.TB) (*Servers, *Keepers, context.Context) { ks.TimerStoreKeeper = timerstorekeeper.NewKeeper(cdc) ks.AccountKeeper = mockAccountKeeper{} ks.BankKeeper = mockBankKeeper{} - ks.StakingKeeper = *stakingkeeper.NewKeeper(cdc, stakingStoreKey, ks.AccountKeeper, ks.BankKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String()) - ks.SlashingKeeper = slashingkeeper.NewKeeper(cdc, legacyCdc, slashingStoreKey, ks.StakingKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String()) ks.Spec = *speckeeper.NewKeeper(cdc, specStoreKey, specMemStoreKey, specparamsSubspace) ks.Epochstorage = *epochstoragekeeper.NewKeeper(cdc, epochStoreKey, epochMemStoreKey, epochparamsSubspace, &ks.BankKeeper, &ks.AccountKeeper, ks.Spec) ks.FixationStoreKeeper = fixationkeeper.NewKeeper(cdc, ks.TimerStoreKeeper, ks.Epochstorage.BlocksToSaveRaw) ks.Dualstaking = *dualstakingkeeper.NewKeeper(cdc, dualstakingStoreKey, dualstakingMemStoreKey, dualstakingparamsSubspace, &ks.BankKeeper, &ks.StakingKeeper, &ks.AccountKeeper, ks.Epochstorage, ks.Spec, ks.FixationStoreKeeper) + ks.StakingKeeper = *stakingkeeper.NewKeeper(cdc, stakingStoreKey, ks.AccountKeeper, ks.BankKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String()) + // register the staking hooks + ks.StakingKeeper.SetHooks(stakingtypes.NewMultiStakingHooks(ks.Dualstaking.Hooks())) + ks.SlashingKeeper = slashingkeeper.NewKeeper(cdc, legacyCdc, slashingStoreKey, ks.StakingKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String()) ks.Plans = *planskeeper.NewKeeper(cdc, plansStoreKey, plansMemStoreKey, plansparamsSubspace, ks.Epochstorage, ks.Spec, ks.FixationStoreKeeper) ks.Projects = *projectskeeper.NewKeeper(cdc, projectsStoreKey, projectsMemStoreKey, projectsparamsSubspace, ks.Epochstorage, ks.FixationStoreKeeper) ks.Protocol = *protocolkeeper.NewKeeper(cdc, protocolStoreKey, protocolMemStoreKey, protocolparamsSubspace) @@ -260,11 +262,6 @@ func InitAllKeepers(t testing.TB) (*Servers, *Keepers, context.Context) { ks.Plans.SetParams(ctx, planstypes.DefaultParams()) ks.Downtime.SetParams(ctx, downtimev1.DefaultParams()) - // register the staking hooks - ks.StakingKeeper.SetHooks( - stakingtypes.NewMultiStakingHooks(ks.Dualstaking.Hooks()), - ) - ks.Epochstorage.PushFixatedParams(ctx, 0, 0) ss := Servers{} diff --git a/x/dualstaking/keeper/delegate.go b/x/dualstaking/keeper/delegate.go index 786c540c5c..88742b777d 100644 --- a/x/dualstaking/keeper/delegate.go +++ b/x/dualstaking/keeper/delegate.go @@ -161,19 +161,18 @@ func (k Keeper) decreaseDelegation(ctx sdk.Context, delegator, provider, chainID // otherwise just append the new version (for next epoch). if delegationEntry.Amount.IsZero() { delegatorEntry.DelProvider(provider) - if delegatorEntry.IsEmpty() { - err := k.delegatorFS.DelEntry(ctx, index, nextEpoch) - if err != nil { - // delete should never fail here - return utils.LavaFormatError("critical: delete delegator entry", err, - utils.Attribute{Key: "delegator", Value: delegator}, - utils.Attribute{Key: "provider", Value: provider}, - utils.Attribute{Key: "chainID", Value: chainID}, - ) - } + } + if delegatorEntry.IsEmpty() { + err := k.delegatorFS.DelEntry(ctx, index, nextEpoch) + if err != nil { + // delete should never fail here + return utils.LavaFormatError("critical: delete delegator entry", err, + utils.Attribute{Key: "delegator", Value: delegator}, + utils.Attribute{Key: "provider", Value: provider}, + utils.Attribute{Key: "chainID", Value: chainID}, + ) } } else { - delegatorEntry.AddProvider(provider) err := k.delegatorFS.AppendEntry(ctx, index, nextEpoch, &delegatorEntry) if err != nil { // append should never fail here diff --git a/x/dualstaking/keeper/hooks.go b/x/dualstaking/keeper/hooks.go index 55a98563fe..8d34962008 100644 --- a/x/dualstaking/keeper/hooks.go +++ b/x/dualstaking/keeper/hooks.go @@ -8,6 +8,7 @@ import ( "github.com/lavanet/lava/utils" "github.com/lavanet/lava/x/dualstaking/types" epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" + "golang.org/x/exp/slices" ) // Wrapper struct @@ -90,16 +91,34 @@ func (h Hooks) BeforeValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, f utils.Attribute{Key: "validator_address", Value: valAddr.String()}, ) } - slashAmount := sdk.NewDecFromInt(val.Tokens).Mul(fraction) + remainingTokensToSlash := fraction.MulInt(val.Tokens).TruncateInt() delegations := h.k.stakingKeeper.GetValidatorDelegations(ctx, valAddr) for _, d := range delegations { - err := h.k.UnbondUniformProviders(ctx, d.String(), sdk.NewCoin(epochstoragetypes.TokenDenom, slashAmount.TruncateInt())) + tokens := val.TokensFromShares(d.Shares).TruncateInt() + tokensToSlash := fraction.MulInt(tokens).TruncateInt() + err := h.k.UnbondUniformProviders(ctx, d.DelegatorAddress, sdk.NewCoin(epochstoragetypes.TokenDenom, tokensToSlash)) if err != nil { return utils.LavaFormatError("slash hook failed", err, utils.Attribute{Key: "validator_address", Value: valAddr.String()}, - utils.Attribute{Key: "delegator_address", Value: d.String()}, - utils.Attribute{Key: "slash_amount", Value: slashAmount.String()}, + utils.Attribute{Key: "delegator_address", Value: d.DelegatorAddress}, + utils.Attribute{Key: "slash_amount", Value: tokensToSlash.String()}, + ) + } + remainingTokensToSlash = remainingTokensToSlash.Sub(tokensToSlash) + } + + // if there's a remainder, remove it from the highest delegation + if !remainingTokensToSlash.IsZero() { + slices.SortFunc(delegations, func(i, j stakingtypes.Delegation) bool { + return i.Shares.GT(j.Shares) + }) + err := h.k.UnbondUniformProviders(ctx, delegations[0].DelegatorAddress, sdk.NewCoin(epochstoragetypes.TokenDenom, remainingTokensToSlash)) + if err != nil { + return utils.LavaFormatError("slash hook failed", err, + utils.Attribute{Key: "validator_address", Value: valAddr.String()}, + utils.Attribute{Key: "delegator_address", Value: delegations[0].DelegatorAddress}, + utils.Attribute{Key: "slash_amount", Value: remainingTokensToSlash.String()}, ) } } From fd183f52602347ff1dadc0932853986b08505bf5 Mon Sep 17 00:00:00 2001 From: oren-lava Date: Tue, 28 Nov 2023 18:24:33 +0200 Subject: [PATCH 05/85] CNS-715: add and fix unit tests --- x/dualstaking/keeper/helpers_test.go | 3 +- x/dualstaking/keeper/hooks_test.go | 285 +++++++++++++++++++++------ 2 files changed, 230 insertions(+), 58 deletions(-) diff --git a/x/dualstaking/keeper/helpers_test.go b/x/dualstaking/keeper/helpers_test.go index a48f01c0b1..d568d35651 100644 --- a/x/dualstaking/keeper/helpers_test.go +++ b/x/dualstaking/keeper/helpers_test.go @@ -37,8 +37,7 @@ func newTester(t *testing.T) *tester { func (ts *tester) setupForDelegation(delegatorCount, stakedCount, unstakedCount, unstakingCount int) *tester { ts.addValidators(1) val, _ := ts.GetAccount(common.VALIDATOR, 0) - _, err := ts.TxCreateValidator(val, math.NewIntFromUint64(uint64(testStake))) - require.Nil(ts.T, err) + ts.TxCreateValidator(val, math.NewIntFromUint64(uint64(testStake))) ts.addClients(delegatorCount) diff --git a/x/dualstaking/keeper/hooks_test.go b/x/dualstaking/keeper/hooks_test.go index 8bf4ad7feb..60dbca4587 100644 --- a/x/dualstaking/keeper/hooks_test.go +++ b/x/dualstaking/keeper/hooks_test.go @@ -1,14 +1,21 @@ package keeper_test import ( + "fmt" + "math/rand" + "strconv" "testing" + "time" "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/lavanet/lava/testutil/common" dualstakingkeeper "github.com/lavanet/lava/x/dualstaking/keeper" + dualstakingtypes "github.com/lavanet/lava/x/dualstaking/types" epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" "github.com/stretchr/testify/require" + "golang.org/x/exp/slices" ) // test that creation of a validator creates a delegation from the validator to an empty provider @@ -19,8 +26,7 @@ func TestCreateValidator(t *testing.T) { validator, _ := ts.GetAccount(common.VALIDATOR, 0) amount := sdk.NewIntFromUint64(100) - _, err := ts.TxCreateValidator(validator, amount) - require.Nil(t, err) + ts.TxCreateValidator(validator, amount) res, err := ts.QueryDualstakingProviderDelegators(dualstakingkeeper.EMPTY_PROVIDER, true) require.Nil(t, err) @@ -35,8 +41,7 @@ func TestDelegateToValidator(t *testing.T) { validator, _ := ts.GetAccount(common.VALIDATOR, 0) amount := sdk.NewIntFromUint64(100) - _, err := ts.TxCreateValidator(validator, amount) - require.Nil(t, err) + ts.TxCreateValidator(validator, amount) res, err := ts.QueryDualstakingProviderDelegators(dualstakingkeeper.EMPTY_PROVIDER, true) require.Nil(t, err) @@ -63,11 +68,8 @@ func TestReDelegateToValidator(t *testing.T) { validator2, _ := ts.GetAccount(common.VALIDATOR, 1) amount := sdk.NewIntFromUint64(100) - _, err := ts.TxCreateValidator(validator1, amount) - require.Nil(t, err) - - _, err = ts.TxCreateValidator(validator2, amount) - require.Nil(t, err) + ts.TxCreateValidator(validator1, amount) + ts.TxCreateValidator(validator2, amount) delegatorsRes, err := ts.QueryDualstakingProviderDelegators(dualstakingkeeper.EMPTY_PROVIDER, true) require.Nil(t, err) @@ -108,11 +110,10 @@ func TestReDelegateToProvider(t *testing.T) { validator, _ := ts.GetAccount(common.VALIDATOR, 0) amount := sdk.NewIntFromUint64(10000) - _, err := ts.TxCreateValidator(validator, amount) - require.Nil(t, err) + ts.TxCreateValidator(validator, amount) provider, _ := ts.GetAccount(common.PROVIDER, 0) - err = ts.StakeProvider(provider.Addr.String(), ts.spec, amount.Int64()) + err := ts.StakeProvider(provider.Addr.String(), ts.spec, amount.Int64()) require.Nil(t, err) ts.AdvanceEpoch() @@ -175,12 +176,11 @@ func TestUnbondUniformProviders(t *testing.T) { // create validator and providers validator, _ := ts.GetAccount(common.VALIDATOR, 0) amount := sdk.NewIntFromUint64(10000) - _, err := ts.TxCreateValidator(validator, amount) - require.Nil(t, err) + ts.TxCreateValidator(validator, amount) for i := 0; i < 5; i++ { provider, _ := ts.GetAccount(common.PROVIDER, i) - err = ts.StakeProvider(provider.Addr.String(), ts.spec, amount.Int64()) + err := ts.StakeProvider(provider.Addr.String(), ts.spec, amount.Int64()) require.Nil(t, err) } @@ -188,7 +188,7 @@ func TestUnbondUniformProviders(t *testing.T) { // delegate to validator (automatically delegates to empty provider) delegatorAcc, delegator := ts.GetAccount(common.CONSUMER, 0) - _, err = ts.TxDelegateValidator(delegatorAcc, validator, sdk.NewInt(210)) + _, err := ts.TxDelegateValidator(delegatorAcc, validator, sdk.NewInt(210)) require.Nil(t, err) // redelegate from empty provider to all providers with fixed amounts @@ -237,45 +237,104 @@ func TestUnbondUniformProviders(t *testing.T) { require.True(t, diff.IsZero()) } -// TestValidatorSlash checks that after a validator gets slashed, the delegators' providers -// get slashed as expected (by an equal amount to preserve the validators-providers delegation balance) func TestValidatorSlash(t *testing.T) { + ts := newTester(t) + _, _ = ts.AddAccount(common.VALIDATOR, 0, testBalance*1000000000) + amount := sdk.NewIntFromUint64(1000000000) + + // create valAcc and providers + valAcc, _ := ts.GetAccount(common.VALIDATOR, 0) + ts.TxCreateValidator(valAcc, amount) + ts.AdvanceEpoch() + + // sanity check: validator should have 1000000000 tokens + val := ts.GetValidator(valAcc.Addr) + require.Equal(t, amount, val.Tokens) + + // sanity check: empty provider should have delegation of 1000000000 tokens + resQ, err := ts.QueryDualstakingProviderDelegators(dualstakingkeeper.EMPTY_PROVIDER, false) + require.Nil(t, err) + require.Equal(t, 1, len(resQ.Delegations)) + require.Equal(t, amount, resQ.Delegations[0].Amount.Amount) + + // slash 0.6*ConsensusPowerTokens = 0.6*100000 from the validator and check balance + expectedTokensToBurn := ts.SlashValidator(valAcc, sdk.NewDecWithPrec(6, 1), 1, ts.Ctx.BlockHeight()) // fraction = 0.6 + + // sanity check: validator should have 0.6*ConsensusPowerTokens = 0.6*100000 + val = ts.GetValidator(valAcc.Addr) + require.Equal(t, amount.Sub(expectedTokensToBurn), val.Tokens) + + // check: the only delegation should be validator delegated to empty provider + // the delegation amount should be original_amount(=1000000000) - expectedTokensToBurn + res, err := ts.QueryDualstakingDelegatorProviders(valAcc.Addr.String(), true) + require.Nil(t, err) + require.Equal(t, 1, len(res.Delegations)) // empty provider + require.Equal(t, amount.Sub(expectedTokensToBurn), res.Delegations[0].Amount.Amount) + + // sanity check: verify that provider-validator delegations are equal + diff, err := ts.Keepers.Dualstaking.VerifyDelegatorBalance(ts.Ctx, valAcc.Addr) + require.Nil(t, err) + require.True(t, diff.IsZero()) +} + +// TestValidatorAndProvidersSlash checks that after a validator gets slashed, the delegators' providers +// get slashed as expected (by an equal amount to preserve the validators-providers delegation balance) +func TestValidatorAndProvidersSlash(t *testing.T) { ts := newTester(t) ts.addValidators(1) ts.addProviders(5) - ts.addClients(1) - amount := sdk.NewIntFromUint64(10000) + _, _ = ts.AddAccount(common.CONSUMER, 0, testBalance*1000000000) - // create validator and providers - validator, _ := ts.GetAccount(common.VALIDATOR, 0) - _, err := ts.TxCreateValidator(validator, amount) - require.Nil(t, err) + power := int64(1) + consensusPowerTokens := ts.Keepers.StakingKeeper.TokensFromConsensusPower(ts.Ctx, power) + stake := consensusPowerTokens.MulRaw(10) + + // create valAcc and providers + valAcc, _ := ts.GetAccount(common.VALIDATOR, 0) + ts.TxCreateValidator(valAcc, stake) for i := 0; i < 5; i++ { provider, _ := ts.GetAccount(common.PROVIDER, i) - err := ts.StakeProvider(provider.Addr.String(), ts.spec, amount.Int64()) + err := ts.StakeProvider(provider.Addr.String(), ts.spec, stake.Int64()) require.Nil(t, err) } - ts.AdvanceEpoch() + // sanity check: validator should have 1000000000*6 tokens (initial stake + 5 provider stakes via dualstaking) + expectedValidatorTokens := stake.MulRaw(6) + val := ts.GetValidator(valAcc.Addr) + require.Equal(t, expectedValidatorTokens, val.Tokens) + // delegate to validator (automatically delegates to empty provider) delegatorAcc, delegator := ts.GetAccount(common.CONSUMER, 0) - _, err = ts.TxDelegateValidator(delegatorAcc, validator, sdk.NewInt(250)) + _, err := ts.TxDelegateValidator(delegatorAcc, valAcc, consensusPowerTokens.MulRaw(250)) require.Nil(t, err) + delegatorValDelegations := ts.Keepers.StakingKeeper.GetAllDelegatorDelegations(ts.Ctx, delegatorAcc.Addr) + require.Equal(t, 1, len(delegatorValDelegations)) + val = ts.GetValidator(valAcc.Addr) + require.Equal(t, consensusPowerTokens.MulRaw(250), val.TokensFromShares(delegatorValDelegations[0].Shares).TruncateInt()) + expectedValidatorTokens = expectedValidatorTokens.Add(consensusPowerTokens.MulRaw(250)) + ts.AdvanceEpoch() // advance epoch to apply the empty provider delegation (that happens automatically when delegating to the validator) - // redelegate from empty provider to all providers with fixed amounts + // sanity check: empty provider should have val_stake(=1000000000) + 250*consensusPowerTokens tokens in two delegations + resQ, err := ts.QueryDualstakingProviderDelegators(dualstakingkeeper.EMPTY_PROVIDER, false) + require.Nil(t, err) + require.Equal(t, 2, len(resQ.Delegations)) + require.Equal(t, stake.Add(consensusPowerTokens.MulRaw(250)), resQ.Delegations[0].Amount.Amount.Add(resQ.Delegations[1].Amount.Amount)) + + // redelegate all the empty provider's funds to all providers with fixed amounts redelegateAmts := []math.Int{ - sdk.NewInt(15), - sdk.NewInt(15), - sdk.NewInt(55), - sdk.NewInt(60), - sdk.NewInt(70), + consensusPowerTokens.MulRaw(15), + consensusPowerTokens.MulRaw(15), + consensusPowerTokens.MulRaw(55), + consensusPowerTokens.MulRaw(60), + consensusPowerTokens.MulRaw(105), } var providers []string for i := 0; i < 5; i++ { _, provider := ts.GetAccount(common.PROVIDER, i) providers = append(providers, provider) + _, err = ts.TxDualstakingRedelegate(delegatorAcc.Addr.String(), dualstakingkeeper.EMPTY_PROVIDER, provider, @@ -283,45 +342,79 @@ func TestValidatorSlash(t *testing.T) { ts.spec.Index, sdk.NewCoin(epochstoragetypes.TokenDenom, redelegateAmts[i])) require.Nil(t, err) + ts.AdvanceEpoch() + + // verify delegation is applied (should be 2 delegations: self delegation + redelegate amount) + resQ, err = ts.QueryDualstakingProviderDelegators(provider, false) + require.Nil(t, err) + require.Equal(t, 2, len(resQ.Delegations)) + require.Equal(t, redelegateAmts[i].Add(stake), resQ.Delegations[0].Amount.Amount.Add(resQ.Delegations[1].Amount.Amount)) } + // since we emptied empty_provider, we wait until its delegation entry in the fixation + // store is actually deleted (and not just marked for deletion) + ts.AdvanceBlockUntilStale() + // sanity check: redelegate from provider0 to provider1 and check delegations balance - _, err = ts.TxDualstakingRedelegate(delegator, providers[0], providers[1], ts.spec.Index, ts.spec.Index, sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(5))) + _, err = ts.TxDualstakingRedelegate(delegator, providers[0], providers[1], ts.spec.Index, ts.spec.Index, sdk.NewCoin(epochstoragetypes.TokenDenom, consensusPowerTokens.MulRaw(5))) require.Nil(t, err) + ts.AdvanceEpoch() // apply redelegation diff, err := ts.Keepers.Dualstaking.VerifyDelegatorBalance(ts.Ctx, delegatorAcc.Addr) require.Nil(t, err) require.True(t, diff.IsZero()) // sanity check: unbond some of provider2's funds and check delegations balance - _, err = ts.TxDualstakingUnbond(delegator, providers[2], ts.spec.Index, sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(5))) + _, err = ts.TxDualstakingUnbond(delegator, providers[2], ts.spec.Index, sdk.NewCoin(epochstoragetypes.TokenDenom, consensusPowerTokens.MulRaw(5))) require.Nil(t, err) + ts.AdvanceEpoch() // apply unbond diff, err = ts.Keepers.Dualstaking.VerifyDelegatorBalance(ts.Ctx, delegatorAcc.Addr) require.Nil(t, err) require.True(t, diff.IsZero()) + expectedValidatorTokens = expectedValidatorTokens.Sub(consensusPowerTokens.MulRaw(5)) + + // get the delegator's provider delegations before the slash + res, err := ts.QueryDualstakingDelegatorProviders(delegator, true) + require.Nil(t, err) + delegationsBeforeSlash := res.Delegations + slices.SortFunc(delegationsBeforeSlash, func(i, j dualstakingtypes.Delegation) bool { + return i.Amount.IsLT(j.Amount) + }) + + // slash consensusPowerTokens*0.6 tokens from the validator and check balance + expectedTokensSlashed := ts.SlashValidator(valAcc, sdk.NewDecWithPrec(6, 1), power, ts.Ctx.BlockHeight()) // fraction = 0.6 + expectedValidatorTokens = expectedValidatorTokens.Sub(expectedTokensSlashed) + val = ts.GetValidator(valAcc.Addr) + require.Equal(t, expectedValidatorTokens, val.Tokens) + + // hard coded effective fraction of slash + fraction := sdk.MustNewDecFromStr("0.001967213114754099") - // slash 24*5 tokens from the validator and check balance - valConsAddr := sdk.GetConsAddress(validator.ConsKey.PubKey()) - ts.Keepers.SlashingKeeper.Slash(ts.Ctx, valConsAddr, sdk.NewDecWithPrec(6, 1), 1, ts.Ctx.BlockHeight()) // fraction = 120/200 = 0.6 + // both the validator and providers have a single delegation that was created by their + // self delegation. Check that the new amount after slash is (1-fraction) * old_amount + res, err = ts.QueryDualstakingDelegatorProviders(valAcc.Addr.String(), true) + require.Nil(t, err) + require.Len(t, res.Delegations, 1) + require.Equal(t, sdk.OneDec().Sub(fraction).MulInt(stake).RoundInt(), res.Delegations[0].Amount.Amount) + + for _, p := range providers { + res, err = ts.QueryDualstakingDelegatorProviders(p, true) + require.Nil(t, err) + require.Len(t, res.Delegations, 1) + require.Equal(t, sdk.OneDec().Sub(fraction).MulInt(stake).RoundInt(), res.Delegations[0].Amount.Amount) + } - res, err := ts.QueryDualstakingDelegatorProviders(delegator, false) + // the total token to deduct from the delegator's provider delegations is: + // total_providers_delegations * fraction = (245 * consensus_power_tokens) * fraction + res, err = ts.QueryDualstakingDelegatorProviders(delegator, true) require.Nil(t, err) + require.Len(t, res.Delegations, 5) // 5 providers from redelegations + totalDelegations := math.ZeroInt() for _, d := range res.Delegations { - switch d.Provider { - case providers[0]: - require.True(t, d.Amount.Amount.IsZero()) - case providers[1]: - require.True(t, d.Amount.Amount.IsZero()) - case providers[2]: - require.Equal(t, int64(21), d.Amount.Amount.Int64()) - case providers[3]: - require.Equal(t, int64(31), d.Amount.Amount) - case providers[4]: - require.Equal(t, int64(38), d.Amount.Amount) // highest delegation is decreased by uniform amount + remainder - default: - require.FailNow(t, "unexpected provider in delegations") - } + totalDelegations = totalDelegations.Add(d.Amount.Amount) } + require.Equal(t, sdk.OneDec().Sub(fraction).MulInt(consensusPowerTokens.MulRaw(245)).TruncateInt(), totalDelegations) + // verify once again that the delegator's delegations balance is preserved diff, err = ts.Keepers.Dualstaking.VerifyDelegatorBalance(ts.Ctx, delegatorAcc.Addr) require.Nil(t, err) require.True(t, diff.IsZero()) @@ -337,14 +430,13 @@ func TestCancelUnbond(t *testing.T) { // create validator and providers validator, _ := ts.GetAccount(common.VALIDATOR, 0) - _, err := ts.TxCreateValidator(validator, amount) - require.Nil(t, err) + ts.TxCreateValidator(validator, amount) ts.AdvanceEpoch() // delegate to validator (automatically delegates to empty provider) delegator, _ := ts.GetAccount(common.CONSUMER, 0) - _, err = ts.TxDelegateValidator(delegator, validator, sdk.NewInt(250)) + _, err := ts.TxDelegateValidator(delegator, validator, sdk.NewInt(250)) require.Nil(t, err) // unbond and advance blocks @@ -363,3 +455,84 @@ func TestCancelUnbond(t *testing.T) { require.Nil(t, err) require.True(t, diff.IsZero()) } + +// TestHooksRandomDelegations creates lots of random delegations through the dualstaking module +// the goal is to verify that all redelegations that are triggered from dualstaking delegation TX +// succeed +func TestHooksRandomDelegations(t *testing.T) { + ts := newTester(t) + _, _ = ts.AddAccount(common.VALIDATOR, 0, testBalance*1000000000) + _, _ = ts.AddAccount(common.PROVIDER, 0, testBalance*1000000000) + _, _ = ts.AddAccount(common.CONSUMER, 0, testBalance*1000000000) + amount := sdk.NewIntFromUint64(1000) + + // create validatorAcc and providers + validatorAcc, _ := ts.GetAccount(common.VALIDATOR, 0) + ts.TxCreateValidator(validatorAcc, amount) + + providerAcc, provider := ts.GetAccount(common.PROVIDER, 0) + err := ts.StakeProvider(providerAcc.Addr.String(), ts.spec, amount.Int64()) + require.Nil(t, err) + + ts.AdvanceEpoch() + + r := rand.New(rand.NewSource(time.Now().UnixNano())) + delegations := r.Perm(int(amount.Int64())) // array of 1000 elements with random number between [0,10000) + + prevDelegatorAcc, prevDelegator := ts.GetAccount(common.CONSUMER, 0) + + for i, d := range delegations { + _, _ = ts.AddAccount(common.CONSUMER, i+1, testBalance*1000000000) + delegatorAcc, delegator := ts.GetAccount(common.CONSUMER, i+1) + d += 1 + d *= 1000000037 // avoid delegating zero + if d%2 == 0 { + delegatorAcc = prevDelegatorAcc + delegator = prevDelegator + } + _, err := ts.TxDualstakingDelegate(delegator, provider, ts.spec.Index, sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(int64(d)))) + if err == nil { + fmt.Printf("%v: delegated %v\n", strconv.Itoa(i), strconv.Itoa(d)) + } else { + fmt.Printf("%v: failed delegating %v. err: %s\n", strconv.Itoa(i), strconv.Itoa(d), err.Error()) + } + require.Nil(t, err) + + _, found := ts.Keepers.StakingKeeper.GetDelegation(ts.Ctx, delegatorAcc.Addr, sdk.ValAddress(validatorAcc.Addr)) + require.True(t, found) + + valConsAddr := sdk.GetConsAddress(validatorAcc.ConsKey.PubKey()) + ts.Keepers.SlashingKeeper.Slash(ts.Ctx, valConsAddr, sdk.NewDecWithPrec(1, 1), 1, ts.Ctx.BlockHeight()) + } +} + +// TestNotRoundedShares checks that the delegate TX works in a specific case in which it +// failed in the past due to not-rounded shares value +func TestNotRoundedShares(t *testing.T) { + ts := newTester(t) + _, _ = ts.AddAccount(common.VALIDATOR, 0, testBalance*10000000000) + _, _ = ts.AddAccount(common.PROVIDER, 0, testBalance*10000000000) + _, _ = ts.AddAccount(common.CONSUMER, 0, testBalance*10000000000) + delAmount := sdk.NewIntFromUint64(1000000000000) + + delegatorAcc, delegator := ts.GetAccount(common.CONSUMER, 0) + + validatorAcc, _ := ts.GetAccount(common.VALIDATOR, 0) + ts.TxCreateValidator(validatorAcc, math.NewIntFromUint64(4495000000001)) + + val, found := ts.Keepers.StakingKeeper.GetValidator(ts.Ctx, sdk.ValAddress(validatorAcc.Addr)) + require.True(t, found) + val.DelegatorShares = sdk.MustNewDecFromStr("4540404040405.050505050505050505") + ts.Keepers.StakingKeeper.SetValidator(ts.Ctx, val) + + providerAcc, provider := ts.GetAccount(common.PROVIDER, 0) + err := ts.StakeProvider(providerAcc.Addr.String(), ts.spec, delAmount.Int64()) + require.Nil(t, err) + + shares := sdk.MustNewDecFromStr("1010101010101.010101010101010101") + require.Nil(t, err) + ts.Keepers.StakingKeeper.SetDelegation(ts.Ctx, stakingtypes.NewDelegation(delegatorAcc.Addr, sdk.ValAddress(validatorAcc.Addr), shares)) + + _, err = ts.TxDualstakingDelegate(delegator, provider, ts.spec.Index, sdk.NewCoin(epochstoragetypes.TokenDenom, delAmount)) + require.Nil(t, err) +} From afe1e5a5c4efa3a70bb8b3e5723e8795ca6f234e Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Wed, 29 Nov 2023 04:13:26 -0500 Subject: [PATCH 06/85] Fix broken stuff --- app/app.go | 2 ++ testutil/keeper/dualstaking.go | 2 +- testutil/keeper/keepers_init.go | 4 ++-- testutil/keeper/plan.go | 3 ++- testutil/keeper/spec.go | 1 + testutil/keeper/subscription.go | 2 +- x/plans/keeper/keeper.go | 3 +++ x/plans/keeper/plan.go | 4 ++++ x/plans/types/expected_keepers.go | 4 ++++ x/plans/types/plan.go | 8 +------- x/spec/keeper/keeper.go | 10 ++++++---- 11 files changed, 27 insertions(+), 16 deletions(-) diff --git a/app/app.go b/app/app.go index 3576a6010a..09a413ac69 100644 --- a/app/app.go +++ b/app/app.go @@ -412,6 +412,7 @@ func New( keys[specmoduletypes.StoreKey], keys[specmoduletypes.MemStoreKey], app.GetSubspace(specmoduletypes.ModuleName), + app.StakingKeeper, ) specModule := specmodule.NewAppModule(appCodec, app.SpecKeeper, app.AccountKeeper, app.BankKeeper) @@ -443,6 +444,7 @@ func New( app.EpochstorageKeeper, app.SpecKeeper, app.FixationStoreKeeper, + app.StakingKeeper, ) plansModule := plansmodule.NewAppModule(appCodec, app.PlansKeeper) diff --git a/testutil/keeper/dualstaking.go b/testutil/keeper/dualstaking.go index f2a81aaaf9..313ec888d1 100644 --- a/testutil/keeper/dualstaking.go +++ b/testutil/keeper/dualstaking.go @@ -67,7 +67,7 @@ func DualstakingKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { nil, &mockAccountKeeper{}, epochstorageKeeper, - speckeeper.NewKeeper(cdc, nil, nil, paramsSubspaceSpec), + speckeeper.NewKeeper(cdc, nil, nil, paramsSubspaceSpec, nil), fixationkeeper.NewKeeper(cdc, tsKeeper, epochstorageKeeper.BlocksToSaveRaw), ) diff --git a/testutil/keeper/keepers_init.go b/testutil/keeper/keepers_init.go index 40e4cfe276..d1c44d1b8c 100644 --- a/testutil/keeper/keepers_init.go +++ b/testutil/keeper/keepers_init.go @@ -225,11 +225,11 @@ func InitAllKeepers(t testing.TB) (*Servers, *Keepers, context.Context) { ks.BankKeeper = mockBankKeeper{} ks.StakingKeeper = *stakingkeeper.NewKeeper(cdc, stakingStoreKey, ks.AccountKeeper, ks.BankKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String()) ks.SlashingKeeper = slashingkeeper.NewKeeper(cdc, legacyCdc, slashingStoreKey, ks.StakingKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String()) - ks.Spec = *speckeeper.NewKeeper(cdc, specStoreKey, specMemStoreKey, specparamsSubspace) + ks.Spec = *speckeeper.NewKeeper(cdc, specStoreKey, specMemStoreKey, specparamsSubspace, ks.StakingKeeper) ks.Epochstorage = *epochstoragekeeper.NewKeeper(cdc, epochStoreKey, epochMemStoreKey, epochparamsSubspace, &ks.BankKeeper, &ks.AccountKeeper, ks.Spec, ks.StakingKeeper) ks.FixationStoreKeeper = fixationkeeper.NewKeeper(cdc, ks.TimerStoreKeeper, ks.Epochstorage.BlocksToSaveRaw) ks.Dualstaking = *dualstakingkeeper.NewKeeper(cdc, dualstakingStoreKey, dualstakingMemStoreKey, dualstakingparamsSubspace, &ks.BankKeeper, &ks.StakingKeeper, &ks.AccountKeeper, ks.Epochstorage, ks.Spec, ks.FixationStoreKeeper) - ks.Plans = *planskeeper.NewKeeper(cdc, plansStoreKey, plansMemStoreKey, plansparamsSubspace, ks.Epochstorage, ks.Spec, ks.FixationStoreKeeper) + ks.Plans = *planskeeper.NewKeeper(cdc, plansStoreKey, plansMemStoreKey, plansparamsSubspace, ks.Epochstorage, ks.Spec, ks.FixationStoreKeeper, ks.StakingKeeper) ks.Projects = *projectskeeper.NewKeeper(cdc, projectsStoreKey, projectsMemStoreKey, projectsparamsSubspace, ks.Epochstorage, ks.FixationStoreKeeper) ks.Protocol = *protocolkeeper.NewKeeper(cdc, protocolStoreKey, protocolMemStoreKey, protocolparamsSubspace) ks.Subscription = *subscriptionkeeper.NewKeeper(cdc, subscriptionStoreKey, subscriptionMemStoreKey, subscriptionparamsSubspace, &ks.BankKeeper, &ks.AccountKeeper, &ks.Epochstorage, ks.Projects, ks.Plans, ks.Dualstaking, ks.FixationStoreKeeper, ks.TimerStoreKeeper, ks.StakingKeeper) diff --git a/testutil/keeper/plan.go b/testutil/keeper/plan.go index 5a682cf184..d4714b2571 100644 --- a/testutil/keeper/plan.go +++ b/testutil/keeper/plan.go @@ -63,8 +63,9 @@ func PlanKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { memStoreKey, paramsSubspace, epochstorageKeeper, - speckeeper.NewKeeper(cdc, nil, nil, paramsSubspaceSpec), + speckeeper.NewKeeper(cdc, nil, nil, paramsSubspaceSpec, nil), fixationkeeper.NewKeeper(cdc, timerstorekeeper.NewKeeper(cdc), epochstorageKeeper.BlocksToSaveRaw), + nil, ) ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) diff --git a/testutil/keeper/spec.go b/testutil/keeper/spec.go index 881a003b23..d6c828cc59 100644 --- a/testutil/keeper/spec.go +++ b/testutil/keeper/spec.go @@ -56,6 +56,7 @@ func specKeeper() (*keeper.Keeper, sdk.Context, error) { storeKey, memStoreKey, paramsSubspace, + nil, ) ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) diff --git a/testutil/keeper/subscription.go b/testutil/keeper/subscription.go index 2ee1abaf44..1ce1dc8ebb 100644 --- a/testutil/keeper/subscription.go +++ b/testutil/keeper/subscription.go @@ -77,7 +77,7 @@ func SubscriptionKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { nil, epochstorageKeeper, projectskeeper.NewKeeper(cdc, nil, nil, paramsSubspaceProjects, nil, fsKeeper), - planskeeper.NewKeeper(cdc, nil, nil, paramsSubspacePlans, nil, nil, fsKeeper), + planskeeper.NewKeeper(cdc, nil, nil, paramsSubspacePlans, nil, nil, fsKeeper, nil), dualstakingkeeper.NewKeeper(cdc, nil, nil, paramsSubspace, nil, nil, mockAccountKeeper{}, nil, nil, fsKeeper), fsKeeper, tsKeeper, diff --git a/x/plans/keeper/keeper.go b/x/plans/keeper/keeper.go index c27fe20c2c..6a83fa5150 100644 --- a/x/plans/keeper/keeper.go +++ b/x/plans/keeper/keeper.go @@ -21,6 +21,7 @@ type ( epochstorageKeeper types.EpochStorageKeeper specKeeper types.SpecKeeper + stakingKeeper types.StakingKeeper plansFS fixationtypes.FixationStore } @@ -34,6 +35,7 @@ func NewKeeper( epochstorageKeeper types.EpochStorageKeeper, specKeeper types.SpecKeeper, fixationStoreKeeper types.FixationStoreKeeper, + stakingKeeper types.StakingKeeper, ) *Keeper { // set KeyTable if it has not already been set if !ps.HasKeyTable() { @@ -48,6 +50,7 @@ func NewKeeper( epochstorageKeeper: epochstorageKeeper, plansFS: fs, specKeeper: specKeeper, + stakingKeeper: stakingKeeper, } } diff --git a/x/plans/keeper/plan.go b/x/plans/keeper/plan.go index 84b38ab8d7..5fa7641815 100644 --- a/x/plans/keeper/plan.go +++ b/x/plans/keeper/plan.go @@ -88,6 +88,10 @@ func (k Keeper) GetAllPlanIndices(ctx sdk.Context) (val []string) { } func (k Keeper) ValidatePlanFields(ctx sdk.Context, planToAdd *types.Plan) error { + if planToAdd.Price.Denom != k.stakingKeeper.BondDenom(ctx) { + return fmt.Errorf("wrong denom type: %s", planToAdd.Price.Denom) + } + for _, chainPolicy := range planToAdd.PlanPolicy.ChainPolicies { specID := chainPolicy.ChainId if specID == types.WILDCARD_CHAIN_POLICY && len(chainPolicy.Apis) == 0 && len(chainPolicy.Requirements) == 0 { diff --git a/x/plans/types/expected_keepers.go b/x/plans/types/expected_keepers.go index 6987e15e4b..27e407e7c6 100644 --- a/x/plans/types/expected_keepers.go +++ b/x/plans/types/expected_keepers.go @@ -19,3 +19,7 @@ type SpecKeeper interface { type FixationStoreKeeper interface { NewFixationStore(storeKey storetypes.StoreKey, prefix string) *fixationstoretypes.FixationStore } + +type StakingKeeper interface { + BondDenom(ctx sdk.Context) string +} diff --git a/x/plans/types/plan.go b/x/plans/types/plan.go index 2191065186..342b2e548a 100644 --- a/x/plans/types/plan.go +++ b/x/plans/types/plan.go @@ -15,14 +15,8 @@ func (p Plan) ValidatePlan() error { return sdkerrors.Wrap(ErrInvalidPlanIndex, "plan's index can't be empty") } - // TODO: YAROM - - // validate denom is ulava - if p.GetPrice().Denom != tokenDenom { - return sdkerrors.Wrap(ErrInvalidPlanPrice, "plan's price denom is not in ulava") - } // check that the plan's price is non-zero - if p.GetPrice().IsEqual(sdk.NewCoin(tokenDenom, sdk.ZeroInt())) { + if p.GetPrice().Amount.IsZero() { return sdkerrors.Wrap(ErrInvalidPlanPrice, "plan's price can't be zero") } diff --git a/x/spec/keeper/keeper.go b/x/spec/keeper/keeper.go index 68fb720c4f..45ac8abe7f 100644 --- a/x/spec/keeper/keeper.go +++ b/x/spec/keeper/keeper.go @@ -29,6 +29,7 @@ func NewKeeper( storeKey, memKey storetypes.StoreKey, ps paramtypes.Subspace, + stakingKeeper types.StakingKeeper, ) *Keeper { // set KeyTable if it has not already been set if !ps.HasKeyTable() { @@ -36,10 +37,11 @@ func NewKeeper( } return &Keeper{ - cdc: cdc, - storeKey: storeKey, - memKey: memKey, - paramstore: ps, + cdc: cdc, + storeKey: storeKey, + memKey: memKey, + paramstore: ps, + stakingKeeper: stakingKeeper, } } From f5170f8671e631634d231630a68b8f6752b1b4f3 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Wed, 29 Nov 2023 04:48:17 -0500 Subject: [PATCH 07/85] Fix testutil --- testutil/keeper/subscription.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/testutil/keeper/subscription.go b/testutil/keeper/subscription.go index 1ce1dc8ebb..9bd12c9168 100644 --- a/testutil/keeper/subscription.go +++ b/testutil/keeper/subscription.go @@ -12,7 +12,6 @@ import ( storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" typesparams "github.com/cosmos/cosmos-sdk/x/params/types" - stakgingKeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" dualstakingkeeper "github.com/lavanet/lava/x/dualstaking/keeper" epochstoragekeeper "github.com/lavanet/lava/x/epochstorage/keeper" fixationkeeper "github.com/lavanet/lava/x/fixationstore/keeper" @@ -81,7 +80,7 @@ func SubscriptionKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { dualstakingkeeper.NewKeeper(cdc, nil, nil, paramsSubspace, nil, nil, mockAccountKeeper{}, nil, nil, fsKeeper), fsKeeper, tsKeeper, - stakgingKeeper.NewKeeper(cdc, nil, nil, nil, ""), + nil, ) ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) From db3490f110350025559dfb5de3a46e6c3d240a7b Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Wed, 29 Nov 2023 11:06:39 -0500 Subject: [PATCH 08/85] Remove plain string output from lavad q pairing providers commands --- proto/lavanet/lava/pairing/query.proto | 1 - x/pairing/keeper/grpc_query_providers.go | 10 +- x/pairing/types/query.pb.go | 293 ++++++++++------------- 3 files changed, 122 insertions(+), 182 deletions(-) diff --git a/proto/lavanet/lava/pairing/query.proto b/proto/lavanet/lava/pairing/query.proto index bc5fa7316c..1f112f4140 100644 --- a/proto/lavanet/lava/pairing/query.proto +++ b/proto/lavanet/lava/pairing/query.proto @@ -119,7 +119,6 @@ message QueryProvidersRequest { message QueryProvidersResponse { repeated lavanet.lava.epochstorage.StakeEntry stakeEntry = 1 [(gogoproto.nullable) = false]; - string output = 2; } message QueryGetPairingRequest { diff --git a/x/pairing/keeper/grpc_query_providers.go b/x/pairing/keeper/grpc_query_providers.go index 6dc5066bfb..7c63b50450 100644 --- a/x/pairing/keeper/grpc_query_providers.go +++ b/x/pairing/keeper/grpc_query_providers.go @@ -2,7 +2,6 @@ package keeper import ( "context" - "fmt" sdk "github.com/cosmos/cosmos-sdk/types" epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" @@ -36,12 +35,5 @@ func (k Keeper) Providers(goCtx context.Context, req *types.QueryProvidersReques stakeEntries = stakeEntriesNoFrozen } - foundAndActive, _, _ := k.specKeeper.IsSpecFoundAndActive(ctx, req.ChainID) - unstakingStakeStorage, found := k.epochStorageKeeper.GetStakeStorageUnstake(ctx) - if !found { - unstakingStakeStorage = epochstoragetypes.StakeStorage{} - } - outputStr := fmt.Sprintf("Staked Providers Query Output:\nChainID: %s Enabled: %t Current Block: %d\nStaked Providers:\n%v\nUnstaking Providers:\n%v\n--------------------------------------\n", req.ChainID, foundAndActive, ctx.BlockHeight(), stakeEntries, unstakingStakeStorage.StakeEntries) - - return &types.QueryProvidersResponse{StakeEntry: stakeEntries, Output: outputStr}, nil + return &types.QueryProvidersResponse{StakeEntry: stakeEntries}, nil } diff --git a/x/pairing/types/query.pb.go b/x/pairing/types/query.pb.go index 9db931cf3e..2cae9c39d1 100644 --- a/x/pairing/types/query.pb.go +++ b/x/pairing/types/query.pb.go @@ -172,7 +172,6 @@ func (m *QueryProvidersRequest) GetShowFrozen() bool { type QueryProvidersResponse struct { StakeEntry []types.StakeEntry `protobuf:"bytes,1,rep,name=stakeEntry,proto3" json:"stakeEntry"` - Output string `protobuf:"bytes,2,opt,name=output,proto3" json:"output,omitempty"` } func (m *QueryProvidersResponse) Reset() { *m = QueryProvidersResponse{} } @@ -215,13 +214,6 @@ func (m *QueryProvidersResponse) GetStakeEntry() []types.StakeEntry { return nil } -func (m *QueryProvidersResponse) GetOutput() string { - if m != nil { - return m.Output - } - return "" -} - type QueryGetPairingRequest struct { ChainID string `protobuf:"bytes,1,opt,name=chainID,proto3" json:"chainID,omitempty"` Client string `protobuf:"bytes,2,opt,name=client,proto3" json:"client,omitempty"` @@ -1820,130 +1812,130 @@ func init() { func init() { proto.RegisterFile("lavanet/lava/pairing/query.proto", fileDescriptor_9e149ce9d21da0d8) } var fileDescriptor_9e149ce9d21da0d8 = []byte{ - // 1968 bytes of a gzipped FileDescriptorProto + // 1956 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x59, 0xdd, 0x6f, 0xdc, 0x58, 0x15, 0xaf, 0x27, 0x1f, 0x4d, 0x4e, 0x9b, 0xdd, 0xea, 0x6e, 0x92, 0x26, 0x26, 0x9b, 0xa6, 0xb7, 0x1f, 0x9b, 0xd0, 0x30, 0xde, 0x4c, 0x3f, 0x36, 0xea, 0x17, 0x24, 0xfd, 0xa2, 0x25, 0xb0, 0xe9, - 0x84, 0xf0, 0xc0, 0x8b, 0xe5, 0x78, 0xee, 0x4c, 0xdc, 0x78, 0x6c, 0xd7, 0xbe, 0xce, 0x26, 0x8c, - 0x06, 0x10, 0x88, 0xd7, 0x15, 0x12, 0xcb, 0x03, 0x12, 0x8f, 0x2b, 0x10, 0x0f, 0xf0, 0x8e, 0xc4, - 0x1b, 0x02, 0xed, 0x03, 0x42, 0x2b, 0xf5, 0x85, 0x07, 0x40, 0xa8, 0xe5, 0x0f, 0x41, 0xbe, 0xf7, - 0x78, 0xc6, 0x9e, 0x78, 0x3c, 0x33, 0x4d, 0xc4, 0x4b, 0x9b, 0x6b, 0x9f, 0x8f, 0xdf, 0xf9, 0x9d, - 0x7b, 0xef, 0x39, 0xc7, 0x03, 0x0b, 0xb6, 0xb1, 0x6f, 0x38, 0x8c, 0x6b, 0xd1, 0xff, 0x9a, 0x67, - 0x58, 0xbe, 0xe5, 0xd4, 0xb4, 0x97, 0x21, 0xf3, 0x0f, 0x8b, 0x9e, 0xef, 0x72, 0x97, 0x4c, 0xa2, - 0x44, 0x31, 0xfa, 0xbf, 0x88, 0x12, 0xea, 0x64, 0xcd, 0xad, 0xb9, 0x42, 0x40, 0x8b, 0xfe, 0x92, - 0xb2, 0xea, 0x5c, 0xcd, 0x75, 0x6b, 0x36, 0xd3, 0x0c, 0xcf, 0xd2, 0x0c, 0xc7, 0x71, 0xb9, 0xc1, - 0x2d, 0xd7, 0x09, 0xf0, 0xed, 0x57, 0x4d, 0x37, 0xa8, 0xbb, 0x81, 0xb6, 0x63, 0x04, 0x4c, 0xba, - 0xd0, 0xf6, 0x57, 0x76, 0x18, 0x37, 0x56, 0x34, 0xcf, 0xa8, 0x59, 0x8e, 0x10, 0x46, 0xd9, 0x8b, - 0x99, 0xb8, 0x3c, 0xc3, 0x37, 0xea, 0xb1, 0xb9, 0xa5, 0x4c, 0x11, 0xe6, 0xb9, 0xe6, 0xae, 0xee, - 0x19, 0x87, 0x75, 0xe6, 0xf0, 0x58, 0x74, 0x2e, 0x25, 0x1a, 0x78, 0xcc, 0x14, 0xff, 0xe0, 0xdb, - 0x0b, 0x69, 0x43, 0xb6, 0xe1, 0x04, 0x9a, 0xe7, 0xda, 0x96, 0x89, 0x14, 0xa8, 0xd7, 0xb3, 0xc1, - 0xf8, 0xee, 0xbe, 0x55, 0x61, 0x7e, 0xec, 0x4c, 0x0f, 0xb8, 0xeb, 0x1b, 0x35, 0x86, 0x4a, 0x6b, - 0x99, 0x4a, 0xa1, 0x63, 0xbd, 0x0c, 0x59, 0xa7, 0x8a, 0x6e, 0xda, 0x56, 0xb4, 0x8c, 0x4d, 0xa2, - 0x89, 0x6b, 0x29, 0x13, 0x22, 0x32, 0x54, 0xd0, 0x02, 0x6e, 0xec, 0x31, 0x9d, 0x39, 0x3c, 0xce, - 0x93, 0xba, 0x9c, 0x8e, 0x31, 0xdc, 0x09, 0x4c, 0xdf, 0xf2, 0x22, 0x4a, 0x53, 0x0b, 0x94, 0xbe, - 0x94, 0x46, 0xe7, 0xbb, 0x2f, 0x98, 0xc9, 0x83, 0xf8, 0x0f, 0x29, 0x44, 0x27, 0x81, 0x3c, 0x8f, - 0xd2, 0xb4, 0x29, 0x68, 0x2f, 0xb3, 0x97, 0x21, 0x0b, 0x38, 0x7d, 0x0e, 0xef, 0xa5, 0x9e, 0x06, - 0x9e, 0xeb, 0x04, 0x8c, 0xdc, 0x86, 0x51, 0x99, 0x9e, 0x19, 0x65, 0x41, 0x59, 0x3c, 0x53, 0x9a, - 0x2b, 0x66, 0x6d, 0x9c, 0xa2, 0xd4, 0x5a, 0x1f, 0xfe, 0xe2, 0xdf, 0x17, 0x4e, 0x95, 0x51, 0x83, - 0x3e, 0x87, 0x29, 0x69, 0x12, 0xe3, 0x8f, 0x7d, 0x91, 0x19, 0x38, 0x6d, 0xee, 0x1a, 0x96, 0xf3, - 0xf4, 0xa1, 0xb0, 0x3a, 0x5e, 0x8e, 0x97, 0x64, 0x1e, 0x20, 0xd8, 0x75, 0x3f, 0x79, 0xec, 0xbb, - 0x3f, 0x60, 0xce, 0x4c, 0x61, 0x41, 0x59, 0x1c, 0x2b, 0x27, 0x9e, 0xd0, 0x26, 0x4c, 0x77, 0x9a, - 0x44, 0xa0, 0xdf, 0x02, 0x10, 0xec, 0x3d, 0x8a, 0xc8, 0x9b, 0x51, 0x16, 0x86, 0x16, 0xcf, 0x94, - 0xae, 0xa4, 0xc1, 0x26, 0xa9, 0x2e, 0x6e, 0xb5, 0x84, 0x11, 0x75, 0x42, 0x9d, 0x4c, 0xc3, 0xa8, - 0x1b, 0x72, 0x2f, 0xe4, 0x02, 0xc2, 0x78, 0x19, 0x57, 0xf4, 0x19, 0xba, 0x7f, 0xc2, 0xf8, 0xa6, - 0x8c, 0xbc, 0x77, 0x48, 0xd3, 0x30, 0x2a, 0xf7, 0x41, 0x6c, 0x4b, 0xae, 0xe8, 0xef, 0x0b, 0x70, - 0xfe, 0x88, 0x31, 0x0c, 0xe6, 0x29, 0x8c, 0xc7, 0x9b, 0x26, 0x78, 0x9b, 0x58, 0xda, 0xda, 0xe4, - 0x12, 0x4c, 0x98, 0xa1, 0xef, 0x47, 0xfb, 0x50, 0xe8, 0x08, 0x14, 0xc3, 0xe5, 0xb3, 0xf8, 0xf0, - 0x51, 0xf4, 0x8c, 0xac, 0xc2, 0x2c, 0xb7, 0xea, 0x4c, 0xb7, 0x59, 0x95, 0xeb, 0xdc, 0xd5, 0x1d, - 0x76, 0xc0, 0x75, 0xcc, 0xed, 0xcc, 0x90, 0x50, 0x98, 0x8a, 0x04, 0x36, 0x58, 0x95, 0x7f, 0xd7, - 0xfd, 0x0e, 0x3b, 0x88, 0x11, 0x93, 0x9b, 0x70, 0x3e, 0x3a, 0x73, 0xba, 0x6d, 0x04, 0x5c, 0x0f, - 0xbd, 0x8a, 0xc1, 0x59, 0x45, 0xdf, 0xb1, 0x5d, 0x73, 0x6f, 0x66, 0x58, 0xe8, 0x4d, 0x46, 0xaf, - 0x37, 0x8c, 0x80, 0x6f, 0xcb, 0x97, 0xeb, 0xd1, 0x3b, 0xb2, 0x02, 0x53, 0x42, 0x48, 0x77, 0xab, - 0x69, 0x67, 0x23, 0x42, 0x89, 0x88, 0x97, 0x1f, 0x57, 0x13, 0x9e, 0xe8, 0x8f, 0x60, 0x56, 0xd0, - 0xf5, 0x3d, 0xe6, 0x5b, 0xd5, 0xc3, 0xe3, 0xd2, 0x4f, 0x54, 0x18, 0x8b, 0x49, 0x12, 0x11, 0x8e, - 0x97, 0x5b, 0x6b, 0x32, 0x09, 0x23, 0xc9, 0x10, 0xe4, 0x82, 0x7e, 0xae, 0x80, 0x9a, 0x85, 0x00, - 0x73, 0x36, 0x09, 0x23, 0xfb, 0x86, 0x6d, 0x55, 0x04, 0x80, 0xb1, 0xb2, 0x5c, 0x90, 0x25, 0x38, - 0x17, 0x85, 0xc6, 0x2a, 0x7a, 0x3b, 0xa1, 0x92, 0xd0, 0x77, 0xe5, 0xf3, 0xd6, 0x4e, 0x26, 0x0b, - 0x70, 0xd6, 0x0c, 0x75, 0x8f, 0xf9, 0x98, 0x28, 0xe9, 0x1c, 0xcc, 0x70, 0x93, 0xf9, 0x32, 0x4d, - 0xef, 0x03, 0xe0, 0x51, 0xd6, 0xad, 0x8a, 0xa0, 0x6a, 0x5c, 0xa4, 0x3a, 0x7a, 0xf2, 0xb4, 0xf2, - 0x6c, 0x78, 0xac, 0x70, 0x6e, 0x88, 0x3e, 0x85, 0x95, 0x78, 0x5b, 0x6d, 0x8b, 0x6b, 0x69, 0x53, - 0xde, 0x4a, 0x5b, 0x72, 0xb3, 0x3c, 0x10, 0xe1, 0xc7, 0x5e, 0x63, 0xfe, 0x26, 0x61, 0xc4, 0x72, - 0x2a, 0xec, 0x00, 0xd9, 0x93, 0x0b, 0xfa, 0x17, 0x05, 0x4a, 0x83, 0xd8, 0x42, 0x26, 0x3e, 0x55, - 0x80, 0x86, 0x3d, 0xc5, 0xf1, 0x42, 0x59, 0xcd, 0xbe, 0x50, 0x7a, 0xbb, 0xc3, 0xad, 0xde, 0x87, - 0x27, 0xda, 0x40, 0x4a, 0xd6, 0x6c, 0xbb, 0x7f, 0x4a, 0x1e, 0x03, 0xb4, 0xeb, 0x17, 0x82, 0xbd, - 0x5a, 0x94, 0xc5, 0xae, 0x18, 0x15, 0xbb, 0xa2, 0xac, 0xa7, 0x58, 0xec, 0x8a, 0x9b, 0x46, 0x8d, - 0xa1, 0x6e, 0x39, 0xa1, 0x49, 0x3f, 0x2d, 0x20, 0x89, 0x7d, 0x7a, 0x1f, 0x94, 0xc4, 0xa1, 0xff, - 0x0f, 0x89, 0xe4, 0x49, 0x8a, 0x8f, 0x82, 0xe0, 0xe3, 0x83, 0x9e, 0x7c, 0xc8, 0x68, 0x52, 0x84, - 0xdc, 0x83, 0x2b, 0xad, 0x7b, 0x0f, 0x8d, 0xa7, 0x1d, 0xe7, 0x6f, 0xca, 0xcf, 0x14, 0xb8, 0xda, - 0x4b, 0x1f, 0x39, 0x7c, 0x01, 0xd3, 0x5e, 0xa6, 0x04, 0xa6, 0x73, 0xb9, 0x4b, 0x31, 0xcb, 0xd4, - 0x41, 0xaa, 0xba, 0x58, 0xa4, 0x2e, 0x46, 0xb5, 0x66, 0xdb, 0xf9, 0x51, 0x9d, 0xd4, 0xbe, 0xfa, - 0x57, 0xcc, 0x43, 0x8e, 0xc7, 0x3e, 0x78, 0x18, 0x3a, 0x59, 0x1e, 0x4e, 0x6e, 0x9b, 0xdc, 0x80, - 0xb9, 0x38, 0xcd, 0xe2, 0xf6, 0x43, 0x3f, 0x41, 0xfe, 0xee, 0xf0, 0xe0, 0xfd, 0x2e, 0x5a, 0xc8, - 0xc5, 0xc7, 0x30, 0xc1, 0x92, 0x2f, 0x30, 0x03, 0x97, 0xb2, 0x29, 0x48, 0xd9, 0xc0, 0xc8, 0xd3, - 0xfa, 0xb4, 0x8a, 0x38, 0xd7, 0x6c, 0x3b, 0x13, 0xe7, 0x49, 0xe5, 0xfb, 0x8f, 0x0a, 0x86, 0x76, - 0xd4, 0x51, 0xf7, 0xd0, 0x86, 0x8e, 0x13, 0xda, 0xc9, 0xe5, 0xd2, 0xc0, 0x4e, 0x70, 0x3b, 0x60, - 0xbe, 0xe8, 0x53, 0x12, 0x75, 0xdb, 0xa8, 0x54, 0x7c, 0x16, 0x04, 0x71, 0xdd, 0xc6, 0x65, 0xb2, - 0xa2, 0x17, 0xd2, 0x15, 0xbd, 0x55, 0x9d, 0x87, 0x92, 0xd5, 0xf9, 0x13, 0x6c, 0xcd, 0x12, 0x2e, - 0x90, 0x96, 0x27, 0x30, 0x66, 0xba, 0x4e, 0x10, 0xd6, 0x5b, 0x35, 0x67, 0xa0, 0x5e, 0xaa, 0xa5, - 0x1c, 0x39, 0xae, 0x1b, 0x07, 0x0f, 0xb6, 0xb1, 0x85, 0x92, 0x0b, 0x7a, 0x07, 0x2e, 0x08, 0xc7, - 0x5b, 0xd1, 0x58, 0x64, 0xb6, 0xca, 0xf9, 0x86, 0x15, 0xf0, 0x9e, 0xdd, 0x09, 0xad, 0xc3, 0x42, - 0x77, 0xe5, 0x13, 0x6f, 0x06, 0xe9, 0x73, 0xf8, 0x8a, 0x70, 0xf7, 0xa8, 0x5a, 0x65, 0x26, 0xb7, - 0xf6, 0xd9, 0xa6, 0x18, 0x88, 0x62, 0x9c, 0x6a, 0x07, 0x53, 0xe3, 0x89, 0xe0, 0xa7, 0x61, 0x34, - 0xea, 0xe4, 0x5a, 0xe9, 0xc0, 0x15, 0xfd, 0xa5, 0x82, 0xfb, 0xff, 0x88, 0x4d, 0x84, 0x5f, 0x82, - 0x51, 0x39, 0x76, 0x21, 0xf9, 0x6a, 0xc7, 0x76, 0x8c, 0x06, 0xb3, 0x22, 0xea, 0xa0, 0x24, 0x59, - 0x83, 0x77, 0x3c, 0xe6, 0x54, 0x2c, 0xa7, 0xa6, 0xa3, 0x6e, 0xa1, 0xa7, 0xee, 0x04, 0x6a, 0xc8, - 0x25, 0xfd, 0x8d, 0x82, 0xed, 0xf5, 0x56, 0x65, 0xaf, 0xb3, 0x55, 0x7b, 0x02, 0xa7, 0xe3, 0x7e, - 0x53, 0x62, 0xfa, 0x5a, 0xf6, 0x11, 0xe9, 0xd2, 0x9e, 0x97, 0x63, 0x6d, 0x32, 0x05, 0xa3, 0x75, - 0xe3, 0x40, 0x37, 0xc3, 0xe4, 0x96, 0x08, 0xc9, 0x35, 0x18, 0x8e, 0xd8, 0x11, 0x1b, 0xf4, 0x4c, - 0xe9, 0x7c, 0xda, 0xb8, 0x18, 0x51, 0xb7, 0x3c, 0x66, 0x96, 0x85, 0x10, 0xfd, 0x3a, 0x5c, 0x4c, - 0x8d, 0x34, 0xdf, 0x76, 0x1d, 0xbe, 0x6b, 0x1f, 0x6e, 0x1a, 0x87, 0x6e, 0xc8, 0x13, 0x99, 0xf1, - 0x92, 0x7d, 0x53, 0xa2, 0x5b, 0xa5, 0x7b, 0x40, 0xb6, 0x12, 0xa3, 0xa0, 0x54, 0x24, 0x14, 0xce, - 0x26, 0x07, 0x44, 0xd4, 0x4a, 0x3d, 0x23, 0xb3, 0x30, 0x26, 0x36, 0x62, 0xd4, 0x4d, 0xa6, 0x0e, - 0x59, 0x25, 0x4a, 0xb7, 0x51, 0x77, 0x43, 0x87, 0xe3, 0x29, 0xc3, 0x15, 0xfd, 0x21, 0xd0, 0x3c, - 0xb4, 0xed, 0x5e, 0x98, 0xbb, 0xdc, 0xb0, 0x85, 0xd7, 0xe1, 0xb2, 0x5c, 0x90, 0x75, 0x38, 0x5d, - 0x61, 0xdc, 0xb0, 0xec, 0x60, 0xa6, 0x20, 0xb6, 0xf1, 0x62, 0x36, 0xed, 0x47, 0xa3, 0x29, 0xc7, - 0x8a, 0xf4, 0x21, 0xbc, 0x93, 0x28, 0x4b, 0x51, 0xa0, 0x39, 0xd4, 0x24, 0xa2, 0x28, 0xa4, 0xa2, - 0x78, 0x01, 0x13, 0x0f, 0xe4, 0x09, 0x44, 0x23, 0x49, 0x26, 0x94, 0x34, 0x13, 0xf7, 0xa3, 0xcd, - 0x12, 0x09, 0xc5, 0xa8, 0x2f, 0xf7, 0xac, 0x96, 0x02, 0x31, 0x2a, 0xd1, 0x07, 0xd8, 0x18, 0x24, - 0xa3, 0xea, 0x96, 0xe3, 0x6e, 0xa7, 0x8f, 0x36, 0xb1, 0xd6, 0xe7, 0x18, 0xc9, 0xa5, 0xfe, 0x5e, - 0x27, 0xf5, 0x5d, 0x8a, 0x42, 0x8a, 0x95, 0x16, 0xeb, 0xa5, 0x5f, 0xcf, 0xc0, 0x88, 0xf0, 0x4f, - 0x7e, 0xaa, 0xc0, 0xa8, 0x1c, 0xf6, 0xc9, 0x62, 0xce, 0xa1, 0x49, 0x7d, 0x5b, 0x50, 0x97, 0xfa, - 0x90, 0x94, 0xf0, 0xe9, 0xe5, 0x9f, 0xbc, 0xfa, 0xef, 0x2f, 0x0a, 0xf3, 0x64, 0x4e, 0xcb, 0xf9, - 0x54, 0x44, 0x7e, 0xa5, 0xc0, 0x78, 0x7b, 0x70, 0xba, 0x96, 0x67, 0xbe, 0xe3, 0xdb, 0x83, 0xba, - 0xdc, 0x9f, 0x30, 0xc2, 0x59, 0x11, 0x70, 0xae, 0x91, 0x25, 0x2d, 0xf7, 0x63, 0x51, 0xa0, 0x35, - 0xf0, 0x46, 0x6f, 0x92, 0xdf, 0x2a, 0x00, 0xed, 0x3b, 0x83, 0x2c, 0xf7, 0x79, 0xb5, 0x48, 0x74, - 0x83, 0x5d, 0x44, 0xf4, 0xae, 0x80, 0x77, 0x8b, 0xdc, 0xc8, 0x86, 0x57, 0x63, 0xad, 0xc1, 0xba, - 0x0d, 0x50, 0x6b, 0xc8, 0x09, 0xb8, 0x49, 0xfe, 0xaa, 0xc0, 0x44, 0x6a, 0x96, 0x25, 0x5a, 0x8e, - 0xfb, 0xac, 0xb9, 0x5b, 0xfd, 0xb0, 0x7f, 0x05, 0x84, 0x5c, 0x16, 0x90, 0x37, 0xc8, 0xb3, 0x6c, - 0xc8, 0xfb, 0x42, 0x29, 0x07, 0xb5, 0xd6, 0x88, 0x49, 0x6f, 0x6a, 0x0d, 0x51, 0xfa, 0x9b, 0xe4, - 0x67, 0x05, 0xa0, 0xdb, 0x7d, 0x4c, 0x30, 0xf9, 0xe4, 0xf6, 0x3d, 0x1a, 0xaa, 0xdf, 0x3c, 0xbe, - 0x21, 0x64, 0x63, 0x43, 0xb0, 0xf1, 0x98, 0x3c, 0xd4, 0x8e, 0xf1, 0x5d, 0x51, 0x6b, 0x88, 0xde, - 0xb7, 0x49, 0x7e, 0x5c, 0x80, 0x2b, 0xbd, 0x9d, 0xaf, 0xd9, 0x76, 0x2e, 0x15, 0x83, 0x4c, 0xc9, - 0xb9, 0x54, 0x0c, 0x34, 0xf0, 0xd2, 0x87, 0x82, 0x8a, 0xfb, 0xe4, 0xee, 0x71, 0xa8, 0x20, 0xaf, - 0x14, 0x98, 0xce, 0x9e, 0x5b, 0xc8, 0x9d, 0x1e, 0x67, 0x2b, 0x6f, 0x6a, 0x53, 0xef, 0xbe, 0x9d, - 0x32, 0xc6, 0x76, 0x5f, 0xc4, 0xb6, 0x4a, 0x6e, 0x69, 0x03, 0x7d, 0x73, 0x6e, 0x25, 0xf6, 0xef, - 0x0a, 0xcc, 0x66, 0xbb, 0x88, 0x92, 0x79, 0x27, 0x3f, 0x07, 0x6f, 0x1f, 0x58, 0xcf, 0xc9, 0x92, - 0xde, 0x12, 0x81, 0x7d, 0x48, 0x8a, 0x83, 0x05, 0x46, 0xfe, 0xa0, 0xc0, 0x44, 0x6a, 0x00, 0x21, - 0xa5, 0x7c, 0x82, 0xb3, 0x46, 0x2b, 0xf5, 0xfa, 0x40, 0x3a, 0x08, 0xf9, 0x86, 0x80, 0x5c, 0x24, - 0xcb, 0x5a, 0x1f, 0xbf, 0x34, 0xb4, 0x32, 0xf0, 0x3b, 0x05, 0xce, 0xa5, 0xec, 0x45, 0xc4, 0x97, - 0xf2, 0xb9, 0x1b, 0x18, 0x73, 0xb7, 0xc9, 0x8e, 0x2e, 0x0b, 0xcc, 0x57, 0xc9, 0xe5, 0x7e, 0x30, - 0x93, 0xcf, 0x15, 0x18, 0x6f, 0x8d, 0x41, 0xb9, 0xd5, 0xb1, 0x73, 0x1e, 0xcb, 0xad, 0x8e, 0x47, - 0x26, 0xab, 0x5e, 0xe5, 0x27, 0x0c, 0x98, 0x2f, 0x7f, 0xcc, 0xd0, 0x1a, 0x38, 0xd6, 0x35, 0x13, - 0x85, 0xf2, 0xcf, 0x0a, 0xbc, 0x97, 0x31, 0xf7, 0x90, 0x9b, 0x39, 0x18, 0xba, 0x0f, 0x59, 0xea, - 0xad, 0x41, 0xd5, 0x30, 0x88, 0x7b, 0x22, 0x88, 0x8f, 0xc8, 0xcd, 0xec, 0x20, 0x02, 0xa1, 0xda, - 0xfe, 0x7a, 0xab, 0xdb, 0x56, 0xc0, 0x13, 0x51, 0xfc, 0x49, 0x81, 0x77, 0x3b, 0x46, 0x1f, 0xb2, - 0x92, 0x03, 0x25, 0x7b, 0xf4, 0x52, 0x4b, 0x83, 0xa8, 0x20, 0xf2, 0x75, 0x81, 0xfc, 0x2e, 0xb9, - 0xdd, 0x65, 0x57, 0xc4, 0x6a, 0x38, 0x43, 0x69, 0x8d, 0xb8, 0x9d, 0x6c, 0x6a, 0x0d, 0x39, 0xbd, - 0x35, 0xc9, 0xdf, 0x14, 0x98, 0xca, 0xec, 0xe5, 0xc9, 0x47, 0x7d, 0x34, 0x4a, 0x59, 0x7d, 0xac, - 0xba, 0x3a, 0xb8, 0x22, 0x06, 0xf4, 0x0d, 0x11, 0xd0, 0x6d, 0xb2, 0xda, 0xe3, 0x36, 0xa9, 0x4b, - 0x6d, 0x5d, 0xb6, 0xd8, 0x89, 0x8e, 0x80, 0xfc, 0x53, 0x81, 0xd9, 0xae, 0x3d, 0x72, 0xee, 0x45, - 0xd9, 0xab, 0x3d, 0xcf, 0xbd, 0x28, 0x7b, 0xb6, 0xe5, 0xbd, 0xaa, 0x5b, 0x72, 0x2c, 0x3b, 0x12, - 0x5e, 0x2b, 0x6d, 0xe4, 0x33, 0x05, 0xa0, 0x3d, 0xcf, 0x9e, 0x60, 0x6f, 0x79, 0x74, 0x48, 0xa6, - 0x4b, 0x02, 0xf1, 0x25, 0x72, 0xb1, 0x0b, 0xe2, 0xca, 0x5e, 0xdc, 0xa5, 0xad, 0xaf, 0x7d, 0xf1, - 0x7a, 0x5e, 0xf9, 0xf2, 0xf5, 0xbc, 0xf2, 0x9f, 0xd7, 0xf3, 0xca, 0xcf, 0xdf, 0xcc, 0x9f, 0xfa, - 0xf2, 0xcd, 0xfc, 0xa9, 0x7f, 0xbc, 0x99, 0x3f, 0xf5, 0xfd, 0x0f, 0x6a, 0x16, 0xdf, 0x0d, 0x77, - 0x8a, 0xa6, 0x5b, 0x4f, 0x9b, 0x39, 0x68, 0x19, 0xe2, 0x87, 0x1e, 0x0b, 0x76, 0x46, 0xc5, 0x6f, - 0x93, 0xd7, 0xff, 0x17, 0x00, 0x00, 0xff, 0xff, 0x9b, 0x6e, 0x1a, 0x85, 0xba, 0x1e, 0x00, 0x00, + 0x84, 0xf0, 0xc0, 0x8b, 0xe5, 0x78, 0xee, 0x4c, 0xdc, 0x78, 0x6c, 0xd7, 0x1f, 0xd9, 0x84, 0xd1, + 0x00, 0x02, 0xf1, 0xba, 0x42, 0x62, 0x79, 0x40, 0xe2, 0x71, 0x05, 0xe2, 0x01, 0xde, 0x91, 0x78, + 0x43, 0xa0, 0x7d, 0x40, 0x68, 0xa5, 0xbe, 0xf0, 0x00, 0x08, 0xb5, 0xfc, 0x21, 0xc8, 0xf7, 0x1e, + 0x7b, 0xec, 0x89, 0xc7, 0x9e, 0x69, 0x22, 0x5e, 0xda, 0x5c, 0xfb, 0x7c, 0xfc, 0xce, 0xef, 0xdc, + 0x7b, 0xcf, 0x39, 0x1e, 0x58, 0x30, 0xb5, 0x7d, 0xcd, 0x62, 0xbe, 0x12, 0xfe, 0xaf, 0x38, 0x9a, + 0xe1, 0x1a, 0x56, 0x43, 0x79, 0x19, 0x30, 0xf7, 0xb0, 0xec, 0xb8, 0xb6, 0x6f, 0x93, 0x49, 0x94, + 0x28, 0x87, 0xff, 0x97, 0x51, 0x42, 0x9e, 0x6c, 0xd8, 0x0d, 0x9b, 0x0b, 0x28, 0xe1, 0x5f, 0x42, + 0x56, 0x9e, 0x6b, 0xd8, 0x76, 0xc3, 0x64, 0x8a, 0xe6, 0x18, 0x8a, 0x66, 0x59, 0xb6, 0xaf, 0xf9, + 0x86, 0x6d, 0x79, 0xf8, 0xf6, 0xab, 0xba, 0xed, 0x35, 0x6d, 0x4f, 0xd9, 0xd1, 0x3c, 0x26, 0x5c, + 0x28, 0xfb, 0x2b, 0x3b, 0xcc, 0xd7, 0x56, 0x14, 0x47, 0x6b, 0x18, 0x16, 0x17, 0x46, 0xd9, 0x8b, + 0x99, 0xb8, 0x1c, 0xcd, 0xd5, 0x9a, 0x91, 0xb9, 0xa5, 0x4c, 0x11, 0xe6, 0xd8, 0xfa, 0xae, 0xea, + 0x68, 0x87, 0x4d, 0x66, 0xf9, 0x91, 0xe8, 0x5c, 0x4a, 0xd4, 0x73, 0x98, 0xce, 0xff, 0xc1, 0xb7, + 0x17, 0xd2, 0x86, 0x4c, 0xcd, 0xf2, 0x14, 0xc7, 0x36, 0x0d, 0x1d, 0x29, 0x90, 0xaf, 0x67, 0x83, + 0x71, 0xed, 0x7d, 0xa3, 0xc6, 0xdc, 0xc8, 0x99, 0xea, 0xf9, 0xb6, 0xab, 0x35, 0x18, 0x2a, 0xad, + 0x65, 0x2a, 0x05, 0x96, 0xf1, 0x32, 0x60, 0xdd, 0x2a, 0xaa, 0x6e, 0x1a, 0xe1, 0x32, 0x32, 0x89, + 0x26, 0xae, 0xa5, 0x4c, 0xf0, 0xc8, 0x50, 0x41, 0xf1, 0x7c, 0x6d, 0x8f, 0xa9, 0xcc, 0xf2, 0xa3, + 0x3c, 0xc9, 0xcb, 0xe9, 0x18, 0x83, 0x1d, 0x4f, 0x77, 0x0d, 0x27, 0xa4, 0x34, 0xb5, 0x40, 0xe9, + 0x4b, 0x69, 0x74, 0xae, 0xfd, 0x82, 0xe9, 0xbe, 0x17, 0xfd, 0x21, 0x84, 0xe8, 0x24, 0x90, 0xe7, + 0x61, 0x9a, 0x36, 0x39, 0xed, 0x55, 0xf6, 0x32, 0x60, 0x9e, 0x4f, 0x9f, 0xc3, 0x7b, 0xa9, 0xa7, + 0x9e, 0x63, 0x5b, 0x1e, 0x23, 0xb7, 0x61, 0x54, 0xa4, 0x67, 0x46, 0x5a, 0x90, 0x16, 0xcf, 0x54, + 0xe6, 0xca, 0x59, 0x1b, 0xa7, 0x2c, 0xb4, 0xd6, 0x87, 0xbf, 0xf8, 0xf7, 0x85, 0x53, 0x55, 0xd4, + 0xa0, 0xcf, 0x61, 0x4a, 0x98, 0xc4, 0xf8, 0x23, 0x5f, 0x64, 0x06, 0x4e, 0xeb, 0xbb, 0x9a, 0x61, + 0x3d, 0x7d, 0xc8, 0xad, 0x8e, 0x57, 0xa3, 0x25, 0x99, 0x07, 0xf0, 0x76, 0xed, 0x4f, 0x1e, 0xbb, + 0xf6, 0x0f, 0x98, 0x35, 0x53, 0x5a, 0x90, 0x16, 0xc7, 0xaa, 0x89, 0x27, 0x94, 0xc1, 0x74, 0xb7, + 0x49, 0x04, 0xfa, 0x2d, 0x00, 0xce, 0xde, 0xa3, 0x90, 0xbc, 0x19, 0x69, 0x61, 0x68, 0xf1, 0x4c, + 0xe5, 0x4a, 0x1a, 0x6c, 0x92, 0xea, 0xf2, 0x56, 0x2c, 0x8c, 0xa8, 0x13, 0xea, 0xf4, 0x19, 0xba, + 0x79, 0xc2, 0xfc, 0x4d, 0x11, 0x61, 0x31, 0xf4, 0x69, 0x18, 0x15, 0xf9, 0xe6, 0xb0, 0xc7, 0xab, + 0xb8, 0xa2, 0xbf, 0x2f, 0xc1, 0xf9, 0x23, 0xc6, 0x10, 0xf4, 0x53, 0x18, 0x8f, 0x36, 0x87, 0xf7, + 0x36, 0x98, 0x3b, 0xda, 0xe4, 0x12, 0x4c, 0xe8, 0x81, 0xeb, 0x86, 0xfb, 0x8d, 0xeb, 0x70, 0x14, + 0xc3, 0xd5, 0xb3, 0xf8, 0xf0, 0x51, 0xf8, 0x8c, 0xac, 0xc2, 0xac, 0x6f, 0x34, 0x99, 0x6a, 0xb2, + 0xba, 0xaf, 0xfa, 0xb6, 0x6a, 0xb1, 0x03, 0x5f, 0xc5, 0x1c, 0xce, 0x0c, 0x71, 0x85, 0xa9, 0x50, + 0x60, 0x83, 0xd5, 0xfd, 0xef, 0xda, 0xdf, 0x61, 0x07, 0x11, 0x62, 0x72, 0x13, 0xce, 0x87, 0x67, + 0x4b, 0x35, 0x35, 0xcf, 0x57, 0x03, 0xa7, 0xa6, 0xf9, 0xac, 0xa6, 0xee, 0x98, 0xb6, 0xbe, 0x37, + 0x33, 0xcc, 0xf5, 0x26, 0xc3, 0xd7, 0x1b, 0x9a, 0xe7, 0x6f, 0x8b, 0x97, 0xeb, 0xe1, 0x3b, 0xb2, + 0x02, 0x53, 0x5c, 0x48, 0xb5, 0xeb, 0x69, 0x67, 0x23, 0x5c, 0x89, 0xf0, 0x97, 0x1f, 0xd7, 0x13, + 0x9e, 0xe8, 0x8f, 0x60, 0x96, 0xd3, 0xf5, 0x3d, 0xe6, 0x1a, 0xf5, 0xc3, 0xe3, 0xd2, 0x4f, 0x64, + 0x18, 0x8b, 0x48, 0xe2, 0x11, 0x8e, 0x57, 0xe3, 0x35, 0x99, 0x84, 0x91, 0x64, 0x08, 0x62, 0x41, + 0x3f, 0x97, 0x40, 0xce, 0x42, 0x80, 0x39, 0x9b, 0x84, 0x91, 0x7d, 0xcd, 0x34, 0x6a, 0x1c, 0xc0, + 0x58, 0x55, 0x2c, 0xc8, 0x12, 0x9c, 0x0b, 0x43, 0x63, 0x35, 0xb5, 0x93, 0x50, 0x41, 0xe8, 0xbb, + 0xe2, 0x79, 0xbc, 0x63, 0xc9, 0x02, 0x9c, 0xd5, 0x03, 0xd5, 0x61, 0x2e, 0x26, 0x4a, 0x38, 0x07, + 0x3d, 0xd8, 0x64, 0xae, 0x48, 0xd3, 0xfb, 0x00, 0x78, 0x64, 0x55, 0xa3, 0xc6, 0xa9, 0x1a, 0xe7, + 0xa9, 0x0e, 0x9f, 0x3c, 0xad, 0x3d, 0x1b, 0x1e, 0x2b, 0x9d, 0x1b, 0xa2, 0x4f, 0x61, 0x25, 0xda, + 0x56, 0xdb, 0xfc, 0xfa, 0xd9, 0x14, 0xb7, 0xcf, 0x96, 0xd8, 0x2c, 0x0f, 0x78, 0xf8, 0x91, 0xd7, + 0x88, 0xbf, 0x49, 0x18, 0x31, 0xac, 0x1a, 0x3b, 0x40, 0xf6, 0xc4, 0x82, 0xfe, 0x45, 0x82, 0xca, + 0x20, 0xb6, 0x90, 0x89, 0x4f, 0x25, 0xa0, 0x41, 0xa1, 0x38, 0x5e, 0x1c, 0xab, 0xd9, 0x17, 0x47, + 0xb1, 0x3b, 0xdc, 0xea, 0x7d, 0x78, 0xa2, 0x2d, 0xa4, 0x64, 0xcd, 0x34, 0xfb, 0xa7, 0xe4, 0x31, + 0x40, 0xa7, 0x4e, 0x21, 0xd8, 0xab, 0x65, 0x51, 0xd4, 0xca, 0x61, 0x51, 0x2b, 0x8b, 0xba, 0x89, + 0x45, 0xad, 0xbc, 0xa9, 0x35, 0x18, 0xea, 0x56, 0x13, 0x9a, 0xf4, 0xd3, 0x12, 0x92, 0xd8, 0xa7, + 0xf7, 0x41, 0x49, 0x1c, 0xfa, 0xff, 0x90, 0x48, 0x9e, 0xa4, 0xf8, 0x28, 0x71, 0x3e, 0x3e, 0x28, + 0xe4, 0x43, 0x44, 0x93, 0x22, 0xe4, 0x1e, 0x5c, 0x89, 0xef, 0x3d, 0x34, 0x9e, 0x76, 0x9c, 0xbf, + 0x29, 0x3f, 0x93, 0xe0, 0x6a, 0x91, 0x3e, 0x72, 0xf8, 0x02, 0xa6, 0x9d, 0x4c, 0x09, 0x4c, 0xe7, + 0x72, 0x8f, 0xa2, 0x95, 0xa9, 0x83, 0x54, 0xf5, 0xb0, 0x48, 0x6d, 0x8c, 0x6a, 0xcd, 0x34, 0xf3, + 0xa3, 0x3a, 0xa9, 0x7d, 0xf5, 0xaf, 0x88, 0x87, 0x1c, 0x8f, 0x7d, 0xf0, 0x30, 0x74, 0xb2, 0x3c, + 0x9c, 0xdc, 0x36, 0xb9, 0x01, 0x73, 0x51, 0x9a, 0xf9, 0xed, 0x87, 0x7e, 0xbc, 0xfc, 0xdd, 0xe1, + 0xc0, 0xfb, 0x3d, 0xb4, 0x90, 0x8b, 0x8f, 0x61, 0x82, 0x25, 0x5f, 0x60, 0x06, 0x2e, 0x65, 0x53, + 0x90, 0xb2, 0x81, 0x91, 0xa7, 0xf5, 0x69, 0x1d, 0x71, 0xae, 0x99, 0x66, 0x26, 0xce, 0x93, 0xca, + 0xf7, 0x1f, 0x25, 0x0c, 0xed, 0xa8, 0xa3, 0xde, 0xa1, 0x0d, 0x1d, 0x27, 0xb4, 0x93, 0xcb, 0xa5, + 0x86, 0x1d, 0xdf, 0xb6, 0xc7, 0x5c, 0xde, 0xa7, 0x24, 0xea, 0xb6, 0x56, 0xab, 0xb9, 0xcc, 0xf3, + 0xa2, 0xba, 0x8d, 0xcb, 0x64, 0x45, 0x2f, 0xa5, 0x2b, 0x7a, 0x5c, 0x9d, 0x87, 0x92, 0xd5, 0xf9, + 0x13, 0x6c, 0xcd, 0x12, 0x2e, 0x90, 0x96, 0x27, 0x30, 0xa6, 0xdb, 0x96, 0x17, 0x34, 0xe3, 0x9a, + 0x33, 0x50, 0x2f, 0x15, 0x2b, 0x87, 0x8e, 0x9b, 0xda, 0xc1, 0x83, 0x6d, 0x6c, 0xa1, 0xc4, 0x82, + 0xde, 0x81, 0x0b, 0xdc, 0xf1, 0x56, 0x38, 0xfe, 0xe8, 0x71, 0x39, 0xdf, 0x30, 0x3c, 0xbf, 0xb0, + 0x3b, 0xa1, 0x4d, 0x58, 0xe8, 0xad, 0x7c, 0xe2, 0xcd, 0x20, 0x7d, 0x0e, 0x5f, 0xe1, 0xee, 0x1e, + 0xd5, 0xeb, 0x4c, 0xf7, 0x8d, 0x7d, 0xb6, 0xc9, 0x07, 0x9f, 0x08, 0xa7, 0xdc, 0xc5, 0xd4, 0x78, + 0x22, 0xf8, 0x69, 0x18, 0x0d, 0x3b, 0xb9, 0x38, 0x1d, 0xb8, 0xa2, 0xbf, 0x94, 0x70, 0xff, 0x1f, + 0xb1, 0x89, 0xf0, 0x2b, 0x30, 0x2a, 0xc6, 0x2b, 0x24, 0x5f, 0xee, 0xda, 0x8e, 0xe1, 0x00, 0x56, + 0x46, 0x1d, 0x94, 0x24, 0x6b, 0xf0, 0x8e, 0xc3, 0xac, 0x9a, 0x61, 0x35, 0x54, 0xd4, 0x2d, 0x15, + 0xea, 0x4e, 0xa0, 0x86, 0x58, 0xd2, 0xdf, 0x48, 0xd8, 0x5e, 0x6f, 0xd5, 0xf6, 0xba, 0x5b, 0xb5, + 0x27, 0x70, 0x3a, 0xea, 0x37, 0x05, 0xa6, 0xaf, 0x65, 0x1f, 0x91, 0x1e, 0xed, 0x79, 0x35, 0xd2, + 0x26, 0x53, 0x30, 0xda, 0xd4, 0x0e, 0x54, 0x3d, 0x48, 0x6e, 0x89, 0x80, 0x5c, 0x83, 0xe1, 0x90, + 0x1d, 0xbe, 0x41, 0xcf, 0x54, 0xce, 0xa7, 0x8d, 0xf3, 0x51, 0x74, 0xcb, 0x61, 0x7a, 0x95, 0x0b, + 0xd1, 0xaf, 0xc3, 0xc5, 0xd4, 0xe8, 0xf2, 0x6d, 0xdb, 0xf2, 0x77, 0xcd, 0xc3, 0x4d, 0xed, 0xd0, + 0x0e, 0xfc, 0x44, 0x66, 0x9c, 0x64, 0xdf, 0x94, 0xe8, 0x56, 0xe9, 0x1e, 0x90, 0xad, 0xc4, 0xc8, + 0x27, 0x14, 0x09, 0x85, 0xb3, 0xc9, 0x41, 0x10, 0xb5, 0x52, 0xcf, 0xc8, 0x2c, 0x8c, 0xf1, 0x8d, + 0x18, 0x76, 0x93, 0xa9, 0x43, 0x56, 0x0b, 0xd3, 0xad, 0x35, 0xed, 0xc0, 0xf2, 0xf1, 0x94, 0xe1, + 0x8a, 0xfe, 0x10, 0x68, 0x1e, 0xda, 0x4e, 0x2f, 0xec, 0xdb, 0xbe, 0x66, 0x72, 0xaf, 0xc3, 0x55, + 0xb1, 0x20, 0xeb, 0x70, 0xba, 0xc6, 0x7c, 0xcd, 0x30, 0xbd, 0x99, 0x12, 0xdf, 0xc6, 0x8b, 0xd9, + 0xb4, 0x1f, 0x8d, 0xa6, 0x1a, 0x29, 0xd2, 0x87, 0xf0, 0x4e, 0xa2, 0x2c, 0x85, 0x81, 0xe6, 0x50, + 0x93, 0x88, 0xa2, 0x94, 0x8a, 0xe2, 0x05, 0x4c, 0x3c, 0x10, 0x27, 0x10, 0x8d, 0x24, 0x99, 0x90, + 0xd2, 0x4c, 0xdc, 0x0f, 0x37, 0x4b, 0x28, 0x14, 0xa1, 0xbe, 0x5c, 0x58, 0x2d, 0x39, 0x62, 0x54, + 0xa2, 0x0f, 0xb0, 0x31, 0x48, 0x46, 0xd5, 0x2b, 0xc7, 0xbd, 0x4e, 0x1f, 0x6d, 0x63, 0xad, 0xcf, + 0x31, 0x92, 0x4b, 0xfd, 0xbd, 0x6e, 0xea, 0x7b, 0x14, 0x85, 0x14, 0x2b, 0x31, 0xeb, 0x95, 0x5f, + 0xcf, 0xc0, 0x08, 0xf7, 0x4f, 0x7e, 0x2a, 0xc1, 0xa8, 0x18, 0xea, 0xc9, 0x62, 0xce, 0xa1, 0x49, + 0x7d, 0x43, 0x90, 0x97, 0xfa, 0x90, 0x14, 0xf0, 0xe9, 0xe5, 0x9f, 0xbc, 0xfa, 0xef, 0x2f, 0x4a, + 0xf3, 0x64, 0x4e, 0xc9, 0xf9, 0x24, 0x44, 0x7e, 0x25, 0xc1, 0x78, 0x67, 0x70, 0xba, 0x96, 0x67, + 0xbe, 0xeb, 0x1b, 0x83, 0xbc, 0xdc, 0x9f, 0x30, 0xc2, 0x59, 0xe1, 0x70, 0xae, 0x91, 0x25, 0x25, + 0xf7, 0xa3, 0x90, 0xa7, 0xb4, 0xf0, 0x46, 0x6f, 0x93, 0xdf, 0x4a, 0x00, 0x9d, 0x3b, 0x83, 0x2c, + 0xf7, 0x79, 0xb5, 0x08, 0x74, 0x83, 0x5d, 0x44, 0xf4, 0x2e, 0x87, 0x77, 0x8b, 0xdc, 0xc8, 0x86, + 0xd7, 0x60, 0xf1, 0x60, 0xdd, 0x01, 0xa8, 0xb4, 0xc4, 0x04, 0xdc, 0x26, 0x7f, 0x95, 0x60, 0x22, + 0x35, 0xcb, 0x12, 0x25, 0xc7, 0x7d, 0xd6, 0xdc, 0x2d, 0x7f, 0xd8, 0xbf, 0x02, 0x42, 0xae, 0x72, + 0xc8, 0x1b, 0xe4, 0x59, 0x36, 0xe4, 0x7d, 0xae, 0x94, 0x83, 0x5a, 0x69, 0x45, 0xa4, 0xb7, 0x95, + 0x16, 0x2f, 0xfd, 0x6d, 0xf2, 0xb3, 0x12, 0xd0, 0xed, 0x3e, 0x26, 0x98, 0x7c, 0x72, 0xfb, 0x1e, + 0x0d, 0xe5, 0x6f, 0x1e, 0xdf, 0x10, 0xb2, 0xb1, 0xc1, 0xd9, 0x78, 0x4c, 0x1e, 0x2a, 0xc7, 0xf8, + 0x7e, 0xa8, 0xb4, 0x78, 0xef, 0xdb, 0x26, 0x3f, 0x2e, 0xc1, 0x95, 0x62, 0xe7, 0x6b, 0xa6, 0x99, + 0x4b, 0xc5, 0x20, 0x53, 0x72, 0x2e, 0x15, 0x03, 0x0d, 0xbc, 0xf4, 0x21, 0xa7, 0xe2, 0x3e, 0xb9, + 0x7b, 0x1c, 0x2a, 0xc8, 0x2b, 0x09, 0xa6, 0xb3, 0xe7, 0x16, 0x72, 0xa7, 0xe0, 0x6c, 0xe5, 0x4d, + 0x6d, 0xf2, 0xdd, 0xb7, 0x53, 0xc6, 0xd8, 0xee, 0xf3, 0xd8, 0x56, 0xc9, 0x2d, 0x65, 0xa0, 0x6f, + 0xcb, 0x71, 0x62, 0xff, 0x2e, 0xc1, 0x6c, 0xb6, 0x8b, 0x30, 0x99, 0x77, 0xf2, 0x73, 0xf0, 0xf6, + 0x81, 0x15, 0x4e, 0x96, 0xf4, 0x16, 0x0f, 0xec, 0x43, 0x52, 0x1e, 0x2c, 0x30, 0xf2, 0x07, 0x09, + 0x26, 0x52, 0x03, 0x08, 0xa9, 0xe4, 0x13, 0x9c, 0x35, 0x5a, 0xc9, 0xd7, 0x07, 0xd2, 0x41, 0xc8, + 0x37, 0x38, 0xe4, 0x32, 0x59, 0x56, 0xfa, 0xf8, 0x45, 0x21, 0xce, 0xc0, 0xef, 0x24, 0x38, 0x97, + 0xb2, 0x17, 0x12, 0x5f, 0xc9, 0xe7, 0x6e, 0x60, 0xcc, 0xbd, 0x26, 0x3b, 0xba, 0xcc, 0x31, 0x5f, + 0x25, 0x97, 0xfb, 0xc1, 0x4c, 0x3e, 0x97, 0x60, 0x3c, 0x1e, 0x83, 0x72, 0xab, 0x63, 0xf7, 0x3c, + 0x96, 0x5b, 0x1d, 0x8f, 0x4c, 0x56, 0x45, 0xe5, 0x27, 0xf0, 0x98, 0x2b, 0x7e, 0xb4, 0x50, 0x5a, + 0x38, 0xd6, 0xb5, 0x13, 0x85, 0xf2, 0xcf, 0x12, 0xbc, 0x97, 0x31, 0xf7, 0x90, 0x9b, 0x39, 0x18, + 0x7a, 0x0f, 0x59, 0xf2, 0xad, 0x41, 0xd5, 0x30, 0x88, 0x7b, 0x3c, 0x88, 0x8f, 0xc8, 0xcd, 0xec, + 0x20, 0x3c, 0xae, 0xda, 0xf9, 0x7a, 0xab, 0x9a, 0x86, 0xe7, 0x27, 0xa2, 0xf8, 0x93, 0x04, 0xef, + 0x76, 0x8d, 0x3e, 0x64, 0x25, 0x07, 0x4a, 0xf6, 0xe8, 0x25, 0x57, 0x06, 0x51, 0x41, 0xe4, 0xeb, + 0x1c, 0xf9, 0x5d, 0x72, 0xbb, 0xc7, 0xae, 0x88, 0xd4, 0x70, 0x86, 0x52, 0x5a, 0x51, 0x3b, 0xd9, + 0x56, 0x5a, 0x62, 0x7a, 0x6b, 0x93, 0xbf, 0x49, 0x30, 0x95, 0xd9, 0xcb, 0x93, 0x8f, 0xfa, 0x68, + 0x94, 0xb2, 0xfa, 0x58, 0x79, 0x75, 0x70, 0x45, 0x0c, 0xe8, 0x1b, 0x3c, 0xa0, 0xdb, 0x64, 0xb5, + 0xe0, 0x36, 0x69, 0x0a, 0x6d, 0x55, 0xb4, 0xd8, 0x89, 0x8e, 0x80, 0xfc, 0x53, 0x82, 0xd9, 0x9e, + 0x3d, 0x72, 0xee, 0x45, 0x59, 0xd4, 0x9e, 0xe7, 0x5e, 0x94, 0x85, 0x6d, 0x79, 0x51, 0x75, 0x4b, + 0x8e, 0x65, 0x47, 0xc2, 0x8b, 0xd3, 0x46, 0x3e, 0x93, 0x00, 0x3a, 0xf3, 0xec, 0x09, 0xf6, 0x96, + 0x47, 0x87, 0x64, 0xba, 0xc4, 0x11, 0x5f, 0x22, 0x17, 0x7b, 0x20, 0xae, 0xed, 0x45, 0x5d, 0xda, + 0xfa, 0xda, 0x17, 0xaf, 0xe7, 0xa5, 0x2f, 0x5f, 0xcf, 0x4b, 0xff, 0x79, 0x3d, 0x2f, 0xfd, 0xfc, + 0xcd, 0xfc, 0xa9, 0x2f, 0xdf, 0xcc, 0x9f, 0xfa, 0xc7, 0x9b, 0xf9, 0x53, 0xdf, 0xff, 0xa0, 0x61, + 0xf8, 0xbb, 0xc1, 0x4e, 0x59, 0xb7, 0x9b, 0x69, 0x33, 0x07, 0xb1, 0x21, 0xff, 0xd0, 0x61, 0xde, + 0xce, 0x28, 0xff, 0x0d, 0xf2, 0xfa, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0x81, 0x70, 0x83, 0x53, + 0xa2, 0x1e, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2716,13 +2708,6 @@ func (m *QueryProvidersResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) _ = i var l int _ = l - if len(m.Output) > 0 { - i -= len(m.Output) - copy(dAtA[i:], m.Output) - i = encodeVarintQuery(dAtA, i, uint64(len(m.Output))) - i-- - dAtA[i] = 0x12 - } if len(m.StakeEntry) > 0 { for iNdEx := len(m.StakeEntry) - 1; iNdEx >= 0; iNdEx-- { { @@ -3981,10 +3966,6 @@ func (m *QueryProvidersResponse) Size() (n int) { n += 1 + l + sovQuery(uint64(l)) } } - l = len(m.Output) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } return n } @@ -4783,38 +4764,6 @@ func (m *QueryProvidersResponse) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Output", 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.Output = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:]) From 68cb197307d72ab2199490ceee3731b028cf5f72 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Wed, 29 Nov 2023 11:48:01 -0500 Subject: [PATCH 09/85] Remove the option to set amount for staking provider from modify-provider --- x/pairing/client/cli/tx_modify_provider.go | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/x/pairing/client/cli/tx_modify_provider.go b/x/pairing/client/cli/tx_modify_provider.go index a534c21a6f..7f1df6086f 100644 --- a/x/pairing/client/cli/tx_modify_provider.go +++ b/x/pairing/client/cli/tx_modify_provider.go @@ -18,7 +18,6 @@ import ( ) const ( - AmountFlagName = "amount" EndpointsFlagName = "endpoints" GeolocationFlag = "geolocation" ValidatorFlag = "validator" @@ -64,7 +63,7 @@ func CmdModifyProvider() *cobra.Command { [chain-id] is the spec the provider wishes to modify the entry for `, Example: `lavad tx pairing modify-provider "ETH1" --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE --from - lavad tx pairing modify-provider "ETH1" --endpoints "my-provider-africa.com:443,AF my-provider-europe.com:443,EU" --geolocation "AF,EU" --validator lava@valoper13w8ffww0akdyhgls2umvvudce3jxzw2s7fwcnk --from `, +lavad tx pairing modify-provider "ETH1" --endpoints "my-provider-africa.com:443,AF my-provider-europe.com:443,EU" --geolocation "AF,EU" --validator lava@valoper13w8ffww0akdyhgls2umvvudce3jxzw2s7fwcnk --from `, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { argChainID := args[0] @@ -107,20 +106,7 @@ func CmdModifyProvider() *cobra.Command { if providerEntry == nil { return utils.LavaFormatError("provider isn't staked on chainID, no address match", nil) } - newAmount, err := cmd.Flags().GetString(AmountFlagName) - if err != nil { - return err - } - if newAmount != "" { - newStake, err := sdk.ParseCoinNormalized(newAmount) - if err != nil { - return err - } - if providerEntry.Stake.Amount.GT(newStake.Amount) { - return utils.LavaFormatError("can't reduce provider stake", nil, utils.Attribute{Key: "current", Value: providerEntry.Stake}, utils.Attribute{Key: "requested", Value: providerEntry.Stake}) - } - providerEntry.Stake = newStake - } + var geolocation int32 if cmd.Flags().Changed(GeolocationFlag) { geolocation, err = planstypes.ParseGeoEnum(geolocationVar.String()) @@ -198,7 +184,6 @@ func CmdModifyProvider() *cobra.Command { } cmd.Flags().String(types.FlagMoniker, "", "The provider's moniker (non-unique name)") cmd.Flags().String(EndpointsFlagName, "", "The endpoints provider is offering in the format \"endpoint-url,geolocation endpoint-url,geolocation\"") - cmd.Flags().String(AmountFlagName, "", "modify the provider's staked amount") cmd.Flags().String(ValidatorFlag, "", "the validator to delegate/bond to with dualstaking") cmd.Flags().Var(&geolocationVar, GeolocationFlag, `modify the provider's geolocation int32 or string value "EU,US"`) cmd.Flags().Uint64(types.FlagCommission, 100, "The provider's commission from the delegators (default 100)") From c844ed7d7f7117cfe4d35f731e6bf687794bbc04 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Wed, 29 Nov 2023 12:07:32 -0500 Subject: [PATCH 10/85] Disable the option to edit the stake amount from pairing --- x/pairing/keeper/staking.go | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/x/pairing/keeper/staking.go b/x/pairing/keeper/staking.go index 482245b83e..cdb64d958d 100644 --- a/x/pairing/keeper/staking.go +++ b/x/pairing/keeper/staking.go @@ -72,6 +72,15 @@ func (k Keeper) StakeNewEntry(ctx sdk.Context, validator, creator, chainID strin utils.Attribute{Key: "provider", Value: senderAddr.String()}, ) } + + if !existingEntry.Stake.Equal(amount) { + return utils.LavaFormatWarning("cannot edit stake amount", fmt.Errorf("cannot edit stake amount"), + utils.Attribute{Key: "spec", Value: specChainID}, + utils.Attribute{Key: "provider", Value: senderAddr.String()}, + utils.Attribute{Key: "stake", Value: existingEntry.Stake}, + ) + } + details := []utils.Attribute{ {Key: "spec", Value: specChainID}, {Key: "provider", Value: senderAddr.String()}, @@ -89,27 +98,6 @@ func (k Keeper) StakeNewEntry(ctx sdk.Context, validator, creator, chainID strin k.epochStorageKeeper.ModifyStakeEntryCurrent(ctx, chainID, existingEntry, indexInStakeStorage) - if amount.Amount.GT(existingEntry.Stake.Amount) { - // delegate the difference - diffAmount := amount.Sub(existingEntry.Stake) - err = k.dualstakingKeeper.DelegateFull(ctx, senderAddr.String(), validator, senderAddr.String(), chainID, diffAmount) - if err != nil { - details = append(details, utils.Attribute{Key: "neededStake", Value: amount.Sub(existingEntry.Stake).String()}) - return utils.LavaFormatWarning("insufficient funds to pay for difference in stake", err, - details..., - ) - } - } else if amount.Amount.LT(existingEntry.Stake.Amount) { - // unbond the difference - diffAmount := existingEntry.Stake.Sub(amount) - err = k.dualstakingKeeper.UnbondFull(ctx, senderAddr.String(), validator, senderAddr.String(), chainID, diffAmount, false) - if err != nil { - details = append(details, utils.Attribute{Key: "neededStake", Value: amount.Sub(existingEntry.Stake).String()}) - return utils.LavaFormatWarning("insufficient funds to pay for difference in stake", err, - details..., - ) - } - } // TODO: create a new entry entirely because then we can keep the copies of this list as pointers only // then we need to change the Copy of StoreCurrentEpochStakeStorage to copy of the pointers only // must also change the unstaking to create a new entry entirely From a25b86bd33c8ae58369841fb774cac3dbc76de35 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Thu, 30 Nov 2023 04:01:32 -0500 Subject: [PATCH 11/85] Remove the unstake boolean --- x/dualstaking/keeper/delegate.go | 29 ++++++++----------- x/dualstaking/keeper/msg_server_delegate.go | 1 - x/dualstaking/keeper/msg_server_redelegate.go | 1 - x/dualstaking/keeper/msg_server_unbond.go | 1 - 4 files changed, 12 insertions(+), 20 deletions(-) diff --git a/x/dualstaking/keeper/delegate.go b/x/dualstaking/keeper/delegate.go index 1fe2c81397..b81f21b948 100644 --- a/x/dualstaking/keeper/delegate.go +++ b/x/dualstaking/keeper/delegate.go @@ -86,10 +86,7 @@ func (k Keeper) increaseDelegation(ctx sdk.Context, delegator, provider, chainID if provider != types.EMPTY_PROVIDER { // update the stake entry - err = k.increaseStakeEntryDelegation(ctx, delegator, provider, chainID, amount) - if err != nil { - return err - } + return k.increaseStakeEntryDelegation(ctx, delegator, provider, chainID, amount) } return nil @@ -98,7 +95,7 @@ func (k Keeper) increaseDelegation(ctx sdk.Context, delegator, provider, chainID // decreaseDelegation decreases the delegation of a delegator to a provider for a // given chain. It updates the fixation stores for both delegations and delegators, // and updates the (epochstorage) stake-entry. -func (k Keeper) decreaseDelegation(ctx sdk.Context, delegator, provider, chainID string, amount sdk.Coin, nextEpoch uint64, unstake bool) error { +func (k Keeper) decreaseDelegation(ctx sdk.Context, delegator, provider, chainID string, amount sdk.Coin, nextEpoch uint64) error { // get, update and append the delegation entry var delegationEntry types.Delegation index := types.DelegationKey(provider, delegator, chainID) @@ -181,9 +178,7 @@ func (k Keeper) decreaseDelegation(ctx sdk.Context, delegator, provider, chainID } if provider != types.EMPTY_PROVIDER { - if err := k.decreaseStakeEntryDelegation(ctx, delegator, provider, chainID, amount, unstake); err != nil { - return err - } + return k.decreaseStakeEntryDelegation(ctx, delegator, provider, chainID, amount) } return nil @@ -224,7 +219,7 @@ func (k Keeper) increaseStakeEntryDelegation(ctx sdk.Context, delegator, provide } // decreaseStakeEntryDelegation decreases the (epochstorage) stake-entry of the provider for a chain. -func (k Keeper) decreaseStakeEntryDelegation(ctx sdk.Context, delegator, provider, chainID string, amount sdk.Coin, unstake bool) error { +func (k Keeper) decreaseStakeEntryDelegation(ctx sdk.Context, delegator, provider, chainID string, amount sdk.Coin) error { providerAddr, err := sdk.AccAddressFromBech32(provider) if err != nil { // panic:ok: this call was alreadys successful by the caller @@ -251,7 +246,7 @@ func (k Keeper) decreaseStakeEntryDelegation(ctx sdk.Context, delegator, provide if err != nil { return fmt.Errorf("invalid or insufficient funds: %w", err) } - if !unstake && stakeEntry.Stake.IsLT(k.getMinStake(ctx, chainID)) { + if stakeEntry.Stake.IsLT(k.getMinStake(ctx, chainID)) { return fmt.Errorf("provider self unbond to less than min stake") } } else { @@ -308,7 +303,7 @@ func (k Keeper) delegate(ctx sdk.Context, delegator, provider, chainID string, a // Redelegate lets a delegator transfer its delegation between providers, but // without the funds being subject to unstakeHoldBlocks witholding period. // (effective on next epoch) -func (k Keeper) Redelegate(ctx sdk.Context, delegator, from, to, fromChainID, toChainID string, amount sdk.Coin, unstake bool) error { +func (k Keeper) Redelegate(ctx sdk.Context, delegator, from, to, fromChainID, toChainID string, amount sdk.Coin) error { nextEpoch := k.epochstorageKeeper.GetCurrentNextEpoch(ctx) if _, err := sdk.AccAddressFromBech32(delegator); err != nil { @@ -348,7 +343,7 @@ func (k Keeper) Redelegate(ctx sdk.Context, delegator, from, to, fromChainID, to ) } - err = k.decreaseDelegation(ctx, delegator, from, fromChainID, amount, nextEpoch, unstake) + err = k.decreaseDelegation(ctx, delegator, from, fromChainID, amount, nextEpoch) if err != nil { return utils.LavaFormatWarning("failed to decrease delegation", err, utils.Attribute{Key: "delegator", Value: delegator}, @@ -368,7 +363,7 @@ func (k Keeper) Redelegate(ctx sdk.Context, delegator, from, to, fromChainID, to // before released and transferred back to the delegator. The rewards from the // provider will be updated accordingly (or terminate) from the next epoch. // (effective on next epoch) -func (k Keeper) unbond(ctx sdk.Context, delegator, provider, chainID string, amount sdk.Coin, unstake bool) error { +func (k Keeper) unbond(ctx sdk.Context, delegator, provider, chainID string, amount sdk.Coin) error { nextEpoch := k.epochstorageKeeper.GetCurrentNextEpoch(ctx) if _, err := sdk.AccAddressFromBech32(delegator); err != nil { @@ -391,7 +386,7 @@ func (k Keeper) unbond(ctx sdk.Context, delegator, provider, chainID string, amo return nil } - err := k.decreaseDelegation(ctx, delegator, provider, chainID, amount, nextEpoch, unstake) + err := k.decreaseDelegation(ctx, delegator, provider, chainID, amount, nextEpoch) if err != nil { return utils.LavaFormatWarning("failed to decrease delegation", err, utils.Attribute{Key: "delegator", Value: delegator}, @@ -526,10 +521,10 @@ func (k Keeper) UnbondUniformProviders(ctx sdk.Context, delegator string, amount if found { if delegation.Amount.Amount.GTE(amount.Amount) { // we have enough here, remove all from empty delegator and bail - return k.unbond(ctx, delegator, types.EMPTY_PROVIDER, types.EMPTY_PROVIDER_CHAINID, amount, false) + return k.unbond(ctx, delegator, types.EMPTY_PROVIDER, types.EMPTY_PROVIDER_CHAINID, amount) } else { // we dont have enough in the empty provider, remove everything and continue with the rest - err = k.unbond(ctx, delegator, types.EMPTY_PROVIDER, types.EMPTY_PROVIDER_CHAINID, delegation.Amount, false) + err = k.unbond(ctx, delegator, types.EMPTY_PROVIDER, types.EMPTY_PROVIDER_CHAINID, delegation.Amount) if err != nil { return err } @@ -588,7 +583,7 @@ func (k Keeper) UnbondUniformProviders(ctx sdk.Context, delegator string, amount // now unbond all for i := range delegations { key := delegationKey{provider: delegations[i].Provider, chainID: delegations[i].ChainID} - err := k.unbond(ctx, delegator, delegations[i].Provider, delegations[i].ChainID, unbondAmount[key], false) // ?? is it false? + err := k.unbond(ctx, delegator, delegations[i].Provider, delegations[i].ChainID, unbondAmount[key]) if err != nil { return err } diff --git a/x/dualstaking/keeper/msg_server_delegate.go b/x/dualstaking/keeper/msg_server_delegate.go index 5cf2bd13e0..cff5f04334 100644 --- a/x/dualstaking/keeper/msg_server_delegate.go +++ b/x/dualstaking/keeper/msg_server_delegate.go @@ -60,7 +60,6 @@ func (k Keeper) DelegateFull(ctx sdk.Context, delegator string, validator string types.EMPTY_PROVIDER_CHAINID, chainID, amount, - false, ) if err == nil { diff --git a/x/dualstaking/keeper/msg_server_redelegate.go b/x/dualstaking/keeper/msg_server_redelegate.go index 8dcc169c49..e269d1c4f2 100644 --- a/x/dualstaking/keeper/msg_server_redelegate.go +++ b/x/dualstaking/keeper/msg_server_redelegate.go @@ -19,7 +19,6 @@ func (k msgServer) Redelegate(goCtx context.Context, msg *types.MsgRedelegate) ( msg.FromChainID, msg.ToChainID, msg.Amount, - false, ) if err == nil { diff --git a/x/dualstaking/keeper/msg_server_unbond.go b/x/dualstaking/keeper/msg_server_unbond.go index e04da87e1e..289ee9e784 100644 --- a/x/dualstaking/keeper/msg_server_unbond.go +++ b/x/dualstaking/keeper/msg_server_unbond.go @@ -29,7 +29,6 @@ func (k Keeper) UnbondFull(ctx sdk.Context, delegator string, validator string, chainID, types.EMPTY_PROVIDER_CHAINID, amount, - unstake, ) if err != nil { return err From f636e34267498264ca552439abff4344bf734e02 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Thu, 30 Nov 2023 04:02:22 -0500 Subject: [PATCH 12/85] Freeze when lower than min stake and unfreeze when greater than min stake --- x/dualstaking/keeper/delegate.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/x/dualstaking/keeper/delegate.go b/x/dualstaking/keeper/delegate.go index b81f21b948..a133d7d7c0 100644 --- a/x/dualstaking/keeper/delegate.go +++ b/x/dualstaking/keeper/delegate.go @@ -209,6 +209,9 @@ func (k Keeper) increaseStakeEntryDelegation(ctx sdk.Context, delegator, provide if delegator == provider { stakeEntry.Stake = stakeEntry.Stake.Add(amount) + if stakeEntry.Stake.IsGTE(k.GetMinStake(ctx, chainID)) && stakeEntry.IsFrozen() { + stakeEntry.UnFreeze(uint64(ctx.BlockHeight())) + } } else { stakeEntry.DelegateTotal = stakeEntry.DelegateTotal.Add(amount) } @@ -246,8 +249,8 @@ func (k Keeper) decreaseStakeEntryDelegation(ctx sdk.Context, delegator, provide if err != nil { return fmt.Errorf("invalid or insufficient funds: %w", err) } - if stakeEntry.Stake.IsLT(k.getMinStake(ctx, chainID)) { - return fmt.Errorf("provider self unbond to less than min stake") + if stakeEntry.Stake.IsLT(k.GetMinStake(ctx, chainID)) { + stakeEntry.Freeze() } } else { stakeEntry.DelegateTotal, err = stakeEntry.DelegateTotal.SafeSub(amount) @@ -419,7 +422,7 @@ func (k Keeper) getUnbondHoldBlocks(ctx sdk.Context, chainID string) uint64 { // NOT REACHED } -func (k Keeper) getMinStake(ctx sdk.Context, chainID string) sdk.Coin { +func (k Keeper) GetMinStake(ctx sdk.Context, chainID string) sdk.Coin { spec, found := k.specKeeper.GetSpec(ctx, chainID) if !found { utils.LavaFormatError("critical: failed to get spec for chainID", From b9cfd5dfadf595fe2405b6f91204c0b6efb2774f Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Thu, 30 Nov 2023 04:13:03 -0500 Subject: [PATCH 13/85] Block unfreeze command if stake is lower than minStake --- x/pairing/keeper/msg_server_unfreeze.go | 11 +++++++++++ x/pairing/types/errors.go | 1 + x/pairing/types/expected_keepers.go | 1 + 3 files changed, 13 insertions(+) diff --git a/x/pairing/keeper/msg_server_unfreeze.go b/x/pairing/keeper/msg_server_unfreeze.go index 5431d113cd..10f4dc219e 100644 --- a/x/pairing/keeper/msg_server_unfreeze.go +++ b/x/pairing/keeper/msg_server_unfreeze.go @@ -24,6 +24,17 @@ func (k msgServer) UnfreezeProvider(goCtx context.Context, msg *types.MsgUnfreez return nil, utils.LavaFormatWarning("Unfreeze_cant_get_stake_entry", types.FreezeStakeEntryNotFoundError, []utils.Attribute{{Key: "chainID", Value: chainId}, {Key: "providerAddress", Value: msg.GetCreator()}}...) } + minStake := k.Keeper.dualstakingKeeper.GetMinStake(ctx, chainId) + if stakeEntry.Stake.IsLT(minStake) { + return nil, utils.LavaFormatWarning("Unfreeze_insufficient_stake", types.UnFreezeInsufficientStakeError, + []utils.Attribute{ + {Key: "chainID", Value: chainId}, + {Key: "providerAddress", Value: msg.GetCreator()}, + {Key: "stake", Value: stakeEntry.Stake}, + {Key: "minStake", Value: minStake}, + }...) + } + if stakeEntry.StakeAppliedBlock > currentBlock { // unfreeze the provider by making the StakeAppliedBlock the current block. This will let the provider be added to the pairing list in the next epoch, when current entries becomes the front of epochStorage stakeEntry.UnFreeze(currentBlock) diff --git a/x/pairing/types/errors.go b/x/pairing/types/errors.go index 131ba3375b..dff553d0aa 100644 --- a/x/pairing/types/errors.go +++ b/x/pairing/types/errors.go @@ -21,4 +21,5 @@ var ( DelegateCommissionOOBError = sdkerrors.New("DelegateCommissionOOBError Error", 694, "Delegation commission out of bound [0,100]") DelegateLimitError = sdkerrors.New("DelegateLimitError Error", 695, "Delegation limit coin is invalid") ProviderRewardError = sdkerrors.New("ProviderRewardError Error", 696, "could not calculate provider reward with delegations") + UnFreezeInsufficientStakeError = sdkerrors.New("UnFreezeInsufficientStakeError Error", 697, "could not unfreeze provider due to insufficient stake. Stake must be above minimum stake to unfreeze") ) diff --git a/x/pairing/types/expected_keepers.go b/x/pairing/types/expected_keepers.go index d384e2f245..8661e69de7 100644 --- a/x/pairing/types/expected_keepers.go +++ b/x/pairing/types/expected_keepers.go @@ -101,6 +101,7 @@ type DualstakingKeeper interface { RewardProvidersAndDelegators(ctx sdk.Context, providerAddr sdk.AccAddress, chainID string, totalReward math.Int, senderModule string, calcOnly bool) (providerReward math.Int, err error) DelegateFull(ctx sdk.Context, delegator string, validator string, provider string, chainID string, amount sdk.Coin) error UnbondFull(ctx sdk.Context, delegator string, validator string, provider string, chainID string, amount sdk.Coin, unstake bool) error + GetMinStake(ctx sdk.Context, chainID string) sdk.Coin } type FixationStoreKeeper interface { From 113bbb96d48e907ad316b402b6cf7b5a7d83a2d1 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Thu, 30 Nov 2023 07:25:43 -0500 Subject: [PATCH 14/85] Add tests --- x/dualstaking/keeper/delegate_test.go | 126 ++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/x/dualstaking/keeper/delegate_test.go b/x/dualstaking/keeper/delegate_test.go index 0819f8b17f..3cde5b8962 100644 --- a/x/dualstaking/keeper/delegate_test.go +++ b/x/dualstaking/keeper/delegate_test.go @@ -492,3 +492,129 @@ func TestBondUnbondBond(t *testing.T) { ts.verifyDelegatorsBalance() } + +func TestDualstakingUnbondStakeIsLowerThanMinStakeCausesFreeze(t *testing.T) { + ts := newTester(t) + + // 0 delegator, 1 provider staked, 0 provider unstaked, 0 provider unstaking + ts.setupForDelegation(0, 1, 0, 0) + + provider1Acct, provider1Addr := ts.GetAccount(common.PROVIDER, 0) + + staked := sdk.NewCoin("ulava", sdk.NewInt(testStake)) + + // unbond once + _, err := ts.TxDualstakingUnbond(provider1Addr, provider1Addr, ts.spec.Name, staked) + require.NoError(t, err) + + stakeEntry := ts.getStakeEntry(provider1Acct.Addr, ts.spec.Name) + require.True(t, staked.IsEqual(stakeEntry.Stake)) + + // advance epoch to digest the delegate + ts.AdvanceEpoch() + // now in effect + staked = staked.Sub(staked) + stakeEntry = ts.getStakeEntry(provider1Acct.Addr, ts.spec.Name) + require.True(t, staked.IsEqual(stakeEntry.Stake)) + require.True(t, stakeEntry.IsFrozen()) +} + +func TestDualstakingBondStakeIsGreaterThanMinStakeCausesUnFreeze(t *testing.T) { + ts := newTester(t) + + // 0 delegator, 0 provider staked, 1 provider unstaked, 0 provider unstaking + ts.setupForDelegation(0, 1, 0, 0) + + provider1Acct, provider1Addr := ts.GetAccount(common.PROVIDER, 0) + + staked := sdk.NewCoin("ulava", sdk.NewInt(testStake)) + + // delegate once + amount := sdk.NewCoin("ulava", sdk.NewInt(10000)) + _, err := ts.TxDualstakingDelegate(provider1Addr, provider1Addr, ts.spec.Name, amount) + require.NoError(t, err) + + // advance epoch to digest the delegate + ts.AdvanceEpoch() + // now in effect + staked = staked.Add(amount) + stakeEntry := ts.getStakeEntry(provider1Acct.Addr, ts.spec.Name) + require.True(t, staked.IsEqual(stakeEntry.Stake)) + require.False(t, stakeEntry.IsFrozen()) +} + +func TestDualstakingRedelegateFreezeOneUnFreezeOther(t *testing.T) { + ts := newTester(t) + + // 0 delegator, 2 provider staked, 0 provider unstaked, 0 provider unstaking + ts.setupForDelegation(0, 2, 0, 0) + + provider1Acct, provider1Addr := ts.GetAccount(common.PROVIDER, 0) + provider2Acct, provider2Addr := ts.GetAccount(common.PROVIDER, 1) + + stake := sdk.NewCoin("ulava", sdk.NewInt(testStake)) + + // redelegate once + _, err := ts.TxDualstakingRedelegate(provider1Addr, provider1Addr, provider2Addr, ts.spec.Name, ts.spec.Name, stake) + require.NoError(t, err) + + // advance epoch to digest the delegate + ts.AdvanceEpoch() + // now in effect + + stakeEntry := ts.getStakeEntry(provider1Acct.Addr, ts.spec.Name) + require.True(t, stakeEntry.Stake.IsZero()) + require.True(t, stakeEntry.IsFrozen()) + + stakeEntry = ts.getStakeEntry(provider2Acct.Addr, ts.spec.Name) + require.True(t, stake.IsEqual(stakeEntry.Stake)) + require.True(t, stake.IsEqual(stakeEntry.DelegateTotal)) + require.False(t, stakeEntry.IsFrozen()) + + // redelegate again + _, err = ts.TxDualstakingRedelegate(provider2Addr, provider2Addr, provider1Addr, ts.spec.Name, ts.spec.Name, stake) + require.NoError(t, err) + + // advance epoch to digest the delegate + ts.AdvanceEpoch() + // now in effect + + stakeEntry = ts.getStakeEntry(provider1Acct.Addr, ts.spec.Name) + require.True(t, stakeEntry.Stake.IsZero()) + require.True(t, stake.IsEqual(stakeEntry.DelegateTotal)) + require.True(t, stakeEntry.IsFrozen()) + + stakeEntry = ts.getStakeEntry(provider2Acct.Addr, ts.spec.Name) + require.True(t, stakeEntry.Stake.IsZero()) + require.True(t, stake.IsEqual(stakeEntry.DelegateTotal)) + require.True(t, stakeEntry.IsFrozen()) +} + +func TestStakingUnbondStakeIsLowerThanMinStakeCausesFreeze(t *testing.T) { + ts := newTester(t) + + // 0 delegator, 1 provider staked, 0 provider unstaked, 0 provider unstaking + ts.setupForDelegation(0, 1, 0, 0) + + provider1Acct, _ := ts.GetAccount(common.PROVIDER, 0) + validator1Acct, _ := ts.GetAccount(common.VALIDATOR, 0) + + stakeInt := sdk.NewInt(testStake) + stake := sdk.NewCoin("ulava", stakeInt) + + stakeEntry := ts.getStakeEntry(provider1Acct.Addr, ts.spec.Name) + require.True(t, stake.IsEqual(stakeEntry.Stake)) + require.False(t, stakeEntry.IsFrozen()) + + // unbond once + _, err := ts.TxUnbondValidator(provider1Acct, validator1Acct, stakeInt) + require.NoError(t, err) + + // advance epoch to digest the delegate + ts.AdvanceEpoch() + // now in effect + + stakeEntry = ts.getStakeEntry(provider1Acct.Addr, ts.spec.Name) + require.True(t, stakeEntry.Stake.IsZero()) + require.True(t, stakeEntry.IsFrozen()) +} From b9b7d03c9a4f11b6b5113728d6bc5b62108788e5 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Thu, 30 Nov 2023 08:09:02 -0500 Subject: [PATCH 15/85] Fix pairing test --- x/pairing/keeper/pairing_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/x/pairing/keeper/pairing_test.go b/x/pairing/keeper/pairing_test.go index ad1531b4a6..c66b805aff 100644 --- a/x/pairing/keeper/pairing_test.go +++ b/x/pairing/keeper/pairing_test.go @@ -879,7 +879,7 @@ func TestPairingUniformDistribution(t *testing.T) { ts.verifyPairingDistribution("uniform distribution", clientAddr, providersToPair, weightFunc) } -// Test that random selection of providers is alighned with their stake +// Test that random selection of providers is aligned with their stake func TestPairingDistributionPerStake(t *testing.T) { providersCount := 10 providersToPair := 3 @@ -893,8 +893,7 @@ func TestPairingDistributionPerStake(t *testing.T) { // double the stake of the first provider p := allProviders.StakeEntry[0] - stake := p.Stake.Amount.Int64() - err = ts.StakeProviderExtra(p.Address, ts.spec, stake*2, p.Endpoints, p.Geolocation, p.Moniker) + _, err = ts.TxDualstakingDelegate(p.Address, p.Address, ts.spec.Index, p.Stake) require.NoError(t, err) ts.AdvanceEpoch() From 0a50db34706aee0bc173ccf23bba5e57b9dc15ff Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Thu, 30 Nov 2023 08:35:32 -0500 Subject: [PATCH 16/85] CR Fix: Use TokenDenom func --- testutil/common/tester.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testutil/common/tester.go b/testutil/common/tester.go index 0d61026818..d7369ea720 100644 --- a/testutil/common/tester.go +++ b/testutil/common/tester.go @@ -171,7 +171,7 @@ func (ts *Tester) StakeProviderExtra( } } - stake := sdk.NewCoin(ts.Keepers.StakingKeeper.BondDenom(ts.Ctx), sdk.NewInt(amount)) + stake := sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(amount)) _, err := ts.TxPairingStakeProvider(addr, spec.Name, stake, endpoints, geoloc, moniker) return err From 94cd4b252152f7b27685976c085fb4e0fcdc02d0 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Sat, 2 Dec 2023 14:53:01 -0500 Subject: [PATCH 17/85] CR Fix: Set deleted field as reserved --- proto/lavanet/lava/pairing/query.proto | 1 + x/pairing/types/query.pb.go | 199 +++++++++++++------------ 2 files changed, 101 insertions(+), 99 deletions(-) diff --git a/proto/lavanet/lava/pairing/query.proto b/proto/lavanet/lava/pairing/query.proto index f03f9f42d3..1cfe159838 100644 --- a/proto/lavanet/lava/pairing/query.proto +++ b/proto/lavanet/lava/pairing/query.proto @@ -120,6 +120,7 @@ message QueryProvidersRequest { message QueryProvidersResponse { repeated lavanet.lava.epochstorage.StakeEntry stakeEntry = 1 [(gogoproto.nullable) = false]; + reserved 2; } message QueryGetPairingRequest { diff --git a/x/pairing/types/query.pb.go b/x/pairing/types/query.pb.go index cec1ff2a7b..04e8332bcc 100644 --- a/x/pairing/types/query.pb.go +++ b/x/pairing/types/query.pb.go @@ -1821,7 +1821,7 @@ func init() { func init() { proto.RegisterFile("lavanet/lava/pairing/query.proto", fileDescriptor_9e149ce9d21da0d8) } var fileDescriptor_9e149ce9d21da0d8 = []byte{ - // 1999 bytes of a gzipped FileDescriptorProto + // 2001 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x59, 0xcb, 0x6f, 0xdc, 0x6a, 0x15, 0xaf, 0x27, 0x8f, 0x26, 0xa7, 0x4d, 0x5b, 0x7d, 0x37, 0x49, 0x13, 0x93, 0x9b, 0xa6, 0x5f, 0x5f, 0x09, 0x0d, 0xe3, 0x9b, 0xe9, 0xe3, 0x46, 0x7d, 0x41, 0xd2, 0x17, 0x29, 0x81, 0x9b, 0x4c, @@ -1849,104 +1849,105 @@ var fileDescriptor_9e149ce9d21da0d8 = []byte{ 0x4c, 0x31, 0xab, 0xc2, 0x8a, 0x42, 0x6b, 0x75, 0xf0, 0x8b, 0x7f, 0x5d, 0x3a, 0x55, 0x46, 0x0d, 0xba, 0x09, 0x13, 0xc2, 0x24, 0x12, 0x15, 0xf9, 0x22, 0x53, 0x70, 0x5a, 0xdf, 0xd3, 0x0c, 0x6b, 0xed, 0x09, 0xb7, 0x3a, 0x5a, 0x8e, 0x8e, 0x64, 0x16, 0xc0, 0xdb, 0xb3, 0x5f, 0x3f, 0x73, 0xed, - 0x1f, 0x30, 0x6b, 0xaa, 0x30, 0x27, 0xcd, 0x8f, 0x94, 0x13, 0x57, 0x28, 0x83, 0xc9, 0x76, 0x93, - 0x08, 0xf4, 0x5b, 0x00, 0x9c, 0xe6, 0xa7, 0x21, 0xcb, 0x53, 0xd2, 0xdc, 0xc0, 0xfc, 0x99, 0xd2, - 0xb5, 0x34, 0xd8, 0x64, 0x4e, 0x8a, 0x5b, 0xb1, 0x30, 0xa2, 0x4e, 0xa8, 0xd3, 0x17, 0xe8, 0xe6, - 0x39, 0xf3, 0x37, 0x44, 0x84, 0xdd, 0xa1, 0x4f, 0xc2, 0xb0, 0x28, 0x0c, 0x0e, 0x7b, 0xb4, 0x8c, - 0x27, 0xfa, 0xbb, 0x02, 0x5c, 0x3c, 0x62, 0x0c, 0x41, 0xaf, 0xc1, 0x68, 0x54, 0x45, 0xde, 0xfb, - 0x60, 0x6e, 0x69, 0x93, 0x2b, 0x30, 0xa6, 0x07, 0xae, 0x1b, 0x16, 0x26, 0xd7, 0xe1, 0x28, 0x06, - 0xcb, 0x67, 0xf1, 0xe2, 0xd3, 0xf0, 0x1a, 0x59, 0x86, 0xe9, 0xb0, 0x10, 0x54, 0x93, 0xed, 0xfa, - 0xaa, 0x6f, 0xab, 0x16, 0x3b, 0xf0, 0x55, 0xcc, 0xe1, 0xd4, 0x00, 0x57, 0x98, 0x08, 0x05, 0xd6, - 0xd9, 0xae, 0xff, 0x5d, 0xfb, 0x3b, 0xec, 0x20, 0x42, 0x4c, 0xee, 0xc0, 0xc5, 0xf0, 0x21, 0x54, - 0x4d, 0xcd, 0xf3, 0xd5, 0xc0, 0xa9, 0x68, 0x3e, 0xab, 0xa8, 0x3b, 0xa6, 0xad, 0xef, 0x4f, 0x0d, - 0x72, 0xbd, 0xf1, 0xf0, 0xf6, 0xba, 0xe6, 0xf9, 0xdb, 0xe2, 0xe6, 0x6a, 0x78, 0x8f, 0x2c, 0xc1, - 0x04, 0x17, 0x52, 0xed, 0xdd, 0xb4, 0xb3, 0x21, 0xae, 0x44, 0xf8, 0xcd, 0x4f, 0x76, 0x13, 0x9e, - 0xe8, 0x8f, 0x60, 0x9a, 0xd3, 0xf5, 0x3d, 0xe6, 0x1a, 0xbb, 0x87, 0xc7, 0xa5, 0x9f, 0xc8, 0x30, - 0x12, 0x91, 0xc4, 0x23, 0x1c, 0x2d, 0xc7, 0x67, 0x32, 0x0e, 0x43, 0xc9, 0x10, 0xc4, 0x81, 0x7e, - 0x2e, 0x81, 0x9c, 0x85, 0x00, 0x73, 0x36, 0x0e, 0x43, 0x75, 0xcd, 0x34, 0x2a, 0x1c, 0xc0, 0x48, - 0x59, 0x1c, 0xc8, 0x02, 0x5c, 0x08, 0x43, 0x63, 0x15, 0xb5, 0x95, 0x50, 0x41, 0xe8, 0x79, 0x71, - 0x3d, 0xae, 0x58, 0x32, 0x07, 0x67, 0xf5, 0x40, 0x75, 0x98, 0x8b, 0x89, 0x12, 0xce, 0x41, 0x0f, - 0x36, 0x98, 0x2b, 0xd2, 0xf4, 0x21, 0x00, 0x3e, 0xdb, 0xaa, 0x51, 0xe1, 0x54, 0x8d, 0xf2, 0x54, - 0x87, 0x57, 0xd6, 0x2a, 0x2f, 0x06, 0x47, 0x0a, 0x17, 0x06, 0xe8, 0x1a, 0x2c, 0x45, 0x65, 0xb5, - 0xcd, 0xdf, 0x53, 0x1b, 0xe2, 0x35, 0xb5, 0x25, 0x8a, 0xe5, 0x31, 0x0f, 0x3f, 0xf2, 0x1a, 0xf1, - 0x37, 0x0e, 0x43, 0x86, 0x55, 0x61, 0x07, 0xc8, 0x9e, 0x38, 0xd0, 0x3f, 0x4b, 0x50, 0xea, 0xc7, - 0x16, 0x32, 0xf1, 0xa9, 0x04, 0x34, 0xe8, 0x2a, 0x8e, 0x2f, 0x8e, 0xe5, 0xec, 0x17, 0x47, 0x77, - 0x77, 0x58, 0xea, 0x3d, 0x78, 0xa2, 0x0d, 0xa4, 0x64, 0xc5, 0x34, 0x7b, 0xa7, 0xe4, 0x19, 0x40, - 0xab, 0xa1, 0x21, 0xd8, 0xeb, 0x45, 0xd1, 0xfd, 0x8a, 0x61, 0xf7, 0x2b, 0x8a, 0x06, 0x8b, 0xdd, - 0xaf, 0xb8, 0xa1, 0x55, 0x19, 0xea, 0x96, 0x13, 0x9a, 0xf4, 0xd3, 0x02, 0x92, 0xd8, 0xa3, 0xf7, - 0x7e, 0x49, 0x1c, 0xf8, 0xff, 0x90, 0x48, 0x9e, 0xa7, 0xf8, 0x28, 0x70, 0x3e, 0x6e, 0x74, 0xe5, - 0x43, 0x44, 0x93, 0x22, 0xe4, 0x21, 0x5c, 0x8b, 0xdf, 0x7b, 0x68, 0x3c, 0xed, 0x38, 0xbf, 0x28, - 0x3f, 0x93, 0xe0, 0x7a, 0x37, 0x7d, 0xe4, 0xf0, 0x25, 0x4c, 0x3a, 0x99, 0x12, 0x98, 0xce, 0xc5, - 0x0e, 0x4d, 0x2b, 0x53, 0x07, 0xa9, 0xea, 0x60, 0x91, 0xda, 0x18, 0xd5, 0x8a, 0x69, 0xe6, 0x47, - 0x75, 0x52, 0x75, 0xf5, 0xcf, 0x88, 0x87, 0x1c, 0x8f, 0x3d, 0xf0, 0x30, 0x70, 0xb2, 0x3c, 0x9c, - 0x5c, 0x99, 0xdc, 0x86, 0x99, 0x28, 0xcd, 0xfc, 0xed, 0x87, 0x7e, 0xbc, 0xfc, 0xea, 0x70, 0xe0, - 0xc3, 0x0e, 0x5a, 0xc8, 0xc5, 0x27, 0x30, 0xc6, 0x92, 0x37, 0x30, 0x03, 0x57, 0xb2, 0x29, 0x48, - 0xd9, 0xc0, 0xc8, 0xd3, 0xfa, 0x74, 0x17, 0x71, 0xae, 0x98, 0x66, 0x26, 0xce, 0x93, 0xca, 0xf7, - 0x1f, 0x24, 0x0c, 0xed, 0xa8, 0xa3, 0xce, 0xa1, 0x0d, 0x1c, 0x27, 0xb4, 0x93, 0xcb, 0xa5, 0x86, - 0x13, 0xdf, 0xb6, 0xc7, 0x5c, 0x3e, 0xa7, 0x24, 0xfa, 0xb6, 0x56, 0xa9, 0xb8, 0xcc, 0xf3, 0xa2, - 0xbe, 0x8d, 0xc7, 0x64, 0x47, 0x2f, 0xa4, 0x3b, 0x7a, 0xdc, 0x9d, 0x07, 0x92, 0xdd, 0xf9, 0x35, - 0x8e, 0x66, 0x09, 0x17, 0x48, 0xcb, 0x73, 0x18, 0xd1, 0x6d, 0xcb, 0x0b, 0x6a, 0x71, 0xcf, 0xe9, - 0x6b, 0x96, 0x8a, 0x95, 0x43, 0xc7, 0x35, 0xed, 0xe0, 0xf1, 0x36, 0x8e, 0x50, 0xe2, 0x40, 0xef, - 0xc3, 0x25, 0xee, 0x78, 0x2b, 0xdc, 0x93, 0xf4, 0xb8, 0x9d, 0xaf, 0x1b, 0x9e, 0xdf, 0x75, 0x3a, - 0xa1, 0x35, 0x98, 0xeb, 0xac, 0x7c, 0xe2, 0xc3, 0x20, 0xdd, 0x84, 0xaf, 0x70, 0x77, 0x4f, 0x77, - 0x77, 0x99, 0xee, 0x1b, 0x75, 0xb6, 0xc1, 0x37, 0xa4, 0x08, 0xa7, 0xdc, 0xc6, 0xd4, 0x68, 0x22, - 0xf8, 0x49, 0x18, 0x0e, 0x27, 0xb9, 0x38, 0x1d, 0x78, 0xa2, 0xbf, 0x94, 0xb0, 0xfe, 0x8f, 0xd8, - 0x44, 0xf8, 0x25, 0x18, 0x16, 0x7b, 0x18, 0x92, 0x2f, 0xb7, 0x95, 0x63, 0xb8, 0xa9, 0x15, 0x51, - 0x07, 0x25, 0xc9, 0x0a, 0x9c, 0x73, 0x98, 0x55, 0x31, 0xac, 0xaa, 0x8a, 0xba, 0x85, 0xae, 0xba, - 0x63, 0xa8, 0x21, 0x8e, 0xf4, 0xbf, 0x12, 0x8e, 0xd7, 0x5b, 0x95, 0xfd, 0xf6, 0x51, 0xed, 0x39, - 0x9c, 0x8e, 0xe6, 0x4d, 0x81, 0xe9, 0x6b, 0xd9, 0x8f, 0x48, 0x87, 0xf1, 0xbc, 0x1c, 0x69, 0x93, - 0x09, 0x18, 0xae, 0x69, 0x07, 0xaa, 0x1e, 0x24, 0x4b, 0x22, 0x20, 0x37, 0x61, 0x30, 0x64, 0x87, - 0x17, 0xe8, 0x99, 0xd2, 0xc5, 0xb4, 0x71, 0xbe, 0xb3, 0x6e, 0x39, 0x4c, 0x2f, 0x73, 0x21, 0xb2, - 0x06, 0xe7, 0xa3, 0x45, 0x4c, 0xc5, 0x95, 0x6a, 0x90, 0xeb, 0xcd, 0xa5, 0xf5, 0xe2, 0x6d, 0xad, - 0xbe, 0x84, 0x6b, 0x55, 0xf9, 0x5c, 0x74, 0x4d, 0x9c, 0xe9, 0xd7, 0xe1, 0x72, 0x6a, 0x0b, 0xfa, - 0xb6, 0x6d, 0xf9, 0x7b, 0xe6, 0xe1, 0x86, 0x76, 0x68, 0x07, 0x7e, 0x22, 0xc9, 0x4e, 0x72, 0x04, - 0x4b, 0x0c, 0xbe, 0x74, 0x1f, 0xc8, 0x56, 0x62, 0xcd, 0x14, 0x8a, 0x84, 0xc2, 0xd9, 0xe4, 0xf2, - 0x89, 0x5a, 0xa9, 0x6b, 0x64, 0x1a, 0x46, 0x78, 0x4d, 0x87, 0x83, 0x69, 0xea, 0x79, 0xad, 0x84, - 0x95, 0xa3, 0xd5, 0xec, 0xc0, 0xf2, 0xf1, 0x81, 0xc5, 0x13, 0xfd, 0x21, 0xd0, 0x3c, 0xb4, 0xad, - 0xb1, 0xda, 0xb7, 0x7d, 0xcd, 0xe4, 0x5e, 0x07, 0xcb, 0xe2, 0x40, 0x56, 0xe1, 0x74, 0x85, 0xf9, - 0x9a, 0x61, 0x7a, 0x53, 0x05, 0xfe, 0x44, 0xcc, 0x67, 0x67, 0xf0, 0x68, 0x34, 0xe5, 0x48, 0x91, - 0x3e, 0x81, 0x73, 0x89, 0x0e, 0x17, 0x06, 0x9a, 0x43, 0x4d, 0x22, 0x8a, 0x42, 0x2a, 0x8a, 0x97, - 0x30, 0xf6, 0x58, 0x3c, 0xcc, 0x68, 0x24, 0xc9, 0x84, 0x94, 0x66, 0xe2, 0x51, 0x58, 0x77, 0xa1, - 0x50, 0x84, 0xfa, 0x6a, 0xd7, 0xc6, 0xcb, 0x11, 0xa3, 0x12, 0x7d, 0x8c, 0x33, 0x46, 0x32, 0xaa, - 0x4e, 0x39, 0xee, 0xf4, 0x20, 0xd3, 0x26, 0x8e, 0x0d, 0x39, 0x46, 0x72, 0xa9, 0x7f, 0xd8, 0x4e, - 0x7d, 0x87, 0xfe, 0x92, 0x62, 0x25, 0x66, 0xbd, 0xf4, 0xeb, 0x29, 0x18, 0xe2, 0xfe, 0xc9, 0x4f, - 0x25, 0x18, 0x16, 0x85, 0x4b, 0xe6, 0x73, 0x9e, 0xbf, 0xd4, 0xe7, 0x08, 0x79, 0xa1, 0x07, 0x49, - 0x01, 0x9f, 0x5e, 0xfd, 0xc9, 0x9b, 0xff, 0xfc, 0xa2, 0x30, 0x4b, 0x66, 0x94, 0x9c, 0xcf, 0x50, - 0xe4, 0x57, 0x12, 0x8c, 0xb6, 0x76, 0xb0, 0x9b, 0x79, 0xe6, 0xdb, 0x3e, 0x57, 0xc8, 0x8b, 0xbd, - 0x09, 0x23, 0x9c, 0x25, 0x0e, 0xe7, 0x26, 0x59, 0x50, 0x72, 0x3f, 0x44, 0x79, 0x4a, 0x03, 0x9b, - 0x43, 0x93, 0xfc, 0x46, 0x02, 0x68, 0xbd, 0x7e, 0xc8, 0x62, 0x8f, 0x6f, 0x29, 0x81, 0xae, 0xbf, - 0x77, 0x1a, 0x7d, 0xc0, 0xe1, 0xdd, 0x25, 0xb7, 0xb3, 0xe1, 0x55, 0x59, 0xbc, 0xa3, 0xb7, 0x00, - 0x2a, 0x0d, 0xb1, 0x4c, 0x37, 0xc9, 0x5f, 0x24, 0x18, 0x4b, 0xad, 0xc5, 0x44, 0xc9, 0x71, 0x9f, - 0xb5, 0xc2, 0xcb, 0x1f, 0xf5, 0xae, 0x80, 0x90, 0xcb, 0x1c, 0xf2, 0x3a, 0x79, 0x91, 0x0d, 0xb9, - 0xce, 0x95, 0x72, 0x50, 0x2b, 0x8d, 0x88, 0xf4, 0xa6, 0xd2, 0xe0, 0x53, 0x44, 0x93, 0xfc, 0xac, - 0x00, 0x74, 0xbb, 0x87, 0x65, 0x28, 0x9f, 0xdc, 0x9e, 0xb7, 0x4c, 0xf9, 0x9b, 0xc7, 0x37, 0x84, - 0x6c, 0xac, 0x73, 0x36, 0x9e, 0x91, 0x27, 0xca, 0x31, 0xbe, 0x59, 0x2a, 0x0d, 0x3e, 0x46, 0x37, - 0xc9, 0x8f, 0x0b, 0x70, 0xad, 0xbb, 0xf3, 0x15, 0xd3, 0xcc, 0xa5, 0xa2, 0x9f, 0x85, 0x3b, 0x97, - 0x8a, 0xbe, 0x76, 0x67, 0xfa, 0x84, 0x53, 0xf1, 0x88, 0x3c, 0x38, 0x0e, 0x15, 0xe4, 0x8d, 0x04, - 0x93, 0xd9, 0x2b, 0x10, 0xb9, 0xdf, 0xe5, 0xd9, 0xca, 0x5b, 0x00, 0xe5, 0x07, 0xef, 0xa7, 0x8c, - 0xb1, 0x3d, 0xe2, 0xb1, 0x2d, 0x93, 0xbb, 0x4a, 0x5f, 0xdf, 0xb3, 0xe3, 0xc4, 0xfe, 0x4d, 0x82, - 0xe9, 0x6c, 0x17, 0x61, 0x32, 0xef, 0xe7, 0xe7, 0xe0, 0xfd, 0x03, 0xeb, 0xba, 0xa4, 0xd2, 0xbb, - 0x3c, 0xb0, 0x8f, 0x48, 0xb1, 0xbf, 0xc0, 0xc8, 0xef, 0x25, 0x18, 0x4b, 0xed, 0x32, 0xa4, 0x94, - 0x4f, 0x70, 0xd6, 0x96, 0x26, 0xdf, 0xea, 0x4b, 0x07, 0x21, 0xdf, 0xe6, 0x90, 0x8b, 0x64, 0x51, - 0xe9, 0xe1, 0x57, 0x8c, 0x38, 0x03, 0xbf, 0x95, 0xe0, 0x42, 0xca, 0x5e, 0x48, 0x7c, 0x29, 0x9f, - 0xbb, 0xbe, 0x31, 0x77, 0x5a, 0x12, 0xe9, 0x22, 0xc7, 0x7c, 0x9d, 0x5c, 0xed, 0x05, 0x33, 0xf9, - 0x5c, 0x82, 0xd1, 0x78, 0xa3, 0xca, 0xed, 0x8e, 0xed, 0xab, 0x5d, 0x6e, 0x77, 0x3c, 0xb2, 0xa4, - 0x75, 0x6b, 0x3f, 0x81, 0xc7, 0x5c, 0xf1, 0x43, 0x89, 0xd2, 0xc0, 0x0d, 0xb1, 0x99, 0x68, 0x94, - 0x7f, 0x92, 0xe0, 0x83, 0x8c, 0x15, 0x8a, 0xdc, 0xc9, 0xc1, 0xd0, 0x79, 0x5f, 0x93, 0xef, 0xf6, - 0xab, 0x86, 0x41, 0x3c, 0xe4, 0x41, 0x7c, 0x4c, 0xee, 0x64, 0x07, 0xe1, 0x71, 0xd5, 0xd6, 0x87, - 0x60, 0xd5, 0x34, 0x3c, 0x3f, 0x11, 0xc5, 0x1f, 0x25, 0x38, 0xdf, 0xb6, 0x45, 0x91, 0xa5, 0x1c, - 0x28, 0xd9, 0x5b, 0x9c, 0x5c, 0xea, 0x47, 0x05, 0x91, 0xaf, 0x72, 0xe4, 0x0f, 0xc8, 0xbd, 0x0e, - 0x55, 0x11, 0xa9, 0xe1, 0x3a, 0xa6, 0x34, 0xa2, 0x71, 0xb2, 0xa9, 0x34, 0xc4, 0x22, 0xd8, 0x24, - 0x7f, 0x95, 0x60, 0x22, 0x73, 0x96, 0x27, 0x1f, 0xf7, 0x30, 0x28, 0x65, 0xcd, 0xb1, 0xf2, 0x72, - 0xff, 0x8a, 0x18, 0xd0, 0x37, 0x78, 0x40, 0xf7, 0xc8, 0x72, 0x97, 0xb7, 0x49, 0x4d, 0x68, 0xab, - 0x62, 0xc4, 0x4e, 0x4c, 0x04, 0xe4, 0x1f, 0x12, 0x4c, 0x77, 0x9c, 0x91, 0x73, 0x5f, 0x94, 0xdd, - 0xc6, 0xf3, 0xdc, 0x17, 0x65, 0xd7, 0xb1, 0xbc, 0x5b, 0x77, 0x4b, 0xae, 0x65, 0x47, 0xc2, 0x8b, - 0xd3, 0x46, 0x3e, 0x93, 0x00, 0x5a, 0xab, 0xf1, 0x09, 0xce, 0x96, 0x47, 0xf7, 0x6d, 0xba, 0xc0, - 0x11, 0x5f, 0x21, 0x97, 0x3b, 0x20, 0xae, 0xec, 0x47, 0x53, 0xda, 0xea, 0xca, 0x17, 0x6f, 0x67, - 0xa5, 0x2f, 0xdf, 0xce, 0x4a, 0xff, 0x7e, 0x3b, 0x2b, 0xfd, 0xfc, 0xdd, 0xec, 0xa9, 0x2f, 0xdf, - 0xcd, 0x9e, 0xfa, 0xfb, 0xbb, 0xd9, 0x53, 0xdf, 0xbf, 0x51, 0x35, 0xfc, 0xbd, 0x60, 0xa7, 0xa8, - 0xdb, 0xb5, 0xb4, 0x99, 0x83, 0xd8, 0x90, 0x7f, 0xe8, 0x30, 0x6f, 0x67, 0x98, 0xff, 0x9c, 0x79, - 0xeb, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x34, 0x6f, 0x0d, 0x41, 0x16, 0x1f, 0x00, 0x00, + 0x1f, 0x30, 0x6b, 0xaa, 0x30, 0x27, 0xcd, 0x8f, 0x94, 0x13, 0x57, 0xe8, 0x3e, 0x4c, 0xb6, 0x9b, + 0x44, 0xa0, 0xdf, 0x02, 0xe0, 0x34, 0x3f, 0x0d, 0x59, 0x9e, 0x92, 0xe6, 0x06, 0xe6, 0xcf, 0x94, + 0xae, 0xa5, 0xc1, 0x26, 0x73, 0x52, 0xdc, 0x8a, 0x85, 0x11, 0x75, 0x42, 0xfd, 0xc5, 0xe0, 0x48, + 0xe1, 0xc2, 0x00, 0x7d, 0x81, 0xce, 0x9e, 0x33, 0x7f, 0x43, 0xc4, 0xd9, 0x3d, 0x80, 0x49, 0x18, + 0x16, 0xe5, 0xc1, 0xc1, 0x8f, 0x96, 0xf1, 0x44, 0x7f, 0x57, 0x80, 0x8b, 0x47, 0x8c, 0x21, 0xf4, + 0x35, 0x18, 0x8d, 0x6a, 0xc9, 0x7b, 0x1f, 0xe4, 0x2d, 0x6d, 0x72, 0x05, 0xc6, 0xf4, 0xc0, 0x75, + 0xc3, 0xf2, 0xe4, 0x3a, 0x1c, 0xc5, 0x60, 0xf9, 0x2c, 0x5e, 0x7c, 0x1a, 0x5e, 0x23, 0xcb, 0x30, + 0x1d, 0x96, 0x83, 0x6a, 0xb2, 0x5d, 0x5f, 0xf5, 0x6d, 0xd5, 0x62, 0x07, 0xbe, 0x8a, 0x99, 0x9c, + 0x1a, 0xe0, 0x0a, 0x13, 0xa1, 0xc0, 0x3a, 0xdb, 0xf5, 0xbf, 0x6b, 0x7f, 0x87, 0x1d, 0x44, 0x88, + 0xc9, 0x1d, 0xb8, 0x18, 0x3e, 0x8a, 0xaa, 0xa9, 0x79, 0xbe, 0x1a, 0x38, 0x15, 0xcd, 0x67, 0x15, + 0x75, 0xc7, 0xb4, 0xf5, 0xfd, 0xa9, 0x41, 0xae, 0x37, 0x1e, 0xde, 0x5e, 0xd7, 0x3c, 0x7f, 0x5b, + 0xdc, 0x5c, 0x0d, 0xef, 0x91, 0x25, 0x98, 0xe0, 0x42, 0xaa, 0xbd, 0x9b, 0x76, 0x36, 0xc4, 0x95, + 0x08, 0xbf, 0xf9, 0xc9, 0x6e, 0xc2, 0x13, 0xfd, 0x11, 0x4c, 0x73, 0xba, 0xbe, 0xc7, 0x5c, 0x63, + 0xf7, 0xf0, 0xb8, 0xf4, 0x13, 0x19, 0x46, 0x22, 0x92, 0x78, 0x84, 0xa3, 0xe5, 0xf8, 0x4c, 0xc6, + 0x61, 0x28, 0x19, 0x82, 0x38, 0xd0, 0xcf, 0x25, 0x90, 0xb3, 0x10, 0x60, 0xce, 0xc6, 0x61, 0xa8, + 0xae, 0x99, 0x46, 0x85, 0x03, 0x18, 0x29, 0x8b, 0x03, 0x59, 0x80, 0x0b, 0x61, 0x68, 0xac, 0xa2, + 0xb6, 0x12, 0x2a, 0x08, 0x3d, 0x2f, 0xae, 0xc7, 0x75, 0x4b, 0xe6, 0xe0, 0xac, 0x1e, 0xa8, 0x0e, + 0x73, 0x31, 0x51, 0xc2, 0x39, 0xe8, 0xc1, 0x06, 0x73, 0x45, 0x9a, 0x3e, 0x04, 0xc0, 0x27, 0x5c, + 0x35, 0x2a, 0x9c, 0xaa, 0x51, 0x9e, 0xea, 0xf0, 0xca, 0x5a, 0x05, 0x6b, 0x74, 0x0d, 0x96, 0xa2, + 0xb2, 0xda, 0xe6, 0x6f, 0xab, 0x0d, 0xf1, 0xb2, 0xda, 0x12, 0xc5, 0xf2, 0x98, 0x87, 0x1f, 0x79, + 0x8d, 0xf8, 0x1b, 0x87, 0x21, 0xc3, 0xaa, 0xb0, 0x03, 0x64, 0x4f, 0x1c, 0xe8, 0x9f, 0x25, 0x28, + 0xf5, 0x63, 0x0b, 0x99, 0xf8, 0x54, 0x02, 0x1a, 0x74, 0x15, 0xc7, 0xd7, 0xc7, 0x72, 0xf6, 0xeb, + 0xa3, 0xbb, 0x3b, 0x2c, 0xf5, 0x1e, 0x3c, 0xd1, 0x06, 0x52, 0xb2, 0x62, 0x9a, 0xbd, 0x53, 0xf2, + 0x0c, 0xa0, 0xd5, 0xd6, 0x10, 0xec, 0xf5, 0xa2, 0xe8, 0x81, 0xc5, 0xb0, 0x07, 0x16, 0x45, 0x9b, + 0xc5, 0x1e, 0x58, 0xdc, 0xd0, 0xaa, 0x0c, 0x75, 0xcb, 0x09, 0x4d, 0xfa, 0x69, 0x01, 0x49, 0xec, + 0xd1, 0x7b, 0xbf, 0x24, 0x0e, 0xfc, 0x7f, 0x48, 0x24, 0xcf, 0x53, 0x7c, 0x14, 0x38, 0x1f, 0x37, + 0xba, 0xf2, 0x21, 0xa2, 0x49, 0x11, 0xf2, 0x10, 0xae, 0xc5, 0xef, 0x3d, 0x34, 0x9e, 0x76, 0x9c, + 0x5f, 0x94, 0x9f, 0x49, 0x70, 0xbd, 0x9b, 0x3e, 0x72, 0xf8, 0x12, 0x26, 0x9d, 0x4c, 0x09, 0x4c, + 0xe7, 0x62, 0x87, 0xd6, 0x95, 0xa9, 0x83, 0x54, 0x75, 0xb0, 0x48, 0x6d, 0x8c, 0x6a, 0xc5, 0x34, + 0xf3, 0xa3, 0x3a, 0xa9, 0xba, 0xfa, 0x67, 0xc4, 0x43, 0x8e, 0xc7, 0x1e, 0x78, 0x18, 0x38, 0x59, + 0x1e, 0x4e, 0xae, 0x4c, 0x6e, 0xc3, 0x4c, 0x94, 0x66, 0xfe, 0xf6, 0x43, 0x3f, 0x5e, 0x7e, 0x75, + 0x38, 0xf0, 0x61, 0x07, 0x2d, 0xe4, 0xe2, 0x13, 0x18, 0x63, 0xc9, 0x1b, 0x98, 0x81, 0x2b, 0xd9, + 0x14, 0xa4, 0x6c, 0x60, 0xe4, 0x69, 0x7d, 0xba, 0x8b, 0x38, 0x57, 0x4c, 0x33, 0x13, 0xe7, 0x49, + 0xe5, 0xfb, 0x0f, 0x12, 0x86, 0x76, 0xd4, 0x51, 0xe7, 0xd0, 0x06, 0x8e, 0x13, 0xda, 0xc9, 0xe5, + 0x52, 0xc3, 0xb9, 0x6f, 0xdb, 0x63, 0x2e, 0x9f, 0x53, 0x12, 0x7d, 0x5b, 0xab, 0x54, 0x5c, 0xe6, + 0x79, 0x51, 0xdf, 0xc6, 0x63, 0xb2, 0xa3, 0x17, 0xd2, 0x1d, 0x3d, 0xee, 0xce, 0x03, 0xc9, 0xee, + 0xfc, 0x1a, 0x47, 0xb3, 0x84, 0x0b, 0xa4, 0xe5, 0x39, 0x8c, 0xe8, 0xb6, 0xe5, 0x05, 0xb5, 0xb8, + 0xe7, 0xf4, 0x35, 0x4b, 0xc5, 0xca, 0xa1, 0xe3, 0x9a, 0x76, 0xf0, 0x78, 0x1b, 0x47, 0x28, 0x71, + 0xa0, 0xf7, 0xe1, 0x12, 0x77, 0xbc, 0x15, 0x6e, 0x4b, 0x7a, 0xdc, 0xce, 0xd7, 0x0d, 0xcf, 0xef, + 0x3a, 0x9d, 0xd0, 0x1a, 0xcc, 0x75, 0x56, 0x3e, 0xf1, 0x61, 0x90, 0x6e, 0xc2, 0x57, 0xb8, 0xbb, + 0xa7, 0xbb, 0xbb, 0x4c, 0xf7, 0x8d, 0x3a, 0xdb, 0xe0, 0x7b, 0x52, 0x84, 0x53, 0x6e, 0x63, 0x6a, + 0x34, 0x11, 0xfc, 0x24, 0x0c, 0x87, 0x93, 0x5c, 0x9c, 0x0e, 0x3c, 0xd1, 0x5f, 0x4a, 0x58, 0xff, + 0x47, 0x6c, 0x22, 0xfc, 0x12, 0x0c, 0x8b, 0x6d, 0x0c, 0xc9, 0x97, 0xdb, 0xca, 0x31, 0xdc, 0xd7, + 0x8a, 0xa8, 0x83, 0x92, 0x64, 0x05, 0xce, 0x39, 0xcc, 0xaa, 0x18, 0x56, 0x55, 0x45, 0xdd, 0x42, + 0x57, 0xdd, 0x31, 0xd4, 0x10, 0x47, 0xfa, 0x5f, 0x09, 0xc7, 0xeb, 0xad, 0xca, 0x7e, 0xfb, 0xa8, + 0xf6, 0x1c, 0x4e, 0x47, 0xf3, 0xa6, 0xc0, 0xf4, 0xb5, 0xec, 0x47, 0xa4, 0xc3, 0x78, 0x5e, 0x8e, + 0xb4, 0xc9, 0x04, 0x0c, 0xd7, 0xb4, 0x03, 0x55, 0x0f, 0x92, 0x25, 0x11, 0x90, 0x9b, 0x30, 0x18, + 0xb2, 0xc3, 0x0b, 0xf4, 0x4c, 0xe9, 0x62, 0xda, 0x38, 0xdf, 0x5c, 0xb7, 0x1c, 0xa6, 0x97, 0xb9, + 0x10, 0x59, 0x83, 0xf3, 0xd1, 0x3a, 0xa6, 0xe2, 0x62, 0x35, 0xc8, 0xf5, 0xe6, 0xd2, 0x7a, 0xf1, + 0xce, 0x56, 0x5f, 0xc2, 0xe5, 0xaa, 0x7c, 0x2e, 0xba, 0x26, 0xce, 0xf4, 0xeb, 0x70, 0x39, 0xb5, + 0x0b, 0x7d, 0xdb, 0xb6, 0xfc, 0x3d, 0xf3, 0x70, 0x43, 0x3b, 0xb4, 0x03, 0x3f, 0x91, 0x64, 0x27, + 0x39, 0x82, 0x25, 0x06, 0x5f, 0xba, 0x0f, 0x64, 0x2b, 0xb1, 0x6c, 0x0a, 0x45, 0x42, 0xe1, 0x6c, + 0x72, 0x05, 0x45, 0xad, 0xd4, 0x35, 0x32, 0x0d, 0x23, 0xbc, 0xa6, 0xc3, 0xc1, 0x34, 0xf5, 0xbc, + 0x56, 0xc2, 0xca, 0xd1, 0x6a, 0x76, 0x60, 0xf9, 0xf8, 0xc0, 0xe2, 0x89, 0xfe, 0x10, 0x68, 0x1e, + 0xda, 0xd6, 0x58, 0xed, 0xdb, 0xbe, 0x66, 0x72, 0xaf, 0x83, 0x65, 0x71, 0x20, 0xab, 0x70, 0xba, + 0xc2, 0x7c, 0xcd, 0x30, 0xbd, 0xa9, 0x02, 0x7f, 0x22, 0xe6, 0xb3, 0x33, 0x78, 0x34, 0x9a, 0x72, + 0xa4, 0x48, 0x9f, 0xc0, 0xb9, 0x44, 0x87, 0x0b, 0x03, 0xcd, 0xa1, 0x26, 0x11, 0x45, 0x21, 0x15, + 0xc5, 0x4b, 0x18, 0x7b, 0x2c, 0x1e, 0x66, 0x34, 0x92, 0x64, 0x42, 0x4a, 0x33, 0xf1, 0x28, 0xac, + 0xbb, 0x50, 0x28, 0x42, 0x7d, 0xb5, 0x6b, 0xe3, 0xe5, 0x88, 0x51, 0x89, 0x3e, 0xc6, 0x19, 0x23, + 0x19, 0x55, 0xa7, 0x1c, 0x77, 0x7a, 0x90, 0x69, 0x13, 0xc7, 0x86, 0x1c, 0x23, 0xb9, 0xd4, 0x3f, + 0x6c, 0xa7, 0xbe, 0x43, 0x7f, 0x49, 0xb1, 0x12, 0xb3, 0x5e, 0xfa, 0xf5, 0x14, 0x0c, 0x71, 0xff, + 0xe4, 0xa7, 0x12, 0x0c, 0x8b, 0xc2, 0x25, 0xf3, 0x39, 0xcf, 0x5f, 0xea, 0xa3, 0x84, 0xbc, 0xd0, + 0x83, 0xa4, 0x80, 0x4f, 0xaf, 0xfe, 0xe4, 0xcd, 0x7f, 0x7e, 0x51, 0x98, 0x25, 0x33, 0x4a, 0xce, + 0xc7, 0x28, 0xf2, 0x2b, 0x09, 0x46, 0x5b, 0x3b, 0xd8, 0xcd, 0x3c, 0xf3, 0x6d, 0x1f, 0x2d, 0xe4, + 0xc5, 0xde, 0x84, 0x11, 0xce, 0x12, 0x87, 0x73, 0x93, 0x2c, 0x28, 0xb9, 0x9f, 0xa3, 0x3c, 0xa5, + 0x81, 0xcd, 0xa1, 0x49, 0x7e, 0x23, 0x01, 0xb4, 0x5e, 0x3f, 0x64, 0xb1, 0xc7, 0xb7, 0x94, 0x40, + 0xd7, 0xdf, 0x3b, 0x8d, 0x3e, 0xe0, 0xf0, 0xee, 0x92, 0xdb, 0xd9, 0xf0, 0xaa, 0x2c, 0xde, 0xd1, + 0x5b, 0x00, 0x95, 0x86, 0x58, 0xa6, 0x9b, 0xe4, 0x2f, 0x12, 0x8c, 0xa5, 0xd6, 0x62, 0xa2, 0xe4, + 0xb8, 0xcf, 0x5a, 0xe1, 0xe5, 0x8f, 0x7a, 0x57, 0x40, 0xc8, 0x65, 0x0e, 0x79, 0x9d, 0xbc, 0xc8, + 0x86, 0x5c, 0xe7, 0x4a, 0x39, 0xa8, 0x95, 0x46, 0x44, 0x7a, 0x53, 0x69, 0xf0, 0x29, 0xa2, 0x49, + 0x7e, 0x56, 0x00, 0xba, 0xdd, 0xc3, 0x32, 0x94, 0x4f, 0x6e, 0xcf, 0x5b, 0xa6, 0xfc, 0xcd, 0xe3, + 0x1b, 0x42, 0x36, 0xd6, 0x39, 0x1b, 0xcf, 0xc8, 0x13, 0xe5, 0x18, 0x5f, 0x2e, 0x95, 0x06, 0x1f, + 0xa3, 0x9b, 0xe4, 0xc7, 0x05, 0xb8, 0xd6, 0xdd, 0xf9, 0x8a, 0x69, 0xe6, 0x52, 0xd1, 0xcf, 0xc2, + 0x9d, 0x4b, 0x45, 0x5f, 0xbb, 0x33, 0x7d, 0xc2, 0xa9, 0x78, 0x44, 0x1e, 0x1c, 0x87, 0x0a, 0xf2, + 0x46, 0x82, 0xc9, 0xec, 0x15, 0x88, 0xdc, 0xef, 0xf2, 0x6c, 0xe5, 0x2d, 0x80, 0xf2, 0x83, 0xf7, + 0x53, 0xc6, 0xd8, 0x1e, 0xf1, 0xd8, 0x96, 0xc9, 0x5d, 0xa5, 0xaf, 0xaf, 0xda, 0x71, 0x62, 0xff, + 0x26, 0xc1, 0x74, 0xb6, 0x8b, 0x30, 0x99, 0xf7, 0xf3, 0x73, 0xf0, 0xfe, 0x81, 0x75, 0x5d, 0x52, + 0xe9, 0x5d, 0x1e, 0xd8, 0x47, 0xa4, 0xd8, 0x5f, 0x60, 0xe4, 0xf7, 0x12, 0x8c, 0xa5, 0x76, 0x19, + 0x52, 0xca, 0x27, 0x38, 0x6b, 0x4b, 0x93, 0x6f, 0xf5, 0xa5, 0x83, 0x90, 0x6f, 0x73, 0xc8, 0x45, + 0xb2, 0xa8, 0xf4, 0xf0, 0x5b, 0x46, 0x9c, 0x81, 0xdf, 0x4a, 0x70, 0x21, 0x65, 0x2f, 0x24, 0xbe, + 0x94, 0xcf, 0x5d, 0xdf, 0x98, 0x3b, 0x2d, 0x89, 0x74, 0x91, 0x63, 0xbe, 0x4e, 0xae, 0xf6, 0x82, + 0x99, 0x7c, 0x2e, 0xc1, 0x68, 0xbc, 0x51, 0xe5, 0x76, 0xc7, 0xf6, 0xd5, 0x2e, 0xb7, 0x3b, 0x1e, + 0x59, 0xd2, 0xba, 0xb5, 0x9f, 0xc0, 0x63, 0xae, 0xf8, 0xb9, 0x44, 0x69, 0xe0, 0x86, 0xd8, 0x4c, + 0x34, 0xca, 0x3f, 0x49, 0xf0, 0x41, 0xc6, 0x0a, 0x45, 0xee, 0xe4, 0x60, 0xe8, 0xbc, 0xaf, 0xc9, + 0x77, 0xfb, 0x55, 0xc3, 0x20, 0x1e, 0xf2, 0x20, 0x3e, 0x26, 0x77, 0xb2, 0x83, 0xf0, 0xb8, 0x6a, + 0xeb, 0x43, 0xb0, 0x6a, 0x1a, 0x9e, 0x9f, 0x88, 0xe2, 0x8f, 0x12, 0x9c, 0x6f, 0xdb, 0xa2, 0xc8, + 0x52, 0x0e, 0x94, 0xec, 0x2d, 0x4e, 0x2e, 0xf5, 0xa3, 0x82, 0xc8, 0x57, 0x39, 0xf2, 0x07, 0xe4, + 0x5e, 0x87, 0xaa, 0x88, 0xd4, 0x70, 0x1d, 0x53, 0x1a, 0xd1, 0x38, 0xd9, 0x54, 0x1a, 0x62, 0x11, + 0x6c, 0x92, 0xbf, 0x4a, 0x30, 0x91, 0x39, 0xcb, 0x93, 0x8f, 0x7b, 0x18, 0x94, 0xb2, 0xe6, 0x58, + 0x79, 0xb9, 0x7f, 0x45, 0x0c, 0xe8, 0x1b, 0x3c, 0xa0, 0x7b, 0x64, 0xb9, 0xcb, 0xdb, 0xa4, 0x26, + 0xb4, 0x55, 0x31, 0x62, 0x27, 0x26, 0x02, 0xf2, 0x0f, 0x09, 0xa6, 0x3b, 0xce, 0xc8, 0xb9, 0x2f, + 0xca, 0x6e, 0xe3, 0x79, 0xee, 0x8b, 0xb2, 0xeb, 0x58, 0xde, 0xad, 0xbb, 0x25, 0xd7, 0xb2, 0x23, + 0xe1, 0xc5, 0x69, 0x23, 0x9f, 0x49, 0x00, 0xad, 0xd5, 0xf8, 0x04, 0x67, 0xcb, 0xa3, 0xfb, 0x36, + 0x5d, 0xe0, 0x88, 0xaf, 0x90, 0xcb, 0x1d, 0x10, 0x57, 0xf6, 0xa3, 0x29, 0x6d, 0x75, 0xe5, 0x8b, + 0xb7, 0xb3, 0xd2, 0x97, 0x6f, 0x67, 0xa5, 0x7f, 0xbf, 0x9d, 0x95, 0x7e, 0xfe, 0x6e, 0xf6, 0xd4, + 0x97, 0xef, 0x66, 0x4f, 0xfd, 0xfd, 0xdd, 0xec, 0xa9, 0xef, 0xdf, 0xa8, 0x1a, 0xfe, 0x5e, 0xb0, + 0x53, 0xd4, 0xed, 0x5a, 0xda, 0xcc, 0x41, 0x6c, 0xc8, 0x3f, 0x74, 0x98, 0xb7, 0x33, 0xcc, 0x7f, + 0xd4, 0xbc, 0xf5, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x5f, 0xe2, 0xef, 0x1c, 0x1f, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. From ffed9418290964792abd2a24222d633678b89ded Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Sun, 3 Dec 2023 04:34:05 -0500 Subject: [PATCH 18/85] CR Fix: Create an helper function --- protocol/chainlib/common_test_utils.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/protocol/chainlib/common_test_utils.go b/protocol/chainlib/common_test_utils.go index bc48e73523..c73f79043e 100644 --- a/protocol/chainlib/common_test_utils.go +++ b/protocol/chainlib/common_test_utils.go @@ -166,6 +166,10 @@ type TestStruct struct { Validator sigs.Account } +func (ts *TestStruct) BondDenom() string { + return ts.Keepers.StakingKeeper.BondDenom(sdk.UnwrapSDKContext(ts.Ctx)) +} + func SetupForTests(t *testing.T, numOfProviders int, specID string, getToTopMostPath string) TestStruct { rand.InitRandomSeed() ts := TestStruct{} @@ -178,7 +182,7 @@ func SetupForTests(t *testing.T, numOfProviders int, specID string, getToTopMost msg, err := stakingtypes.NewMsgCreateValidator( sdk.ValAddress(ts.Validator.Addr), ts.Validator.PubKey, - sdk.NewCoin(ts.Keepers.StakingKeeper.BondDenom(sdk.UnwrapSDKContext(ts.Ctx)), sdk.NewIntFromUint64(uint64(balance))), + sdk.NewCoin(ts.BondDenom(), sdk.NewIntFromUint64(uint64(balance))), stakingtypes.Description{}, stakingtypes.NewCommissionRates(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(1, 1)), sdk.ZeroInt(), From 08f2e71cc9eeb155204ca47c119ddb8de109e80a Mon Sep 17 00:00:00 2001 From: oren-lava Date: Sun, 3 Dec 2023 12:25:25 +0200 Subject: [PATCH 19/85] CNS-715: PR fixes --- x/dualstaking/keeper/hooks.go | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/x/dualstaking/keeper/hooks.go b/x/dualstaking/keeper/hooks.go index 5c336434cf..20640972b2 100644 --- a/x/dualstaking/keeper/hooks.go +++ b/x/dualstaking/keeper/hooks.go @@ -92,11 +92,16 @@ func (h Hooks) BeforeValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, f ) } + // unbond from providers according to slash + // sort the delegations so if there's a remainder, remove it from the highest delegation in the last iteration remainingTokensToSlash := fraction.MulInt(val.Tokens).TruncateInt() delegations := h.k.stakingKeeper.GetValidatorDelegations(ctx, valAddr) - for _, d := range delegations { - tokens := val.TokensFromShares(d.Shares).TruncateInt() - tokensToSlash := fraction.MulInt(tokens).TruncateInt() + slices.SortFunc(delegations, func(i, j stakingtypes.Delegation) bool { + return i.Shares.GT(j.Shares) + }) + for i, d := range delegations { + tokens := val.TokensFromShares(d.Shares) + tokensToSlash := fraction.Mul(tokens).TruncateInt() err := h.k.UnbondUniformProviders(ctx, d.DelegatorAddress, sdk.NewCoin(epochstoragetypes.TokenDenom, tokensToSlash)) if err != nil { return utils.LavaFormatError("slash hook failed", err, @@ -106,20 +111,16 @@ func (h Hooks) BeforeValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, f ) } remainingTokensToSlash = remainingTokensToSlash.Sub(tokensToSlash) - } - // if there's a remainder, remove it from the highest delegation - if !remainingTokensToSlash.IsZero() { - slices.SortFunc(delegations, func(i, j stakingtypes.Delegation) bool { - return i.Shares.GT(j.Shares) - }) - err := h.k.UnbondUniformProviders(ctx, delegations[0].DelegatorAddress, sdk.NewCoin(epochstoragetypes.TokenDenom, remainingTokensToSlash)) - if err != nil { - return utils.LavaFormatError("slash hook failed", err, - utils.Attribute{Key: "validator_address", Value: valAddr.String()}, - utils.Attribute{Key: "delegator_address", Value: delegations[0].DelegatorAddress}, - utils.Attribute{Key: "slash_amount", Value: remainingTokensToSlash.String()}, - ) + if !remainingTokensToSlash.IsZero() && i == len(delegations)-1 { + err := h.k.UnbondUniformProviders(ctx, delegations[0].DelegatorAddress, sdk.NewCoin(epochstoragetypes.TokenDenom, remainingTokensToSlash)) + if err != nil { + return utils.LavaFormatError("slash hook unbond remainder failed", err, + utils.Attribute{Key: "validator_address", Value: valAddr.String()}, + utils.Attribute{Key: "delegator_address", Value: delegations[0].DelegatorAddress}, + utils.Attribute{Key: "slash_amount", Value: remainingTokensToSlash.String()}, + ) + } } } From a793be855e15019ac5771bcc2e4be9020d597d85 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Sun, 3 Dec 2023 12:16:20 +0000 Subject: [PATCH 20/85] pr changes --- x/dualstaking/keeper/migrations.go | 1 + x/pairing/keeper/delegator_rewards_test.go | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/x/dualstaking/keeper/migrations.go b/x/dualstaking/keeper/migrations.go index 065e5a6650..b099d6bf17 100644 --- a/x/dualstaking/keeper/migrations.go +++ b/x/dualstaking/keeper/migrations.go @@ -9,6 +9,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/utils" dualstakingtypes "github.com/lavanet/lava/x/dualstaking/types" + epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" "github.com/lavanet/lava/x/pairing/types" ) diff --git a/x/pairing/keeper/delegator_rewards_test.go b/x/pairing/keeper/delegator_rewards_test.go index ab62c458a0..8898fc661b 100644 --- a/x/pairing/keeper/delegator_rewards_test.go +++ b/x/pairing/keeper/delegator_rewards_test.go @@ -436,7 +436,7 @@ func TestDelegationTimestamp(t *testing.T) { // delegate and check the timestamp is equal to current time + month currentTimeAfterMonth := subscriptionkeeper.NextMonth(ts.BlockTime()).UTC().Unix() - _, err := ts.TxDualstakingDelegate(delegator, provider, ts.spec.Index, sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(testStake))) + _, err := ts.TxDualstakingDelegate(delegator, provider, ts.spec.Index, sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(testStake))) require.Nil(t, err) ts.AdvanceEpoch() // apply delegations @@ -451,8 +451,8 @@ func TestDelegationTimestamp(t *testing.T) { // advance time and delegate again to verify that the timestamp hasn't changed ts.AdvanceMonths(1) - expectedDelegation := sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(2*testStake)) - _, err = ts.TxDualstakingDelegate(delegator, provider, ts.spec.Index, sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(testStake))) + expectedDelegation := sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(2*testStake)) + _, err = ts.TxDualstakingDelegate(delegator, provider, ts.spec.Index, sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(testStake))) require.Nil(t, err) ts.AdvanceEpoch() // apply delegations @@ -480,14 +480,14 @@ func TestDelegationFirstMonthPairing(t *testing.T) { // increase delegation limit of stake entry stakeEntry, found, stakeEntryIndex := ts.Keepers.Epochstorage.GetStakeEntryByAddressCurrent(ts.Ctx, ts.spec.Index, providerAcc.Addr) require.True(t, found) - stakeEntry.DelegateLimit = sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(10*testStake)) + stakeEntry.DelegateLimit = sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(10*testStake)) ts.Keepers.Epochstorage.ModifyStakeEntryCurrent(ts.Ctx, ts.spec.Index, stakeEntry, stakeEntryIndex) ts.AdvanceEpoch() // delegate and check the delegation's timestamp is equal than nowPlusMonthTime nowPlusMonthTime := subscriptionkeeper.NextMonth(ts.BlockTime()).UTC().Unix() - _, err := ts.TxDualstakingDelegate(delegator, provider, ts.spec.Index, sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(testStake))) + _, err := ts.TxDualstakingDelegate(delegator, provider, ts.spec.Index, sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(testStake))) require.Nil(t, err) ts.AdvanceEpoch() // apply delegations @@ -522,7 +522,7 @@ func TestDelegationFirstMonthReward(t *testing.T) { // increase delegation limit and zero commission of stake entry stakeEntry, found, stakeEntryIndex := ts.Keepers.Epochstorage.GetStakeEntryByAddressCurrent(ts.Ctx, ts.spec.Index, providerAcc.Addr) require.True(t, found) - stakeEntry.DelegateLimit = sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(10*testStake)) + stakeEntry.DelegateLimit = sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(10*testStake)) ts.Keepers.Epochstorage.ModifyStakeEntryCurrent(ts.Ctx, ts.spec.Index, stakeEntry, stakeEntryIndex) ts.AdvanceEpoch() makeProviderCommissionZero(ts, ts.spec.Index, providerAcc.Addr) @@ -530,7 +530,7 @@ func TestDelegationFirstMonthReward(t *testing.T) { // delegate and check the delegation's timestamp is equal to nowPlusMonthTime nowPlusMonthTime := subscriptionkeeper.NextMonth(ts.BlockTime()).UTC().Unix() - _, err := ts.TxDualstakingDelegate(delegator, provider, ts.spec.Index, sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(testStake))) + _, err := ts.TxDualstakingDelegate(delegator, provider, ts.spec.Index, sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(testStake))) require.Nil(t, err) ts.AdvanceEpoch() // apply delegations @@ -573,12 +573,12 @@ func TestRedelegationFirstMonthReward(t *testing.T) { // increase delegation limit and zero commission of both stake entries stakeEntry, found, stakeEntryIndex := ts.Keepers.Epochstorage.GetStakeEntryByAddressCurrent(ts.Ctx, ts.spec.Index, providerAcc.Addr) require.True(t, found) - stakeEntry.DelegateLimit = sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(10*testStake)) + stakeEntry.DelegateLimit = sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(10*testStake)) ts.Keepers.Epochstorage.ModifyStakeEntryCurrent(ts.Ctx, ts.spec.Index, stakeEntry, stakeEntryIndex) ts.AdvanceEpoch() stakeEntry, found, stakeEntryIndex = ts.Keepers.Epochstorage.GetStakeEntryByAddressCurrent(ts.Ctx, ts.spec.Index, provider1Acc.Addr) require.True(t, found) - stakeEntry.DelegateLimit = sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(10*testStake)) + stakeEntry.DelegateLimit = sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(10*testStake)) ts.Keepers.Epochstorage.ModifyStakeEntryCurrent(ts.Ctx, ts.spec.Index, stakeEntry, stakeEntryIndex) ts.AdvanceEpoch() makeProviderCommissionZero(ts, ts.spec.Index, provider1Acc.Addr) @@ -587,7 +587,7 @@ func TestRedelegationFirstMonthReward(t *testing.T) { // delegate and check the delegation's timestamp is equal to nowPlusMonthTime nowPlusMonthTime := subscriptionkeeper.NextMonth(ts.BlockTime()).UTC().Unix() - _, err := ts.TxDualstakingDelegate(delegator, provider, ts.spec.Index, sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewInt(testStake))) + _, err := ts.TxDualstakingDelegate(delegator, provider, ts.spec.Index, sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(testStake))) require.Nil(t, err) ts.AdvanceEpoch() // apply delegations @@ -602,7 +602,7 @@ func TestRedelegationFirstMonthReward(t *testing.T) { // advance a month a redelegate some of the funds to the second provider ts.AdvanceMonths(1) - redelegateAmount := sdk.NewCoin(epochstoragetypes.TokenDenom, res.Delegations[0].Amount.Amount.QuoRaw(2)) + redelegateAmount := sdk.NewCoin(ts.TokenDenom(), res.Delegations[0].Amount.Amount.QuoRaw(2)) _, err = ts.TxDualstakingRedelegate(delegator, provider, provider1, ts.spec.Index, ts.spec.Index, redelegateAmount) require.Nil(t, err) From 6a7d51cbf0b769a12f5f20c29579ce52d8459f31 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Sun, 3 Dec 2023 12:29:47 +0000 Subject: [PATCH 21/85] pr changes --- common/types/token.go | 5 ++++ protocol/statetracker/tx_sender.go | 10 +++---- x/dualstaking/keeper/delegate_test.go | 27 ++++++++++--------- x/pairing/client/cli/tx_modify_provider.go | 3 ++- x/pairing/client/cli/tx_stake_provider.go | 5 ++-- .../types/message_stake_provider_test.go | 5 ++-- x/plans/types/plan_decode_test.go | 7 ++--- 7 files changed, 36 insertions(+), 26 deletions(-) create mode 100644 common/types/token.go diff --git a/common/types/token.go b/common/types/token.go new file mode 100644 index 0000000000..43aaea4a4e --- /dev/null +++ b/common/types/token.go @@ -0,0 +1,5 @@ +package types + +const ( + TokenDenom = "ulava" +) diff --git a/protocol/statetracker/tx_sender.go b/protocol/statetracker/tx_sender.go index ecb66c1aa8..c6154d9fb9 100644 --- a/protocol/statetracker/tx_sender.go +++ b/protocol/statetracker/tx_sender.go @@ -14,6 +14,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/tx" sdk "github.com/cosmos/cosmos-sdk/types" typestx "github.com/cosmos/cosmos-sdk/types/tx" + commontypes "github.com/lavanet/lava/common/types" "github.com/lavanet/lava/protocol/common" "github.com/lavanet/lava/protocol/rpcprovider/reliabilitymanager" "github.com/lavanet/lava/utils" @@ -22,8 +23,7 @@ import ( ) const ( - tokenDenom = "ulava" - defaultGasPrice = "0.000000001" + tokenDenom + defaultGasPrice = "0.000000001" + commontypes.TokenDenom defaultGasAdjustment = 3 // same account can continue failing the more providers you have under the same account // for example if you have a provider staked at 20 chains you will ask for 20 payments per epoch. @@ -45,7 +45,7 @@ func NewTxSender(ctx context.Context, clientCtx client.Context, txFactory tx.Fac func (ts *TxSender) checkProfitability(simResult *typestx.SimulateResponse, gasUsed uint64, txFactory tx.Factory) error { txEvents := simResult.GetResult().Events - lavaReward := sdk.NewCoin(tokenDenom, sdk.NewInt(0)) + lavaReward := sdk.NewCoin(commontypes.TokenDenom, sdk.NewInt(0)) for _, txEvent := range txEvents { if txEvent.Type == utils.EventPrefix+pairingtypes.RelayPaymentEventName { for _, attribute := range txEvent.Attributes { @@ -313,7 +313,7 @@ func (pts *ProviderTxSender) SendVoteCommitment(voteID string, vote *reliability func parseInsufficientFeesError(msg string, gasUsed uint64) error { feesPart := strings.Split(msg, "insufficient fees; got: ")[1] - prices := strings.Split(feesPart, tokenDenom) + prices := strings.Split(feesPart, commontypes.TokenDenom) var required int var err error for _, p := range prices { @@ -331,7 +331,7 @@ func parseInsufficientFeesError(msg string, gasUsed uint64) error { minimumGasPricesGot := (float64(gasUsed) / float64(required)) utils.LavaFormatError("Bad Lava Node Configuration detected, Gas fees inconsistencies can be related to the app.toml configuration of the lava node you are using under 'minimum-gas-prices', Please remove the field or set it to the required amount or change rpc to a different lava node", nil, utils.Attribute{Key: "Required Minimum Gas Prices", Value: defaultGasPrice}, - utils.Attribute{Key: "Current (estimated) Minimum Gas Prices", Value: strconv.FormatFloat(minimumGasPricesGot, 'f', -1, 64) + tokenDenom}, + utils.Attribute{Key: "Current (estimated) Minimum Gas Prices", Value: strconv.FormatFloat(minimumGasPricesGot, 'f', -1, 64) + commontypes.TokenDenom}, ) return nil diff --git a/x/dualstaking/keeper/delegate_test.go b/x/dualstaking/keeper/delegate_test.go index 0819f8b17f..4390efb665 100644 --- a/x/dualstaking/keeper/delegate_test.go +++ b/x/dualstaking/keeper/delegate_test.go @@ -4,11 +4,12 @@ import ( "testing" sdk "github.com/cosmos/cosmos-sdk/types" + commontypes "github.com/lavanet/lava/common/types" "github.com/lavanet/lava/testutil/common" "github.com/stretchr/testify/require" ) -var zeroCoin = sdk.NewCoin("ulava", sdk.ZeroInt()) +var zeroCoin = sdk.NewCoin(commontypes.TokenDenom, sdk.ZeroInt()) func TestDelegateFail(t *testing.T) { ts := newTester(t) @@ -74,7 +75,7 @@ func TestDelegateFail(t *testing.T) { for _, tt := range template { t.Run(tt.name, func(t *testing.T) { - amount := sdk.NewCoin("ulava", sdk.ZeroInt()) + amount := sdk.NewCoin(commontypes.TokenDenom, sdk.ZeroInt()) amount.Amount = amount.Amount.Add(sdk.NewInt(tt.amount)) _, err := ts.TxDualstakingDelegate(tt.delegator, tt.provider, tt.chainID, amount) require.Error(t, err, tt.name) @@ -94,7 +95,7 @@ func TestDelegate(t *testing.T) { delegated := zeroCoin // delegate once - amount := sdk.NewCoin("ulava", sdk.NewInt(10000)) + amount := sdk.NewCoin(commontypes.TokenDenom, sdk.NewInt(10000)) _, err := ts.TxDualstakingDelegate(client1Addr, provider1Addr, ts.spec.Name, amount) require.NoError(t, err) // not yet in effect @@ -140,7 +141,7 @@ func TestRedelegateFail(t *testing.T) { _, provider4Addr := ts.GetAccount(common.PROVIDER, 3) // delegate once for setup - amount := sdk.NewCoin("ulava", sdk.NewInt(10000)) + amount := sdk.NewCoin(commontypes.TokenDenom, sdk.NewInt(10000)) _, err := ts.TxDualstakingDelegate(client1Addr, provider1Addr, ts.spec.Name, amount) require.NoError(t, err) @@ -220,7 +221,7 @@ func TestRedelegateFail(t *testing.T) { for _, tt := range template { t.Run(tt.name, func(t *testing.T) { - amount := sdk.NewCoin("ulava", sdk.ZeroInt()) + amount := sdk.NewCoin(commontypes.TokenDenom, sdk.ZeroInt()) amount.Amount = amount.Amount.Add(sdk.NewInt(tt.amount)) _, err := ts.TxDualstakingRedelegate( tt.delegator, tt.provider1, tt.provider2, tt.chainID, tt.chainID, amount) @@ -243,7 +244,7 @@ func TestRedelegate(t *testing.T) { delegated2 := zeroCoin // delegate once - amount := sdk.NewCoin("ulava", sdk.NewInt(10000)) + amount := sdk.NewCoin(commontypes.TokenDenom, sdk.NewInt(10000)) _, err := ts.TxDualstakingDelegate( client1Addr, provider1Addr, ts.spec.Name, amount) require.NoError(t, err) @@ -258,7 +259,7 @@ func TestRedelegate(t *testing.T) { require.True(t, delegated2.IsEqual(stakeEntry2.DelegateTotal)) // redelegate once - amount = sdk.NewCoin("ulava", sdk.NewInt(5000)) + amount = sdk.NewCoin(commontypes.TokenDenom, sdk.NewInt(5000)) _, err = ts.TxDualstakingRedelegate( client1Addr, provider1Addr, provider2Addr, ts.spec.Name, ts.spec.Name, amount) require.NoError(t, err) @@ -280,7 +281,7 @@ func TestRedelegate(t *testing.T) { require.NoError(t, err) // redelegate from unstaking provider - amount = sdk.NewCoin("ulava", sdk.NewInt(5000)) + amount = sdk.NewCoin(commontypes.TokenDenom, sdk.NewInt(5000)) _, err = ts.TxDualstakingRedelegate( client1Addr, provider1Addr, provider2Addr, ts.spec.Name, ts.spec.Name, amount) require.NoError(t, err) @@ -305,7 +306,7 @@ func TestUnbondFail(t *testing.T) { _, provider2Addr := ts.GetAccount(common.PROVIDER, 1) // delegate once for setup - amount := sdk.NewCoin("ulava", sdk.NewInt(10000)) + amount := sdk.NewCoin(commontypes.TokenDenom, sdk.NewInt(10000)) _, err := ts.TxDualstakingDelegate(client1Addr, provider1Addr, ts.spec.Name, amount) require.NoError(t, err) @@ -362,7 +363,7 @@ func TestUnbondFail(t *testing.T) { for _, tt := range template { t.Run(tt.name, func(t *testing.T) { - amount := sdk.NewCoin("ulava", sdk.ZeroInt()) + amount := sdk.NewCoin(commontypes.TokenDenom, sdk.ZeroInt()) amount.Amount = amount.Amount.Add(sdk.NewInt(tt.amount)) _, err := ts.TxDualstakingUnbond(tt.delegator, tt.provider, tt.chainID, amount) require.Error(t, err, tt.name) @@ -382,7 +383,7 @@ func TestUnbond(t *testing.T) { delegated := zeroCoin // delegate once - amount := sdk.NewCoin("ulava", sdk.NewInt(10000)) + amount := sdk.NewCoin(commontypes.TokenDenom, sdk.NewInt(10000)) _, err := ts.TxDualstakingDelegate(client1Addr, provider1Addr, ts.spec.Name, amount) require.NoError(t, err) @@ -394,7 +395,7 @@ func TestUnbond(t *testing.T) { require.True(t, delegated.IsEqual(stakeEntry.DelegateTotal)) // unbond once - amount = sdk.NewCoin("ulava", sdk.NewInt(1000)) + amount = sdk.NewCoin(commontypes.TokenDenom, sdk.NewInt(1000)) _, err = ts.TxDualstakingUnbond(client1Addr, provider1Addr, ts.spec.Name, amount) require.NoError(t, err) @@ -460,7 +461,7 @@ func TestBondUnbondBond(t *testing.T) { delegated := zeroCoin // delegate once - amount := sdk.NewCoin("ulava", sdk.NewInt(10000)) + amount := sdk.NewCoin(commontypes.TokenDenom, sdk.NewInt(10000)) _, err := ts.TxDualstakingDelegate(client1Addr, provider1Addr, ts.spec.Name, amount) require.NoError(t, err) diff --git a/x/pairing/client/cli/tx_modify_provider.go b/x/pairing/client/cli/tx_modify_provider.go index 46f409cc06..e4f1b9e3f8 100644 --- a/x/pairing/client/cli/tx_modify_provider.go +++ b/x/pairing/client/cli/tx_modify_provider.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" sdk "github.com/cosmos/cosmos-sdk/types" + commontypes "github.com/lavanet/lava/common/types" "github.com/lavanet/lava/utils" "github.com/lavanet/lava/utils/sigs" epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" @@ -192,7 +193,7 @@ func CmdModifyProvider() *cobra.Command { providerEntry.DelegateCommission, ) - if msg.DelegateLimit.Denom != "ulava" { + if msg.DelegateLimit.Denom != commontypes.TokenDenom { return sdkerrors.Wrapf(types.DelegateLimitError, "Coin denomanator is not ulava") } diff --git a/x/pairing/client/cli/tx_stake_provider.go b/x/pairing/client/cli/tx_stake_provider.go index 07ccef53de..a57a4d9afb 100644 --- a/x/pairing/client/cli/tx_stake_provider.go +++ b/x/pairing/client/cli/tx_stake_provider.go @@ -12,6 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/tx" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + commontypes "github.com/lavanet/lava/common/types" epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" "github.com/lavanet/lava/x/pairing/types" planstypes "github.com/lavanet/lava/x/plans/types" @@ -99,7 +100,7 @@ func CmdStakeProvider() *cobra.Command { commission, ) - if msg.DelegateLimit.Denom != "ulava" { + if msg.DelegateLimit.Denom != commontypes.TokenDenom { return sdkerrors.Wrapf(types.DelegateLimitError, "Coin denomanator is not ulava") } @@ -203,7 +204,7 @@ func CmdBulkStakeProvider() *cobra.Command { commission, ) - if msg.DelegateLimit.Denom != "ulava" { + if msg.DelegateLimit.Denom != commontypes.TokenDenom { return nil, sdkerrors.Wrapf(types.DelegateLimitError, "Coin denomanator is not ulava") } diff --git a/x/pairing/types/message_stake_provider_test.go b/x/pairing/types/message_stake_provider_test.go index 90272dc4ed..c5f0fc204b 100644 --- a/x/pairing/types/message_stake_provider_test.go +++ b/x/pairing/types/message_stake_provider_test.go @@ -5,6 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/types" legacyerrors "github.com/cosmos/cosmos-sdk/types/errors" + commontypes "github.com/lavanet/lava/common/types" "github.com/lavanet/lava/testutil/sample" "github.com/stretchr/testify/require" ) @@ -20,7 +21,7 @@ func TestMsgStakeProvider_ValidateBasic(t *testing.T) { msg: MsgStakeProvider{ Creator: "invalid_address", Moniker: "dummyMoniker", - DelegateLimit: types.NewCoin("ulava", types.ZeroInt()), + DelegateLimit: types.NewCoin(commontypes.TokenDenom, types.ZeroInt()), DelegateCommission: 100, }, err: legacyerrors.ErrInvalidAddress, @@ -29,7 +30,7 @@ func TestMsgStakeProvider_ValidateBasic(t *testing.T) { msg: MsgStakeProvider{ Creator: sample.AccAddress(), Moniker: "dummyMoniker", - DelegateLimit: types.NewCoin("ulava", types.ZeroInt()), + DelegateLimit: types.NewCoin(commontypes.TokenDenom, types.ZeroInt()), DelegateCommission: 100, }, }, diff --git a/x/plans/types/plan_decode_test.go b/x/plans/types/plan_decode_test.go index a3c5c1833c..0f43fd9fb4 100644 --- a/x/plans/types/plan_decode_test.go +++ b/x/plans/types/plan_decode_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/cosmos/cosmos-sdk/types" + commontypes "github.com/lavanet/lava/common/types" "github.com/lavanet/lava/utils/decoder" "github.com/mitchellh/mapstructure" "github.com/stretchr/testify/require" @@ -55,7 +56,7 @@ func TestDecodeJsonPlan(t *testing.T) { Index: "to_delete_plan", Description: "This plan has no restrictions", Type: "rpc", - Price: types.NewCoin("ulava", types.NewIntFromUint64(100000)), + Price: types.NewCoin(commontypes.TokenDenom, types.NewIntFromUint64(100000)), AnnualDiscountPercentage: 20, AllowOveruse: true, OveruseRate: 2, @@ -130,7 +131,7 @@ func TestDecodePlanAddProposal(t *testing.T) { Index: "to_delete_plan", Description: "This plan has no restrictions", Type: "rpc", - Price: types.NewCoin("ulava", types.NewIntFromUint64(100000)), + Price: types.NewCoin(commontypes.TokenDenom, types.NewIntFromUint64(100000)), AnnualDiscountPercentage: 20, AllowOveruse: true, OveruseRate: 2, @@ -151,7 +152,7 @@ func TestDecodePlanAddProposal(t *testing.T) { Index: "to_delete_plan_2", Description: "This plan has no restrictions", Type: "rpc", - Price: types.NewCoin("ulava", types.NewIntFromUint64(100000)), + Price: types.NewCoin(commontypes.TokenDenom, types.NewIntFromUint64(100000)), AnnualDiscountPercentage: 20, AllowOveruse: true, OveruseRate: 2, From 4b4a61c5e9f7b3e0a108bd207caa91da823783b5 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Sun, 3 Dec 2023 08:56:10 -0500 Subject: [PATCH 22/85] CR Fix: Move the GetMinStake to spec module --- x/dualstaking/keeper/delegate.go | 16 ++-------------- x/dualstaking/types/expected_keepers.go | 1 + x/pairing/keeper/msg_server_unfreeze.go | 2 +- x/pairing/types/expected_keepers.go | 2 +- x/spec/keeper/spec.go | 12 ++++++++++++ 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/x/dualstaking/keeper/delegate.go b/x/dualstaking/keeper/delegate.go index a133d7d7c0..1881545c4a 100644 --- a/x/dualstaking/keeper/delegate.go +++ b/x/dualstaking/keeper/delegate.go @@ -209,7 +209,7 @@ func (k Keeper) increaseStakeEntryDelegation(ctx sdk.Context, delegator, provide if delegator == provider { stakeEntry.Stake = stakeEntry.Stake.Add(amount) - if stakeEntry.Stake.IsGTE(k.GetMinStake(ctx, chainID)) && stakeEntry.IsFrozen() { + if stakeEntry.Stake.IsGTE(k.specKeeper.GetMinStake(ctx, chainID)) && stakeEntry.IsFrozen() { stakeEntry.UnFreeze(uint64(ctx.BlockHeight())) } } else { @@ -249,7 +249,7 @@ func (k Keeper) decreaseStakeEntryDelegation(ctx sdk.Context, delegator, provide if err != nil { return fmt.Errorf("invalid or insufficient funds: %w", err) } - if stakeEntry.Stake.IsLT(k.GetMinStake(ctx, chainID)) { + if stakeEntry.Stake.IsLT(k.specKeeper.GetMinStake(ctx, chainID)) { stakeEntry.Freeze() } } else { @@ -422,18 +422,6 @@ func (k Keeper) getUnbondHoldBlocks(ctx sdk.Context, chainID string) uint64 { // NOT REACHED } -func (k Keeper) GetMinStake(ctx sdk.Context, chainID string) sdk.Coin { - spec, found := k.specKeeper.GetSpec(ctx, chainID) - if !found { - utils.LavaFormatError("critical: failed to get spec for chainID", - fmt.Errorf("unknown chainID"), - utils.Attribute{Key: "chainID", Value: chainID}, - ) - } - - return spec.MinStakeProvider -} - // GetDelegatorProviders gets all the providers the delegator is delegated to func (k Keeper) GetDelegatorProviders(ctx sdk.Context, delegator string, epoch uint64) (providers []string, err error) { _, err = sdk.AccAddressFromBech32(delegator) diff --git a/x/dualstaking/types/expected_keepers.go b/x/dualstaking/types/expected_keepers.go index 84cd6abef8..c85b3979d3 100644 --- a/x/dualstaking/types/expected_keepers.go +++ b/x/dualstaking/types/expected_keepers.go @@ -50,6 +50,7 @@ type SpecKeeper interface { GetContributorReward(ctx sdk.Context, chainId string) (contributors []sdk.AccAddress, percentage math.LegacyDec) GetSpec(ctx sdk.Context, index string) (val spectypes.Spec, found bool) GetAllChainIDs(ctx sdk.Context) (chainIDs []string) + GetMinStake(ctx sdk.Context, chainID string) sdk.Coin } type StakingKeeper interface { diff --git a/x/pairing/keeper/msg_server_unfreeze.go b/x/pairing/keeper/msg_server_unfreeze.go index 10f4dc219e..2ebd301d0c 100644 --- a/x/pairing/keeper/msg_server_unfreeze.go +++ b/x/pairing/keeper/msg_server_unfreeze.go @@ -24,7 +24,7 @@ func (k msgServer) UnfreezeProvider(goCtx context.Context, msg *types.MsgUnfreez return nil, utils.LavaFormatWarning("Unfreeze_cant_get_stake_entry", types.FreezeStakeEntryNotFoundError, []utils.Attribute{{Key: "chainID", Value: chainId}, {Key: "providerAddress", Value: msg.GetCreator()}}...) } - minStake := k.Keeper.dualstakingKeeper.GetMinStake(ctx, chainId) + minStake := k.Keeper.specKeeper.GetMinStake(ctx, chainId) if stakeEntry.Stake.IsLT(minStake) { return nil, utils.LavaFormatWarning("Unfreeze_insufficient_stake", types.UnFreezeInsufficientStakeError, []utils.Attribute{ diff --git a/x/pairing/types/expected_keepers.go b/x/pairing/types/expected_keepers.go index 233a60f322..6e36119c47 100644 --- a/x/pairing/types/expected_keepers.go +++ b/x/pairing/types/expected_keepers.go @@ -23,6 +23,7 @@ type SpecKeeper interface { GetSpec(ctx sdk.Context, index string) (val spectypes.Spec, found bool) // this spec is unexpanded don;t use for collections work GetExpectedServicesForExpandedSpec(expandedSpec spectypes.Spec, mandatory bool) map[epochstoragetypes.EndpointService]struct{} GetAllChainIDs(ctx sdk.Context) (chainIDs []string) + GetMinStake(ctx sdk.Context, chainID string) sdk.Coin } type EpochstorageKeeper interface { @@ -103,7 +104,6 @@ type DualstakingKeeper interface { RewardProvidersAndDelegators(ctx sdk.Context, providerAddr sdk.AccAddress, chainID string, totalReward math.Int, senderModule string, calcOnly bool) (providerReward math.Int, err error) DelegateFull(ctx sdk.Context, delegator string, validator string, provider string, chainID string, amount sdk.Coin) error UnbondFull(ctx sdk.Context, delegator string, validator string, provider string, chainID string, amount sdk.Coin, unstake bool) error - GetMinStake(ctx sdk.Context, chainID string) sdk.Coin } type FixationStoreKeeper interface { diff --git a/x/spec/keeper/spec.go b/x/spec/keeper/spec.go index 60e38fbfda..d4beef7014 100644 --- a/x/spec/keeper/spec.go +++ b/x/spec/keeper/spec.go @@ -336,3 +336,15 @@ func (k Keeper) GetContributorReward(ctx sdk.Context, chainId string) (contribut } return contributors, *spec.ContributorPercentage } + +func (k Keeper) GetMinStake(ctx sdk.Context, chainID string) sdk.Coin { + spec, found := k.GetSpec(ctx, chainID) + if !found { + utils.LavaFormatError("critical: failed to get spec for chainID", + fmt.Errorf("unknown chainID"), + utils.Attribute{Key: "chainID", Value: chainID}, + ) + } + + return spec.MinStakeProvider +} From cee23f0de6fa9299c0b836f31a0552852fc93d0c Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Sun, 3 Dec 2023 09:50:24 -0500 Subject: [PATCH 23/85] Revert "Remove the option to set amount for staking provider from modify-provider" This reverts commit 68cb197307d72ab2199490ceee3731b028cf5f72. --- x/pairing/client/cli/tx_modify_provider.go | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/x/pairing/client/cli/tx_modify_provider.go b/x/pairing/client/cli/tx_modify_provider.go index 7f1df6086f..a534c21a6f 100644 --- a/x/pairing/client/cli/tx_modify_provider.go +++ b/x/pairing/client/cli/tx_modify_provider.go @@ -18,6 +18,7 @@ import ( ) const ( + AmountFlagName = "amount" EndpointsFlagName = "endpoints" GeolocationFlag = "geolocation" ValidatorFlag = "validator" @@ -63,7 +64,7 @@ func CmdModifyProvider() *cobra.Command { [chain-id] is the spec the provider wishes to modify the entry for `, Example: `lavad tx pairing modify-provider "ETH1" --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE --from -lavad tx pairing modify-provider "ETH1" --endpoints "my-provider-africa.com:443,AF my-provider-europe.com:443,EU" --geolocation "AF,EU" --validator lava@valoper13w8ffww0akdyhgls2umvvudce3jxzw2s7fwcnk --from `, + lavad tx pairing modify-provider "ETH1" --endpoints "my-provider-africa.com:443,AF my-provider-europe.com:443,EU" --geolocation "AF,EU" --validator lava@valoper13w8ffww0akdyhgls2umvvudce3jxzw2s7fwcnk --from `, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { argChainID := args[0] @@ -106,7 +107,20 @@ lavad tx pairing modify-provider "ETH1" --endpoints "my-provider-africa.com:443, if providerEntry == nil { return utils.LavaFormatError("provider isn't staked on chainID, no address match", nil) } - + newAmount, err := cmd.Flags().GetString(AmountFlagName) + if err != nil { + return err + } + if newAmount != "" { + newStake, err := sdk.ParseCoinNormalized(newAmount) + if err != nil { + return err + } + if providerEntry.Stake.Amount.GT(newStake.Amount) { + return utils.LavaFormatError("can't reduce provider stake", nil, utils.Attribute{Key: "current", Value: providerEntry.Stake}, utils.Attribute{Key: "requested", Value: providerEntry.Stake}) + } + providerEntry.Stake = newStake + } var geolocation int32 if cmd.Flags().Changed(GeolocationFlag) { geolocation, err = planstypes.ParseGeoEnum(geolocationVar.String()) @@ -184,6 +198,7 @@ lavad tx pairing modify-provider "ETH1" --endpoints "my-provider-africa.com:443, } cmd.Flags().String(types.FlagMoniker, "", "The provider's moniker (non-unique name)") cmd.Flags().String(EndpointsFlagName, "", "The endpoints provider is offering in the format \"endpoint-url,geolocation endpoint-url,geolocation\"") + cmd.Flags().String(AmountFlagName, "", "modify the provider's staked amount") cmd.Flags().String(ValidatorFlag, "", "the validator to delegate/bond to with dualstaking") cmd.Flags().Var(&geolocationVar, GeolocationFlag, `modify the provider's geolocation int32 or string value "EU,US"`) cmd.Flags().Uint64(types.FlagCommission, 100, "The provider's commission from the delegators (default 100)") From c8bca9a0c14c862b745c16f29308af94437dd841 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Sun, 3 Dec 2023 09:49:57 -0500 Subject: [PATCH 24/85] Revert "Disable the option to edit the stake amount from pairing" This reverts commit c844ed7d7f7117cfe4d35f731e6bf687794bbc04. --- x/pairing/keeper/staking.go | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/x/pairing/keeper/staking.go b/x/pairing/keeper/staking.go index cdb64d958d..482245b83e 100644 --- a/x/pairing/keeper/staking.go +++ b/x/pairing/keeper/staking.go @@ -72,15 +72,6 @@ func (k Keeper) StakeNewEntry(ctx sdk.Context, validator, creator, chainID strin utils.Attribute{Key: "provider", Value: senderAddr.String()}, ) } - - if !existingEntry.Stake.Equal(amount) { - return utils.LavaFormatWarning("cannot edit stake amount", fmt.Errorf("cannot edit stake amount"), - utils.Attribute{Key: "spec", Value: specChainID}, - utils.Attribute{Key: "provider", Value: senderAddr.String()}, - utils.Attribute{Key: "stake", Value: existingEntry.Stake}, - ) - } - details := []utils.Attribute{ {Key: "spec", Value: specChainID}, {Key: "provider", Value: senderAddr.String()}, @@ -98,6 +89,27 @@ func (k Keeper) StakeNewEntry(ctx sdk.Context, validator, creator, chainID strin k.epochStorageKeeper.ModifyStakeEntryCurrent(ctx, chainID, existingEntry, indexInStakeStorage) + if amount.Amount.GT(existingEntry.Stake.Amount) { + // delegate the difference + diffAmount := amount.Sub(existingEntry.Stake) + err = k.dualstakingKeeper.DelegateFull(ctx, senderAddr.String(), validator, senderAddr.String(), chainID, diffAmount) + if err != nil { + details = append(details, utils.Attribute{Key: "neededStake", Value: amount.Sub(existingEntry.Stake).String()}) + return utils.LavaFormatWarning("insufficient funds to pay for difference in stake", err, + details..., + ) + } + } else if amount.Amount.LT(existingEntry.Stake.Amount) { + // unbond the difference + diffAmount := existingEntry.Stake.Sub(amount) + err = k.dualstakingKeeper.UnbondFull(ctx, senderAddr.String(), validator, senderAddr.String(), chainID, diffAmount, false) + if err != nil { + details = append(details, utils.Attribute{Key: "neededStake", Value: amount.Sub(existingEntry.Stake).String()}) + return utils.LavaFormatWarning("insufficient funds to pay for difference in stake", err, + details..., + ) + } + } // TODO: create a new entry entirely because then we can keep the copies of this list as pointers only // then we need to change the Copy of StoreCurrentEpochStakeStorage to copy of the pointers only // must also change the unstaking to create a new entry entirely From 5e7b193d7bc3c91de27afb59c667e3dcbd18c367 Mon Sep 17 00:00:00 2001 From: oren-lava Date: Sun, 3 Dec 2023 17:54:52 +0200 Subject: [PATCH 25/85] CNS-715: PR fixes --- x/dualstaking/keeper/hooks.go | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/x/dualstaking/keeper/hooks.go b/x/dualstaking/keeper/hooks.go index e9493d2d82..1fd8251741 100644 --- a/x/dualstaking/keeper/hooks.go +++ b/x/dualstaking/keeper/hooks.go @@ -93,15 +93,19 @@ func (h Hooks) BeforeValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, f } // unbond from providers according to slash - // sort the delegations so if there's a remainder, remove it from the highest delegation in the last iteration + // sort the delegations from lowest to highest so if there's a remainder, + // remove it from the highest delegation in the last iteration remainingTokensToSlash := fraction.MulInt(val.Tokens).TruncateInt() delegations := h.k.stakingKeeper.GetValidatorDelegations(ctx, valAddr) slices.SortFunc(delegations, func(i, j stakingtypes.Delegation) bool { - return i.Shares.GT(j.Shares) + return val.TokensFromShares(i.Shares).LT(val.TokensFromShares(j.Shares)) }) for i, d := range delegations { tokens := val.TokensFromShares(d.Shares) tokensToSlash := fraction.Mul(tokens).TruncateInt() + if i == len(delegations)-1 { + tokensToSlash = remainingTokensToSlash + } err := h.k.UnbondUniformProviders(ctx, d.DelegatorAddress, sdk.NewCoin(commontypes.TokenDenom, tokensToSlash)) if err != nil { return utils.LavaFormatError("slash hook failed", err, @@ -111,17 +115,6 @@ func (h Hooks) BeforeValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, f ) } remainingTokensToSlash = remainingTokensToSlash.Sub(tokensToSlash) - - if !remainingTokensToSlash.IsZero() && i == len(delegations)-1 { - err := h.k.UnbondUniformProviders(ctx, delegations[0].DelegatorAddress, sdk.NewCoin(commontypes.TokenDenom, remainingTokensToSlash)) - if err != nil { - return utils.LavaFormatError("slash hook unbond remainder failed", err, - utils.Attribute{Key: "validator_address", Value: valAddr.String()}, - utils.Attribute{Key: "delegator_address", Value: delegations[0].DelegatorAddress}, - utils.Attribute{Key: "slash_amount", Value: remainingTokensToSlash.String()}, - ) - } - } } details := make(map[string]string) From 2d267ccb9c136edf3f85b3105c84e9bd090acafc Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Sun, 3 Dec 2023 16:26:44 +0000 Subject: [PATCH 26/85] fix init order --- testutil/keeper/keepers_init.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testutil/keeper/keepers_init.go b/testutil/keeper/keepers_init.go index aa09dee3a5..e218bd450b 100644 --- a/testutil/keeper/keepers_init.go +++ b/testutil/keeper/keepers_init.go @@ -223,11 +223,11 @@ func InitAllKeepers(t testing.TB) (*Servers, *Keepers, context.Context) { ks.TimerStoreKeeper = timerstorekeeper.NewKeeper(cdc) ks.AccountKeeper = mockAccountKeeper{} ks.BankKeeper = mockBankKeeper{} + ks.StakingKeeper = *stakingkeeper.NewKeeper(cdc, stakingStoreKey, ks.AccountKeeper, ks.BankKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String()) ks.Spec = *speckeeper.NewKeeper(cdc, specStoreKey, specMemStoreKey, specparamsSubspace, ks.StakingKeeper) ks.Epochstorage = *epochstoragekeeper.NewKeeper(cdc, epochStoreKey, epochMemStoreKey, epochparamsSubspace, &ks.BankKeeper, &ks.AccountKeeper, ks.Spec, ks.StakingKeeper) ks.FixationStoreKeeper = fixationkeeper.NewKeeper(cdc, ks.TimerStoreKeeper, ks.Epochstorage.BlocksToSaveRaw) ks.Dualstaking = *dualstakingkeeper.NewKeeper(cdc, dualstakingStoreKey, dualstakingMemStoreKey, dualstakingparamsSubspace, &ks.BankKeeper, &ks.StakingKeeper, &ks.AccountKeeper, ks.Epochstorage, ks.Spec, ks.FixationStoreKeeper) - ks.StakingKeeper = *stakingkeeper.NewKeeper(cdc, stakingStoreKey, ks.AccountKeeper, ks.BankKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String()) // register the staking hooks ks.StakingKeeper.SetHooks(stakingtypes.NewMultiStakingHooks(ks.Dualstaking.Hooks())) ks.SlashingKeeper = slashingkeeper.NewKeeper(cdc, legacyCdc, slashingStoreKey, ks.StakingKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String()) From a5a5eae3b9bfa5030d7ccd210b7aa0ea5c672396 Mon Sep 17 00:00:00 2001 From: Omer <100387053+omerlavanet@users.noreply.github.com> Date: Sun, 3 Dec 2023 18:47:37 +0200 Subject: [PATCH 27/85] PRT-1013-pick-the-best-endpoint (#999) * adding geolocations sorting * finished sorting endpoints by geolocation in the sdk * lint problems * problems * lint * fix geolocation missing field from endpoints * fix comnflict in merge * one more * provide more info when req block mismatch happens * add setting up npm for tests * added debug logs for sdk test * remove spamming log messages on transport * added more debug info * Some fixes * adjust ignore and lock * fix init_sdk * add block session when lock issues occur (super rare race) * adding readme for e2e * adding package json to e2e * commenting out emergency mode tests --------- Co-authored-by: Elad Gildnur Co-authored-by: Ran Mishael --- .gitignore | 1 - ecosystem/lava-sdk/scripts/init_sdk.sh | 5 + ecosystem/lava-sdk/src/config/default.ts | 3 +- ecosystem/lava-sdk/src/lavasession/common.ts | 19 + .../consumerSessionManager.test.ts | 6 +- .../src/lavasession/consumerSessionManager.ts | 9 +- .../src/lavasession/consumerTypes.test.ts | 5 + .../lava-sdk/src/lavasession/consumerTypes.ts | 8 +- .../lava-sdk/src/lavasession/geolocation.ts | 106 ++ .../src/rpcconsumer/rpcconsumer_server.ts | 23 +- ecosystem/lava-sdk/src/sdk/sdk.ts | 9 +- .../stateQuery/state_chain_query.ts | 6 +- .../updaters/emergency_tracker.test.ts | 12 +- .../stateTracker/updaters/pairing_updater.ts | 12 +- ecosystem/lava-sdk/src/util/transportNode.ts | 10 +- ecosystem/lava-sdk/yarn.lock | 1122 +++++++++-------- go.mod | 2 +- go.sum | 4 - protocol/lavasession/common.go | 19 + protocol/lavasession/common_test.go | 113 ++ .../lavasession/consumer_session_manager.go | 3 + protocol/lavasession/consumer_types.go | 2 + protocol/rpcprovider/rpcprovider_server.go | 10 +- protocol/statetracker/pairing_updater.go | 9 +- testutil/e2e/README.md | 21 +- testutil/e2e/lava_fullFlow_test.go | 2 + testutil/e2e/sdk/e2e.go | 4 +- .../e2e/sdk/tests/emergency_mode_badge.ts | 2 +- .../e2e/sdk/tests/emergency_mode_badge_err.ts | 2 +- .../e2e/sdk/tests/emergency_mode_fetch.ts | 2 +- .../e2e/sdk/tests/emergency_mode_fetch_err.ts | 2 +- testutil/e2e/sdk/tests/package.json | 5 + testutil/e2e/sdkE2E.go | 130 +- x/pairing/keeper/pairing_test.go | 2 +- x/pairing/keeper/scores/geo_req.go | 17 +- x/plans/types/geolocation.go | 2 +- x/spec/types/spec.go | 2 +- 37 files changed, 1045 insertions(+), 666 deletions(-) create mode 100644 ecosystem/lava-sdk/src/lavasession/geolocation.ts create mode 100644 protocol/lavasession/common_test.go create mode 100644 testutil/e2e/sdk/tests/package.json diff --git a/.gitignore b/.gitignore index 09aeb9d948..eab6fcc08e 100644 --- a/.gitignore +++ b/.gitignore @@ -86,7 +86,6 @@ ecosystem/lavajs/proto/gogoproto ecosystem/lavajs/proto/google ecosystem/lavajs/proto/tendermint -testutil/e2e/sdk/tests/package.json testutil/e2e/sdk/tests/package-lock.json testutil/e2e/sdk/tests/node_modules.json diff --git a/ecosystem/lava-sdk/scripts/init_sdk.sh b/ecosystem/lava-sdk/scripts/init_sdk.sh index 85436dca04..a3a955a194 100755 --- a/ecosystem/lava-sdk/scripts/init_sdk.sh +++ b/ecosystem/lava-sdk/scripts/init_sdk.sh @@ -112,3 +112,8 @@ if [ "$use_sudo" = true ]; then else ./scripts/protoc_grpc_relay.sh fi + +cd $__lava_root_dir/testutil/e2e/sdk/tests +npm install --save-dev @types/node + +cd $curr_dir \ No newline at end of file diff --git a/ecosystem/lava-sdk/src/config/default.ts b/ecosystem/lava-sdk/src/config/default.ts index 9c856b0f78..da26bf3fb4 100644 --- a/ecosystem/lava-sdk/src/config/default.ts +++ b/ecosystem/lava-sdk/src/config/default.ts @@ -1,8 +1,9 @@ +import { Geolocation } from "../lavasession/geolocation"; export const DEFAULT_LAVA_PAIRING_LIST = "https://raw.githubusercontent.com/lavanet/lava-providers/main/sdkSeedProviders.json"; export const DEFAULT_LAVA_PAIRING_NETWORK = "testnet"; export const LAVA_CHAIN_ID = "LAV1"; -export const DEFAULT_GEOLOCATION = "1"; +export const DEFAULT_GEOLOCATION = Geolocation.USC; export const DEFAULT_NETWORKS = ["mainnet", "testnet"]; export const DEFAULT_LAVA_CHAINID = "lava-testnet-2"; export const BOOT_RETRY_ATTEMPTS = 2; diff --git a/ecosystem/lava-sdk/src/lavasession/common.ts b/ecosystem/lava-sdk/src/lavasession/common.ts index a8e723726b..819c0e3ba5 100644 --- a/ecosystem/lava-sdk/src/lavasession/common.ts +++ b/ecosystem/lava-sdk/src/lavasession/common.ts @@ -1,3 +1,5 @@ +import { Endpoint } from "./consumerTypes"; +import { Geolocation, calcGeoLatency } from "./geolocation"; export const AVAILABILITY_PERCENTAGE = 0.1; export const MAX_ALLOWED_BLOCK_LISTED_SESSION_PER_PROVIDER = 3; export const MAX_SESSIONS_ALLOWED_PER_PROVIDER = 1000; @@ -24,3 +26,20 @@ export function GetAllProviders( return returnedProviders; } + +export function SortByGeolocations( + pairingEndpoints: Array, + currentGeo: Geolocation +) { + const latencyToGeo = function (a: Geolocation, b: Geolocation): number { + return calcGeoLatency(a, b); + }; + + // sort the endpoints by geolocation relevance: + const lessFunc = function (a: Endpoint, b: Endpoint): Geolocation { + const latencyA = latencyToGeo(a.geolocation, currentGeo); + const latencyB = latencyToGeo(b.geolocation, currentGeo); + return latencyA - latencyB; + }; + pairingEndpoints.sort(lessFunc); +} diff --git a/ecosystem/lava-sdk/src/lavasession/consumerSessionManager.test.ts b/ecosystem/lava-sdk/src/lavasession/consumerSessionManager.test.ts index 82cc00fb31..23802cba88 100644 --- a/ecosystem/lava-sdk/src/lavasession/consumerSessionManager.test.ts +++ b/ecosystem/lava-sdk/src/lavasession/consumerSessionManager.test.ts @@ -57,7 +57,7 @@ function setupConsumerSessionManager( const cm = new ConsumerSessionManager( relayer, - new RPCEndpoint("stub", "stub", "stub", "0"), + new RPCEndpoint("stub", "stub", "stub", 1), optimizer ); @@ -1129,6 +1129,7 @@ function createPairingList( addons: new Set(), connectionRefusals: 0, enabled, + geolocation: 1, }, ]; const pairingEndpointsWithAddon: Endpoint[] = [ @@ -1138,6 +1139,7 @@ function createPairingList( addons: new Set(["addon"]), connectionRefusals: 0, enabled, + geolocation: 1, }, ]; const pairingEndpointsWithExtension: Endpoint[] = [ @@ -1147,6 +1149,7 @@ function createPairingList( addons: new Set(["addon"]), connectionRefusals: 0, enabled, + geolocation: 1, }, ]; const pairingEndpointsWithExtensions: Endpoint[] = [ @@ -1156,6 +1159,7 @@ function createPairingList( addons: new Set(["addon"]), connectionRefusals: 0, enabled, + geolocation: 1, }, ]; diff --git a/ecosystem/lava-sdk/src/lavasession/consumerSessionManager.ts b/ecosystem/lava-sdk/src/lavasession/consumerSessionManager.ts index 5a49df69ab..557935f649 100644 --- a/ecosystem/lava-sdk/src/lavasession/consumerSessionManager.ts +++ b/ecosystem/lava-sdk/src/lavasession/consumerSessionManager.ts @@ -129,13 +129,18 @@ export class ConsumerSessionManager { ) { this.allowedUpdateForCurrentEpoch = false; } else { - const errorMsg = `Trying to update provider list for older epoch ${JSON.stringify( + let errorMsg = `Trying to update provider list for older epoch ${JSON.stringify( { epoch, currentEpoch: this.currentEpoch, } )}`; - Logger.error(errorMsg); + if (epoch == this.currentEpoch) { + errorMsg += ", this is ok only during emergency mode"; + Logger.warn(errorMsg); + } else { + Logger.error(errorMsg); + } return new Error(errorMsg); } } diff --git a/ecosystem/lava-sdk/src/lavasession/consumerTypes.test.ts b/ecosystem/lava-sdk/src/lavasession/consumerTypes.test.ts index 041f5d2f32..ee4946430e 100644 --- a/ecosystem/lava-sdk/src/lavasession/consumerTypes.test.ts +++ b/ecosystem/lava-sdk/src/lavasession/consumerTypes.test.ts @@ -5,9 +5,12 @@ import { QoSReport, SingleConsumerSession, } from "./consumerTypes"; +import { Geolocation } from "./geolocation"; import { AVAILABILITY_PERCENTAGE } from "./common"; import { AlreadyLockedError, NotLockedError } from "./errors"; +const geolocationValue: Geolocation = Geolocation.USC; + describe("consumerTypes", () => { describe("SingleConsumerSession", () => { it("tests locking", () => { @@ -20,6 +23,7 @@ describe("consumerTypes", () => { extensions: new Set(), addons: new Set(), connectionRefusals: 0, + geolocation: geolocationValue, } ); @@ -40,6 +44,7 @@ describe("consumerTypes", () => { extensions: new Set(), addons: new Set(), connectionRefusals: 0, + geolocation: geolocationValue, } ); diff --git a/ecosystem/lava-sdk/src/lavasession/consumerTypes.ts b/ecosystem/lava-sdk/src/lavasession/consumerTypes.ts index 6e59230189..3e17ca7d2e 100644 --- a/ecosystem/lava-sdk/src/lavasession/consumerTypes.ts +++ b/ecosystem/lava-sdk/src/lavasession/consumerTypes.ts @@ -25,7 +25,7 @@ import { ReportedProvider, } from "../grpc_web_services/lavanet/lava/pairing/relay_pb"; import { ProviderOptimizerStrategy } from "../providerOptimizer/providerOptimizer"; - +import { Geolocation } from "./geolocation"; export interface SessionInfo { session: SingleConsumerSession; epoch: number; @@ -123,6 +123,7 @@ export class SingleConsumerSession { connectionRefusals: 0, addons: new Set(), extensions: new Set(), + geolocation: 0, }; public blockListed = false; public consecutiveNumberOfFailures = 0; @@ -253,19 +254,20 @@ export interface Endpoint { connectionRefusals: number; addons: Set; extensions: Set; + geolocation: Geolocation; } export class RPCEndpoint { public networkAddress = ""; public chainId = ""; public apiInterface = ""; - public geolocation = "1"; + public geolocation: Geolocation = 1; public constructor( address: string, chainId: string, apiInterface: string, - geolocation: string + geolocation: Geolocation ) { this.networkAddress = address; this.chainId = chainId; diff --git a/ecosystem/lava-sdk/src/lavasession/geolocation.ts b/ecosystem/lava-sdk/src/lavasession/geolocation.ts new file mode 100644 index 0000000000..d3e726d1f2 --- /dev/null +++ b/ecosystem/lava-sdk/src/lavasession/geolocation.ts @@ -0,0 +1,106 @@ +export enum Geolocation { + GLS = 0, + USC = 1, + EU = 2, + USE = 4, + USW = 8, + AF = 16, + AS = 32, + AU = 64, + GL = 65535, +} + +const GeolocationName: Record = { + 0: "GLS", + 1: "USC", + 2: "EU", + 4: "USE", + 8: "USW", + 16: "AF", + 32: "AS", + 64: "AU", + 65535: "GL", +}; + +const GeolocationValue: Record = { + GLS: 0, + USC: 1, + EU: 2, + USE: 4, + USW: 8, + AF: 16, + AS: 32, + AU: 64, + GL: 65535, +}; + +type GeoLatencyMap = Record>; +const maxGeoLatency = 10000; +const GEO_LATENCY_MAP: GeoLatencyMap = { + [Geolocation.AS]: { + [Geolocation.AU]: 146, + [Geolocation.EU]: 155, + }, + [Geolocation.USE]: { + [Geolocation.USC]: 42, + [Geolocation.USW]: 68, + [Geolocation.EU]: 116, + }, + [Geolocation.USW]: { + [Geolocation.USC]: 45, + [Geolocation.USE]: 68, + }, + [Geolocation.USC]: { + [Geolocation.USE]: 42, + [Geolocation.USW]: 45, + [Geolocation.EU]: 170, + }, + [Geolocation.EU]: { + [Geolocation.USE]: 116, + [Geolocation.AF]: 138, + [Geolocation.AS]: 155, + [Geolocation.USC]: 170, + }, + [Geolocation.AF]: { + [Geolocation.EU]: 138, + [Geolocation.USE]: 203, + [Geolocation.AS]: 263, + }, + [Geolocation.AU]: { + [Geolocation.AS]: 146, + [Geolocation.USW]: 179, + }, +} as GeoLatencyMap; + +export function calcGeoLatency(reqGeo: Geolocation, pGeo: Geolocation): number { + let minLatency: number = maxGeoLatency; + + if (pGeo === reqGeo) { + minLatency = 1; + } + + const inner = GEO_LATENCY_MAP[reqGeo]; + if (inner && inner[pGeo] !== undefined) { + const latency = inner[pGeo]; + if (latency < minLatency) { + minLatency = latency; + } + } + + return minLatency; +} + +export function GeolocationFromString(geolocation: string): Geolocation { + const parsedValue = parseInt(geolocation, 10); + + if (!isNaN(parsedValue) && GeolocationName.hasOwnProperty(parsedValue)) { + return parsedValue as Geolocation; + } + + const upperCaseGeo = geolocation.toUpperCase(); + if (GeolocationValue.hasOwnProperty(upperCaseGeo)) { + return GeolocationValue[upperCaseGeo] as Geolocation; + } + + throw new Error(`Invalid Geolocation: ${geolocation}`); +} diff --git a/ecosystem/lava-sdk/src/rpcconsumer/rpcconsumer_server.ts b/ecosystem/lava-sdk/src/rpcconsumer/rpcconsumer_server.ts index 3e757d88e4..4acdc2184a 100644 --- a/ecosystem/lava-sdk/src/rpcconsumer/rpcconsumer_server.ts +++ b/ecosystem/lava-sdk/src/rpcconsumer/rpcconsumer_server.ts @@ -233,7 +233,11 @@ export class RPCConsumerServer { const singleConsumerSession = sessionInfo.session; const epoch = sessionInfo.epoch; const reportedProviders = sessionInfo.reportedProviders; - + Logger.debug( + `Before Construct: ${relayData.getRequestBlock()}, address: ${providerPublicAddress}, session: ${ + singleConsumerSession.sessionId + }` + ); relayResult.request = constructRelayRequest( lavaChainId, chainID, @@ -245,7 +249,19 @@ export class RPCConsumerServer { ); Logger.info(`Sending relay to provider ${providerPublicAddress}`); - + Logger.debug( + `Relay stats sessionId:${ + singleConsumerSession.sessionId + }, guid:${relayResult.request + .getRelayData() + ?.getSalt_asB64()}, requestedBlock: ${relayResult.request + .getRelayData() + ?.getRequestBlock()}, apiInterface:${relayResult.request + .getRelayData() + ?.getApiInterface()}, seenBlock: ${relayResult.request + .getRelayData() + ?.getSeenBlock()}` + ); const promise = this.relayInner( singleConsumerSession, relayResult, @@ -383,7 +399,10 @@ export class RPCConsumerServer { return relayResponse; } const chainBlockStats = this.chainParser.chainBlockStats(); + Logger.debug("Updating requested Block", singleConsumerSession.sessionId); UpdateRequestedBlock(relayData, reply); + Logger.debug("after Updating", relayData.getRequestBlock()); + Logger.debug("did errored", relayResponse.err); const finalized = IsFinalizedBlock( relayData.getRequestBlock(), reply.getLatestBlock(), diff --git a/ecosystem/lava-sdk/src/sdk/sdk.ts b/ecosystem/lava-sdk/src/sdk/sdk.ts index 601ba722b9..a856572697 100644 --- a/ecosystem/lava-sdk/src/sdk/sdk.ts +++ b/ecosystem/lava-sdk/src/sdk/sdk.ts @@ -33,6 +33,7 @@ import { } from "../providerOptimizer/providerOptimizer"; import { AverageWorldLatency } from "../common/timeout"; import { ConsumerConsistency } from "../rpcconsumer/consumerConsistency"; +import { GeolocationFromString } from "../lavasession/geolocation"; export type ChainIDsToInit = string | string[]; // chainId or an array of chain ids to initialize sdk for. type RelayReceiver = string; // chainId + ApiInterface @@ -46,7 +47,7 @@ export interface LavaSDKOptions { chainIds: ChainIDsToInit; // Required: The ID of the chain you want to query or an array of chain ids example "ETH1" | ["ETH1", "LAV1"] pairingListConfig?: string; // Optional: The Lava pairing list config used for communicating with the Lava network network?: string; // Optional: The network from pairingListConfig to be used ["mainnet", "testnet"] - geolocation?: string; // Optional: The geolocation to be used ["1" for North America, "2" for Europe ] + geolocation?: string; // Optional: The geolocation to be used ["1" or "USC" for US central, "2" or "EU" for Europe, 4: "USE", 8: "USW", 16: "AF", 32: "AS", 64: "AU"] lavaChainId?: string; // Optional: The Lava chain ID (default value for Lava Testnet) secure?: boolean; // Optional: communicates through https, this is a temporary flag that will be disabled once the chain will use https by default allowInsecureTransport?: boolean; // Optional: indicates to use a insecure transport when connecting the provider, this is used for testing purposes only and allows self-signed certificates to be used @@ -121,7 +122,7 @@ export class LavaSDK { this.walletAddress = ""; this.badgeManager = new BadgeManager(badge); this.network = network || DEFAULT_LAVA_PAIRING_NETWORK; - this.geolocation = geolocation || DEFAULT_GEOLOCATION; + this.geolocation = geolocation || DEFAULT_GEOLOCATION.toString(); this.lavaChainId = lavaChainId || DEFAULT_LAVA_CHAINID; this.pairingListConfig = pairingListConfig || ""; this.account = SDKErrors.errAccountNotInitialized; @@ -189,7 +190,7 @@ export class LavaSDK { "", // We do no need this in sdk as we are not opening any ports "LAV1", "tendermintrpc", - this.geolocation // This is also deprecated + GeolocationFromString(this.geolocation) // This is also deprecated ); const chainAsset = this.setupChainAssets( @@ -329,7 +330,7 @@ export class LavaSDK { "", // We do no need this in sdk as we are not opening any ports chainId, apiInterface, - this.geolocation // This is also deprecated + GeolocationFromString(this.geolocation) ); // create provider optimizer diff --git a/ecosystem/lava-sdk/src/stateTracker/stateQuery/state_chain_query.ts b/ecosystem/lava-sdk/src/stateTracker/stateQuery/state_chain_query.ts index b3ba029cd5..5cf6247041 100644 --- a/ecosystem/lava-sdk/src/stateTracker/stateQuery/state_chain_query.ts +++ b/ecosystem/lava-sdk/src/stateTracker/stateQuery/state_chain_query.ts @@ -21,6 +21,7 @@ import { SendRelayOptions } from "../../chainlib/base_chain_parser"; import { Spec } from "../../grpc_web_services/lavanet/lava/spec/spec_pb"; import { StakeEntry } from "../../grpc_web_services/lavanet/lava/epochstorage/stake_entry_pb"; import { Endpoint as PairingEndpoint } from "../../grpc_web_services/lavanet/lava/epochstorage/endpoint_pb"; +import { GeolocationFromString } from "../../lavasession/geolocation"; import { Params as DowntimeParams } from "../../grpc_web_services/lavanet/lava/downtime/v1/downtime_pb"; interface PairingList { @@ -328,7 +329,9 @@ export class StateChainQuery { const pairingEndpoint = new PairingEndpoint(); pairingEndpoint.setIpport(provider.rpcAddress); pairingEndpoint.setApiInterfacesList(["tendermintrpc"]); - pairingEndpoint.setGeolocation(Number(this.config.geolocation)); + pairingEndpoint.setGeolocation( + GeolocationFromString(this.config.geolocation) + ); // Add newly created endpoint in the pairing endpoint list pairingEndpoints.push(pairingEndpoint); @@ -338,6 +341,7 @@ export class StateChainQuery { connectionRefusals: 0, addons: new Set(), extensions: new Set(), + geolocation: GeolocationFromString(this.config.geolocation), }; // Create a new pairing object diff --git a/ecosystem/lava-sdk/src/stateTracker/updaters/emergency_tracker.test.ts b/ecosystem/lava-sdk/src/stateTracker/updaters/emergency_tracker.test.ts index e3aef73473..b204efd360 100644 --- a/ecosystem/lava-sdk/src/stateTracker/updaters/emergency_tracker.test.ts +++ b/ecosystem/lava-sdk/src/stateTracker/updaters/emergency_tracker.test.ts @@ -108,7 +108,7 @@ describe("EmergencyTracker", () => { relayer, cm, new TendermintRpcChainParser(), - DEFAULT_GEOLOCATION, + DEFAULT_GEOLOCATION.toString(), rpcEndpoint, "LAV1", finalizationConsensus, @@ -121,7 +121,7 @@ describe("EmergencyTracker", () => { relayer, ["LAV1"], { - geolocation: DEFAULT_GEOLOCATION, + geolocation: DEFAULT_GEOLOCATION.toString(), network: DEFAULT_LAVA_PAIRING_NETWORK, }, rpcConsumerServerLoL, @@ -192,7 +192,7 @@ describe("EmergencyTracker", () => { relayer, cm, new TendermintRpcChainParser(), - DEFAULT_GEOLOCATION, + DEFAULT_GEOLOCATION.toString(), rpcEndpoint, "LAV1", finalizationConsensus, @@ -211,7 +211,7 @@ describe("EmergencyTracker", () => { relayer, ["LAV1"], { - geolocation: DEFAULT_GEOLOCATION, + geolocation: DEFAULT_GEOLOCATION.toString(), network: DEFAULT_LAVA_PAIRING_NETWORK, }, rpcConsumerServerLoL, @@ -252,6 +252,7 @@ function createPairingList( addons: new Set(), connectionRefusals: 0, enabled, + geolocation: DEFAULT_GEOLOCATION, }, ]; const pairingEndpointsWithAddon: Endpoint[] = [ @@ -261,6 +262,7 @@ function createPairingList( addons: new Set(["addon"]), connectionRefusals: 0, enabled, + geolocation: DEFAULT_GEOLOCATION, }, ]; const pairingEndpointsWithExtension: Endpoint[] = [ @@ -270,6 +272,7 @@ function createPairingList( addons: new Set(["addon"]), connectionRefusals: 0, enabled, + geolocation: DEFAULT_GEOLOCATION, }, ]; const pairingEndpointsWithExtensions: Endpoint[] = [ @@ -279,6 +282,7 @@ function createPairingList( addons: new Set(["addon"]), connectionRefusals: 0, enabled, + geolocation: DEFAULT_GEOLOCATION, }, ]; diff --git a/ecosystem/lava-sdk/src/stateTracker/updaters/pairing_updater.ts b/ecosystem/lava-sdk/src/stateTracker/updaters/pairing_updater.ts index e40aeaab6f..37883f00b2 100644 --- a/ecosystem/lava-sdk/src/stateTracker/updaters/pairing_updater.ts +++ b/ecosystem/lava-sdk/src/stateTracker/updaters/pairing_updater.ts @@ -8,6 +8,8 @@ import { ConsumerSessionsWithProvider } from "../../lavasession/consumerTypes"; import { PairingResponse } from "../stateQuery/state_query"; import { Config } from "../state_tracker"; import { Endpoint as ConsumerEndpoint } from "../../lavasession/consumerTypes"; +import { SortByGeolocations } from "../../lavasession/common"; +import { GeolocationFromString } from "../../lavasession/geolocation"; export class PairingUpdater { private stateQuery: StateQuery; @@ -146,14 +148,22 @@ export class PairingUpdater { networkAddress: endpoint.getIpport(), enabled: true, connectionRefusals: 0, + geolocation: endpoint.getGeolocation(), }; - if (endpoint.getGeolocation() == Number(this.config.geolocation)) { + if ( + endpoint.getGeolocation() == + GeolocationFromString(this.config.geolocation) + ) { sameGeoEndpoints.push(consumerEndpoint); // set same geo location provider endpoint } else { differntGeoEndpoints.push(consumerEndpoint); // set different geo location provider endpoint } } + SortByGeolocations( + differntGeoEndpoints, + GeolocationFromString(this.config.geolocation) + ); // skip if we have no endpoints at all. if (sameGeoEndpoints.length == 0 && differntGeoEndpoints.length == 0) { diff --git a/ecosystem/lava-sdk/src/util/transportNode.ts b/ecosystem/lava-sdk/src/util/transportNode.ts index ca75c536dc..f1230ed55a 100644 --- a/ecosystem/lava-sdk/src/util/transportNode.ts +++ b/ecosystem/lava-sdk/src/util/transportNode.ts @@ -40,18 +40,18 @@ class NodeHttp implements grpc.Transport { } responseCallback(response: http.IncomingMessage) { - Logger.debug("NodeHttp.response", response.statusCode); + // Logger.debug("NodeHttp.response", response.statusCode); const headers = filterHeadersForUndefined(response.headers); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion this.options.onHeaders(new grpc.Metadata(headers), response.statusCode!); response.on("data", (chunk) => { - Logger.debug("NodeHttp.data", chunk); + // Logger.debug("NodeHttp.data", chunk); this.options.onChunk(toArrayBuffer(chunk as Buffer)); }); response.on("end", () => { - Logger.debug("NodeHttp.end"); + // Logger.debug("NodeHttp.end"); this.options.onEnd(); }); } @@ -82,13 +82,13 @@ class NodeHttp implements grpc.Transport { ); } this.request.on("error", (err) => { - Logger.debug("NodeHttp.error", err); + // Logger.debug("NodeHttp.error", err); this.options.onEnd(err); }); } cancel() { - Logger.debug("NodeHttp.abort"); + // Logger.debug("NodeHttp.abort"); this.request.destroy(); } } diff --git a/ecosystem/lava-sdk/yarn.lock b/ecosystem/lava-sdk/yarn.lock index d8c1d97a7c..9caa30111e 100644 --- a/ecosystem/lava-sdk/yarn.lock +++ b/ecosystem/lava-sdk/yarn.lock @@ -103,10 +103,10 @@ "@babel/traverse" "^7.20.1" "@babel/types" "^7.20.2" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.8.0": - version "7.20.2" - resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz" - integrity sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ== +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz" + integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== "@babel/helper-simple-access@^7.20.2": version "7.20.2" @@ -122,15 +122,15 @@ dependencies: "@babel/types" "^7.18.6" -"@babel/helper-string-parser@^7.19.4": - version "7.19.4" - resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz" - integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== +"@babel/helper-string-parser@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz" + integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== -"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": - version "7.19.1" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz" - integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== +"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1", "@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== "@babel/helper-validator-option@^7.18.6": version "7.18.6" @@ -155,10 +155,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.10", "@babel/parser@^7.20.1", "@babel/parser@^7.20.2": - version "7.20.3" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz" - integrity sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.10", "@babel/parser@^7.20.1", "@babel/parser@^7.20.2", "@babel/parser@^7.20.7": + version "7.23.0" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz" + integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -196,11 +196,11 @@ "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-jsx@^7.7.2": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz" - integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q== + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz" + integrity sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg== dependencies: - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" @@ -252,11 +252,11 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-typescript@^7.7.2": - version "7.20.0" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz" - integrity sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ== + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz" + integrity sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ== dependencies: - "@babel/helper-plugin-utils" "^7.19.0" + "@babel/helper-plugin-utils" "^7.22.5" "@babel/template@^7.18.10", "@babel/template@^7.3.3": version "7.18.10" @@ -267,7 +267,7 @@ "@babel/parser" "^7.18.10" "@babel/types" "^7.18.10" -"@babel/traverse@^7.20.1", "@babel/traverse@^7.7.2": +"@babel/traverse@^7.20.1": version "7.20.1" resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz" integrity sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA== @@ -283,13 +283,13 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.19.0", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.3.0", "@babel/types@^7.3.3": - version "7.20.2" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.20.2.tgz" - integrity sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog== +"@babel/types@^7.0.0", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.19.0", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.7", "@babel/types@^7.3.3": + version "7.23.0" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz" + integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg== dependencies: - "@babel/helper-string-parser" "^7.19.4" - "@babel/helper-validator-identifier" "^7.19.1" + "@babel/helper-string-parser" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" "@bcoe/v8-coverage@^0.2.3": @@ -632,110 +632,110 @@ resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@jest/console@^29.3.1": - version "29.3.1" - resolved "https://registry.npmjs.org/@jest/console/-/console-29.3.1.tgz" - integrity sha512-IRE6GD47KwcqA09RIWrabKdHPiKDGgtAL31xDxbi/RjQMsr+lY+ppxmHwY0dUEV3qvvxZzoe5Hl0RXZJOjQNUg== +"@jest/console@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz" + integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== dependencies: - "@jest/types" "^29.3.1" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" - jest-message-util "^29.3.1" - jest-util "^29.3.1" + jest-message-util "^29.7.0" + jest-util "^29.7.0" slash "^3.0.0" -"@jest/core@^29.3.1": - version "29.3.1" - resolved "https://registry.npmjs.org/@jest/core/-/core-29.3.1.tgz" - integrity sha512-0ohVjjRex985w5MmO5L3u5GR1O30DexhBSpuwx2P+9ftyqHdJXnk7IUWiP80oHMvt7ubHCJHxV0a0vlKVuZirw== +"@jest/core@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz" + integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== dependencies: - "@jest/console" "^29.3.1" - "@jest/reporters" "^29.3.1" - "@jest/test-result" "^29.3.1" - "@jest/transform" "^29.3.1" - "@jest/types" "^29.3.1" + "@jest/console" "^29.7.0" + "@jest/reporters" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" ci-info "^3.2.0" exit "^0.1.2" graceful-fs "^4.2.9" - jest-changed-files "^29.2.0" - jest-config "^29.3.1" - jest-haste-map "^29.3.1" - jest-message-util "^29.3.1" - jest-regex-util "^29.2.0" - jest-resolve "^29.3.1" - jest-resolve-dependencies "^29.3.1" - jest-runner "^29.3.1" - jest-runtime "^29.3.1" - jest-snapshot "^29.3.1" - jest-util "^29.3.1" - jest-validate "^29.3.1" - jest-watcher "^29.3.1" + jest-changed-files "^29.7.0" + jest-config "^29.7.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-resolve-dependencies "^29.7.0" + jest-runner "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + jest-watcher "^29.7.0" micromatch "^4.0.4" - pretty-format "^29.3.1" + pretty-format "^29.7.0" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^29.3.1": - version "29.3.1" - resolved "https://registry.npmjs.org/@jest/environment/-/environment-29.3.1.tgz" - integrity sha512-pMmvfOPmoa1c1QpfFW0nXYtNLpofqo4BrCIk6f2kW4JFeNlHV2t3vd+3iDLf31e2ot2Mec0uqZfmI+U0K2CFag== +"@jest/environment@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz" + integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== dependencies: - "@jest/fake-timers" "^29.3.1" - "@jest/types" "^29.3.1" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" - jest-mock "^29.3.1" + jest-mock "^29.7.0" -"@jest/expect-utils@^29.3.1": - version "29.3.1" - resolved "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.3.1.tgz" - integrity sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g== +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== dependencies: - jest-get-type "^29.2.0" + jest-get-type "^29.6.3" -"@jest/expect@^29.3.1": - version "29.3.1" - resolved "https://registry.npmjs.org/@jest/expect/-/expect-29.3.1.tgz" - integrity sha512-QivM7GlSHSsIAWzgfyP8dgeExPRZ9BIe2LsdPyEhCGkZkoyA+kGsoIzbKAfZCvvRzfZioKwPtCZIt5SaoxYCvg== +"@jest/expect@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz" + integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== dependencies: - expect "^29.3.1" - jest-snapshot "^29.3.1" + expect "^29.7.0" + jest-snapshot "^29.7.0" -"@jest/fake-timers@^29.3.1": - version "29.3.1" - resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.3.1.tgz" - integrity sha512-iHTL/XpnDlFki9Tq0Q1GGuVeQ8BHZGIYsvCO5eN/O/oJaRzofG9Xndd9HuSDBI/0ZS79pg0iwn07OMTQ7ngF2A== +"@jest/fake-timers@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz" + integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== dependencies: - "@jest/types" "^29.3.1" - "@sinonjs/fake-timers" "^9.1.2" + "@jest/types" "^29.6.3" + "@sinonjs/fake-timers" "^10.0.2" "@types/node" "*" - jest-message-util "^29.3.1" - jest-mock "^29.3.1" - jest-util "^29.3.1" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-util "^29.7.0" -"@jest/globals@^29.3.1": - version "29.3.1" - resolved "https://registry.npmjs.org/@jest/globals/-/globals-29.3.1.tgz" - integrity sha512-cTicd134vOcwO59OPaB6AmdHQMCtWOe+/DitpTZVxWgMJ+YvXL1HNAmPyiGbSHmF/mXVBkvlm8YYtQhyHPnV6Q== +"@jest/globals@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz" + integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== dependencies: - "@jest/environment" "^29.3.1" - "@jest/expect" "^29.3.1" - "@jest/types" "^29.3.1" - jest-mock "^29.3.1" + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/types" "^29.6.3" + jest-mock "^29.7.0" -"@jest/reporters@^29.3.1": - version "29.3.1" - resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-29.3.1.tgz" - integrity sha512-GhBu3YFuDrcAYW/UESz1JphEAbvUjaY2vShRZRoRY1mxpCMB3yGSJ4j9n0GxVlEOdCf7qjvUfBCrTUUqhVfbRA== +"@jest/reporters@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz" + integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^29.3.1" - "@jest/test-result" "^29.3.1" - "@jest/transform" "^29.3.1" - "@jest/types" "^29.3.1" - "@jridgewell/trace-mapping" "^0.3.15" + "@jest/console" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" "@types/node" "*" chalk "^4.0.0" collect-v8-coverage "^1.0.0" @@ -743,81 +743,81 @@ glob "^7.1.3" graceful-fs "^4.2.9" istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^5.1.0" + istanbul-lib-instrument "^6.0.0" istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" istanbul-reports "^3.1.3" - jest-message-util "^29.3.1" - jest-util "^29.3.1" - jest-worker "^29.3.1" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + jest-worker "^29.7.0" slash "^3.0.0" string-length "^4.0.1" strip-ansi "^6.0.0" v8-to-istanbul "^9.0.1" -"@jest/schemas@^29.0.0": - version "29.0.0" - resolved "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz" - integrity sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA== +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== dependencies: - "@sinclair/typebox" "^0.24.1" + "@sinclair/typebox" "^0.27.8" -"@jest/source-map@^29.2.0": - version "29.2.0" - resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-29.2.0.tgz" - integrity sha512-1NX9/7zzI0nqa6+kgpSdKPK+WU1p+SJk3TloWZf5MzPbxri9UEeXX5bWZAPCzbQcyuAzubcdUHA7hcNznmRqWQ== +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== dependencies: - "@jridgewell/trace-mapping" "^0.3.15" + "@jridgewell/trace-mapping" "^0.3.18" callsites "^3.0.0" graceful-fs "^4.2.9" -"@jest/test-result@^29.3.1": - version "29.3.1" - resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-29.3.1.tgz" - integrity sha512-qeLa6qc0ddB0kuOZyZIhfN5q0e2htngokyTWsGriedsDhItisW7SDYZ7ceOe57Ii03sL988/03wAcBh3TChMGw== +"@jest/test-result@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz" + integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== dependencies: - "@jest/console" "^29.3.1" - "@jest/types" "^29.3.1" + "@jest/console" "^29.7.0" + "@jest/types" "^29.6.3" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^29.3.1": - version "29.3.1" - resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.3.1.tgz" - integrity sha512-IqYvLbieTv20ArgKoAMyhLHNrVHJfzO6ARZAbQRlY4UGWfdDnLlZEF0BvKOMd77uIiIjSZRwq3Jb3Fa3I8+2UA== +"@jest/test-sequencer@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz" + integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== dependencies: - "@jest/test-result" "^29.3.1" + "@jest/test-result" "^29.7.0" graceful-fs "^4.2.9" - jest-haste-map "^29.3.1" + jest-haste-map "^29.7.0" slash "^3.0.0" -"@jest/transform@^29.3.1": - version "29.3.1" - resolved "https://registry.npmjs.org/@jest/transform/-/transform-29.3.1.tgz" - integrity sha512-8wmCFBTVGYqFNLWfcOWoVuMuKYPUBTnTMDkdvFtAYELwDOl9RGwOsvQWGPFxDJ8AWY9xM/8xCXdqmPK3+Q5Lug== +"@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== dependencies: "@babel/core" "^7.11.6" - "@jest/types" "^29.3.1" - "@jridgewell/trace-mapping" "^0.3.15" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" babel-plugin-istanbul "^6.1.1" chalk "^4.0.0" convert-source-map "^2.0.0" fast-json-stable-stringify "^2.1.0" graceful-fs "^4.2.9" - jest-haste-map "^29.3.1" - jest-regex-util "^29.2.0" - jest-util "^29.3.1" + jest-haste-map "^29.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" micromatch "^4.0.4" pirates "^4.0.4" slash "^3.0.0" - write-file-atomic "^4.0.1" + write-file-atomic "^4.0.2" -"@jest/types@^29.3.1": - version "29.3.1" - resolved "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz" - integrity sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA== +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== dependencies: - "@jest/schemas" "^29.0.0" + "@jest/schemas" "^29.6.3" "@types/istanbul-lib-coverage" "^2.0.0" "@types/istanbul-reports" "^3.0.0" "@types/node" "*" @@ -841,7 +841,7 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/resolve-uri@3.1.0", "@jridgewell/resolve-uri@^3.0.3": +"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": version "3.1.0" resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== @@ -859,7 +859,7 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": version "1.4.14" resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== @@ -872,13 +872,13 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.14", "@jridgewell/trace-mapping@^0.3.15", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.16" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.16.tgz" - integrity sha512-LCQ+NeThyJ4k1W2d+vIKdxuSt9R3pQSZ4P92m7EakaYuXcVWbHuT5bjNcqLd4Rdgi6xYWYDvBJZJLZSLanjDcA== +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.14", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.19" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz" + integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== dependencies: - "@jridgewell/resolve-uri" "3.1.0" - "@jridgewell/sourcemap-codec" "1.4.14" + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" "@noble/hashes@^1", "@noble/hashes@^1.0.0", "@noble/hashes@^1.2.0": version "1.3.0" @@ -959,29 +959,29 @@ resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz" integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA= -"@sinclair/typebox@^0.24.1": - version "0.24.51" - resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz" - integrity sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA== +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== "@sindresorhus/is@^0.7.0": version "0.7.0" resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz" integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== -"@sinonjs/commons@^1.7.0": - version "1.8.5" - resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.5.tgz" - integrity sha512-rTpCA0wG1wUxglBSFdMMY0oTrKYvgf4fNgv/sXbfCVAdf+FnPBdKJR/7XbpTCwbCrvCbdPYnlWaUUYz4V2fPDA== +"@sinonjs/commons@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz" + integrity sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA== dependencies: type-detect "4.0.8" -"@sinonjs/fake-timers@^9.1.2": - version "9.1.2" - resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz" - integrity sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw== +"@sinonjs/fake-timers@^10.0.2": + version "10.3.0" + resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== dependencies: - "@sinonjs/commons" "^1.7.0" + "@sinonjs/commons" "^3.0.0" "@stdlib/array-base-filled@^0.0.x": version "0.0.2" @@ -2384,37 +2384,37 @@ integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== "@types/babel__core@^7.1.14": - version "7.1.20" - resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz" - integrity sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ== + version "7.20.2" + resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.2.tgz" + integrity sha512-pNpr1T1xLUc2l3xJKuPtsEky3ybxN3m4fJkknfIpTCTfIZCDW57oAg+EfCgIIp2rvCe0Wn++/FfodDS4YXxBwA== dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" "@types/babel__generator" "*" "@types/babel__template" "*" "@types/babel__traverse" "*" "@types/babel__generator@*": - version "7.6.4" - resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz" - integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== + version "7.6.5" + resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.5.tgz" + integrity sha512-h9yIuWbJKdOPLJTbmSpPzkF67e659PbQDba7ifWm5BJ8xTv+sDmS7rFmywkWOvXedGTivCdeGSIIX8WLcRTz8w== dependencies: "@babel/types" "^7.0.0" "@types/babel__template@*": - version "7.4.1" - resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz" - integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + version "7.4.2" + resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.2.tgz" + integrity sha512-/AVzPICMhMOMYoSx9MoKpGDKdBRsIXMNByh1PXSZoa+v6ZoLa8xxtsT/uLQ/NJm0XVAWl/BvId4MlDeXJaeIZQ== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" "@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": - version "7.18.2" - resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.2.tgz" - integrity sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg== + version "7.20.2" + resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.2.tgz" + integrity sha512-ojlGK1Hsfce93J0+kn3H5R73elidKUaZonirN33GSmgTUMpzI/MIFfSpF3haANe3G1bEBS9/9/QEqwTzwqFsKw== dependencies: - "@babel/types" "^7.3.0" + "@babel/types" "^7.20.7" "@types/eslint-scope@^3.7.3": version "3.7.4" @@ -2443,9 +2443,9 @@ integrity sha512-pYVNNJ+winC4aek+lZp93sIKxnXt5qMkuKmaqS3WGuTq0Bw1ZDYNBgzG5kkdtwcv+GmYJGo3yEg6z2cKKAiEdw== "@types/graceful-fs@^4.1.3": - version "4.1.5" - resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz" - integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== + version "4.1.7" + resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.7.tgz" + integrity sha512-MhzcwU8aUygZroVwL2jeYk6JisJrPl/oov/gsgGCue9mkgl9wjGbzReYQClxiUgFDnib9FuHqTndccKeZKxTRw== dependencies: "@types/node" "*" @@ -2503,10 +2503,10 @@ dependencies: undici-types "~5.26.4" -"@types/prettier@^2.1.5": - version "2.7.1" - resolved "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz" - integrity sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow== +"@types/object-hash@^1.3.0": + version "1.3.4" + resolved "https://registry.npmjs.org/@types/object-hash/-/object-hash-1.3.4.tgz" + integrity sha512-xFdpkAkikBgqBdG9vIlsqffDV8GpvnPEzs0IUtr1v3BEB97ijsFQ4RXVbUZwjFThhB4MDSTUfvmxUD5PGx0wXA== "@types/seedrandom@^3.0.6": version "3.0.6" @@ -2838,9 +2838,9 @@ ansi-styles@^5.0.0: integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== anymatch@^3.0.3: - version "3.1.2" - resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + version "3.1.3" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: normalize-path "^3.0.0" picomatch "^2.0.4" @@ -2888,15 +2888,15 @@ axios@^0.21.2: dependencies: follow-redirects "^1.14.0" -babel-jest@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-29.3.1.tgz" - integrity sha512-aard+xnMoxgjwV70t0L6wkW/3HQQtV+O0PEimxKgzNqCJnbYmroPojdP2tqKSOAt8QAKV/uSZU8851M7B5+fcA== +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== dependencies: - "@jest/transform" "^29.3.1" + "@jest/transform" "^29.7.0" "@types/babel__core" "^7.1.14" babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^29.2.0" + babel-preset-jest "^29.6.3" chalk "^4.0.0" graceful-fs "^4.2.9" slash "^3.0.0" @@ -2912,10 +2912,10 @@ babel-plugin-istanbul@^6.1.1: istanbul-lib-instrument "^5.0.4" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^29.2.0: - version "29.2.0" - resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.2.0.tgz" - integrity sha512-TnspP2WNiR3GLfCsUNHqeXw0RoQ2f9U5hQ5L3XFpwuO8htQmSrhh8qsB6vi5Yi8+kuynN1yjDjQsPfkebmB6ZA== +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== dependencies: "@babel/template" "^7.3.3" "@babel/types" "^7.3.3" @@ -2940,12 +2940,12 @@ babel-preset-current-node-syntax@^1.0.0: "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-top-level-await" "^7.8.3" -babel-preset-jest@^29.2.0: - version "29.2.0" - resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.2.0.tgz" - integrity sha512-z9JmMJppMxNv8N7fNRHvhMg9cvIkMxQBXgFkane3yKVEvEOP+kB50lk8DFRvF9PGqbyXxlmebKWhuDORO8RgdA== +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== dependencies: - babel-plugin-jest-hoist "^29.2.0" + babel-plugin-jest-hoist "^29.6.3" babel-preset-current-node-syntax "^1.0.0" balanced-match@^1.0.0: @@ -3118,10 +3118,10 @@ caniuse-lite@^1.0.30001400: resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz" integrity sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg== -case-anything@^2.1.13: - version "2.1.13" - resolved "https://registry.npmjs.org/case-anything/-/case-anything-2.1.13.tgz" - integrity sha512-zlOQ80VrQ2Ue+ymH5OuM/DlDq64mEm+B9UTdHULv5osUMD6HalNTblf2b1u/m6QecjsnOkBpqVZ+XPwIVsy7Ng== +case-anything@^2.1.10: + version "2.1.10" + resolved "https://registry.npmjs.org/case-anything/-/case-anything-2.1.10.tgz" + integrity sha512-JczJwVrCP0jPKh05McyVsuOg6AYosrB9XWZKbQzXeDAm2ClE/PJE/BcrrQrVyGYH7Jg8V/LDupmyL4kFlVsVFQ== chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.2: version "4.1.2" @@ -3156,9 +3156,9 @@ ci-info@^3.2.0: integrity sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw== cjs-module-lexer@^1.0.0: - version "1.2.2" - resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz" - integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== + version "1.2.3" + resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz" + integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== cliui@^7.0.2: version "7.0.4" @@ -3200,9 +3200,9 @@ co@^4.6.0: integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== collect-v8-coverage@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz" - integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== + version "1.0.2" + resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz" + integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== color-convert@^1.9.0: version "1.9.3" @@ -3260,7 +3260,7 @@ content-disposition@^0.5.2: dependencies: safe-buffer "5.2.1" -convert-source-map@^1.6.0, convert-source-map@^1.7.0: +convert-source-map@^1.7.0: version "1.9.0" resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz" integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== @@ -3296,6 +3296,19 @@ cosmjs-types@^0.5.2: long "^4.0.0" protobufjs "~6.11.2" +create-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz" + integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-config "^29.7.0" + jest-util "^29.7.0" + prompts "^2.0.1" + create-require@^1.1.0: version "1.1.1" resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" @@ -3310,6 +3323,11 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +dataloader@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/dataloader/-/dataloader-1.4.0.tgz" + integrity sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw== + debug@^2.6.9: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" @@ -3396,10 +3414,10 @@ decompress@^4.2.1: pify "^2.3.0" strip-dirs "^2.0.0" -dedent@^0.7.0: - version "0.7.0" - resolved "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz" - integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== +dedent@^1.0.0: + version "1.5.1" + resolved "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz" + integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== deep-is@^0.1.3: version "0.1.4" @@ -3407,9 +3425,9 @@ deep-is@^0.1.3: integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== deepmerge@^4.2.2: - version "4.2.2" - resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz" - integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + version "4.3.1" + resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== define-properties@^1.1.3: version "1.1.4" @@ -3429,10 +3447,10 @@ detect-newline@^3.0.0: resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -diff-sequences@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.3.1.tgz" - integrity sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ== +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== diff@^4.0.1: version "4.0.2" @@ -3471,9 +3489,9 @@ download@^8.0.0: pify "^4.0.1" dprint-node@^1.0.7: - version "1.0.8" - resolved "https://registry.npmjs.org/dprint-node/-/dprint-node-1.0.8.tgz" - integrity sha512-iVKnUtYfGrYcW1ZAlfR/F59cUVL8QIhWoBJoSjkkdua/dkWIgjZfiLMeTjiB06X0ZLkQ0M2C1VbUj/CxkIf1zg== + version "1.0.7" + resolved "https://registry.npmjs.org/dprint-node/-/dprint-node-1.0.7.tgz" + integrity sha512-NTZOW9A7ipb0n7z7nC3wftvsbceircwVHSgzobJsEQa+7RnOMbhrfX5IflA6CtC4GA63DSAiHYXa4JKEy9F7cA== dependencies: detect-libc "^1.0.3" @@ -3725,16 +3743,16 @@ exit@^0.1.2: resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz" integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== -expect@^29.0.0, expect@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/expect/-/expect-29.3.1.tgz" - integrity sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA== +expect@^29.0.0, expect@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== dependencies: - "@jest/expect-utils" "^29.3.1" - jest-get-type "^29.2.0" - jest-matcher-utils "^29.3.1" - jest-message-util "^29.3.1" - jest-util "^29.3.1" + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" ext-list@^2.0.0: version "2.2.2" @@ -3914,9 +3932,9 @@ fs.realpath@^1.0.0: integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== fsevents@^2.3.2: - version "2.3.2" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + version "2.3.3" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== function-bind@^1.1.1: version "1.1.1" @@ -4268,13 +4286,6 @@ is-arrayish@^0.2.1: resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== -is-core-module@^2.13.0: - version "2.13.0" - resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz" - integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== - dependencies: - has "^1.0.3" - is-core-module@^2.9.0: version "2.10.0" resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz" @@ -4376,7 +4387,7 @@ istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz" integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== -istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: +istanbul-lib-instrument@^5.0.4: version "5.2.1" resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz" integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== @@ -4387,13 +4398,24 @@ istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: istanbul-lib-coverage "^3.2.0" semver "^6.3.0" +istanbul-lib-instrument@^6.0.0: + version "6.0.1" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz" + integrity sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + istanbul-lib-report@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" - integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + version "3.0.1" + resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== dependencies: istanbul-lib-coverage "^3.0.0" - make-dir "^3.0.0" + make-dir "^4.0.0" supports-color "^7.1.0" istanbul-lib-source-maps@^4.0.0: @@ -4406,9 +4428,9 @@ istanbul-lib-source-maps@^4.0.0: source-map "^0.6.1" istanbul-reports@^3.1.3: - version "3.1.5" - resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz" - integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== + version "3.1.6" + resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz" + integrity sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" @@ -4421,345 +4443,342 @@ isurl@^1.0.0-alpha5: has-to-string-tag-x "^1.2.0" is-object "^1.0.1" -jest-changed-files@^29.2.0: - version "29.2.0" - resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.2.0.tgz" - integrity sha512-qPVmLLyBmvF5HJrY7krDisx6Voi8DmlV3GZYX0aFNbaQsZeoz1hfxcCMbqDGuQCxU1dJy9eYc2xscE8QrCCYaA== +jest-changed-files@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz" + integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== dependencies: execa "^5.0.0" + jest-util "^29.7.0" p-limit "^3.1.0" -jest-circus@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/jest-circus/-/jest-circus-29.3.1.tgz" - integrity sha512-wpr26sEvwb3qQQbdlmei+gzp6yoSSoSL6GsLPxnuayZSMrSd5Ka7IjAvatpIernBvT2+Ic6RLTg+jSebScmasg== +jest-circus@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz" + integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== dependencies: - "@jest/environment" "^29.3.1" - "@jest/expect" "^29.3.1" - "@jest/test-result" "^29.3.1" - "@jest/types" "^29.3.1" + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" co "^4.6.0" - dedent "^0.7.0" + dedent "^1.0.0" is-generator-fn "^2.0.0" - jest-each "^29.3.1" - jest-matcher-utils "^29.3.1" - jest-message-util "^29.3.1" - jest-runtime "^29.3.1" - jest-snapshot "^29.3.1" - jest-util "^29.3.1" + jest-each "^29.7.0" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" p-limit "^3.1.0" - pretty-format "^29.3.1" + pretty-format "^29.7.0" + pure-rand "^6.0.0" slash "^3.0.0" stack-utils "^2.0.3" -jest-cli@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-29.3.1.tgz" - integrity sha512-TO/ewvwyvPOiBBuWZ0gm04z3WWP8TIK8acgPzE4IxgsLKQgb377NYGrQLc3Wl/7ndWzIH2CDNNsUjGxwLL43VQ== +jest-cli@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz" + integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== dependencies: - "@jest/core" "^29.3.1" - "@jest/test-result" "^29.3.1" - "@jest/types" "^29.3.1" + "@jest/core" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" chalk "^4.0.0" + create-jest "^29.7.0" exit "^0.1.2" - graceful-fs "^4.2.9" import-local "^3.0.2" - jest-config "^29.3.1" - jest-util "^29.3.1" - jest-validate "^29.3.1" - prompts "^2.0.1" + jest-config "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" yargs "^17.3.1" -jest-config@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/jest-config/-/jest-config-29.3.1.tgz" - integrity sha512-y0tFHdj2WnTEhxmGUK1T7fgLen7YK4RtfvpLFBXfQkh2eMJAQq24Vx9472lvn5wg0MAO6B+iPfJfzdR9hJYalg== +jest-config@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz" + integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== dependencies: "@babel/core" "^7.11.6" - "@jest/test-sequencer" "^29.3.1" - "@jest/types" "^29.3.1" - babel-jest "^29.3.1" + "@jest/test-sequencer" "^29.7.0" + "@jest/types" "^29.6.3" + babel-jest "^29.7.0" chalk "^4.0.0" ci-info "^3.2.0" deepmerge "^4.2.2" glob "^7.1.3" graceful-fs "^4.2.9" - jest-circus "^29.3.1" - jest-environment-node "^29.3.1" - jest-get-type "^29.2.0" - jest-regex-util "^29.2.0" - jest-resolve "^29.3.1" - jest-runner "^29.3.1" - jest-util "^29.3.1" - jest-validate "^29.3.1" + jest-circus "^29.7.0" + jest-environment-node "^29.7.0" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-runner "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" micromatch "^4.0.4" parse-json "^5.2.0" - pretty-format "^29.3.1" + pretty-format "^29.7.0" slash "^3.0.0" strip-json-comments "^3.1.1" -jest-diff@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-29.3.1.tgz" - integrity sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw== +jest-diff@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== dependencies: chalk "^4.0.0" - diff-sequences "^29.3.1" - jest-get-type "^29.2.0" - pretty-format "^29.3.1" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" -jest-docblock@^29.2.0: - version "29.2.0" - resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.2.0.tgz" - integrity sha512-bkxUsxTgWQGbXV5IENmfiIuqZhJcyvF7tU4zJ/7ioTutdz4ToB5Yx6JOFBpgI+TphRY4lhOyCWGNH/QFQh5T6A== +jest-docblock@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== dependencies: detect-newline "^3.0.0" -jest-each@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/jest-each/-/jest-each-29.3.1.tgz" - integrity sha512-qrZH7PmFB9rEzCSl00BWjZYuS1BSOH8lLuC0azQE9lQrAx3PWGKHTDudQiOSwIy5dGAJh7KA0ScYlCP7JxvFYA== +jest-each@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz" + integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== dependencies: - "@jest/types" "^29.3.1" + "@jest/types" "^29.6.3" chalk "^4.0.0" - jest-get-type "^29.2.0" - jest-util "^29.3.1" - pretty-format "^29.3.1" - -jest-environment-node@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.3.1.tgz" - integrity sha512-xm2THL18Xf5sIHoU7OThBPtuH6Lerd+Y1NLYiZJlkE3hbE+7N7r8uvHIl/FkZ5ymKXJe/11SQuf3fv4v6rUMag== - dependencies: - "@jest/environment" "^29.3.1" - "@jest/fake-timers" "^29.3.1" - "@jest/types" "^29.3.1" + jest-get-type "^29.6.3" + jest-util "^29.7.0" + pretty-format "^29.7.0" + +jest-environment-node@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz" + integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" - jest-mock "^29.3.1" - jest-util "^29.3.1" + jest-mock "^29.7.0" + jest-util "^29.7.0" -jest-get-type@^29.2.0: - version "29.2.0" - resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.2.0.tgz" - integrity sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA== +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== -jest-haste-map@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.3.1.tgz" - integrity sha512-/FFtvoG1xjbbPXQLFef+WSU4yrc0fc0Dds6aRPBojUid7qlPqZvxdUBA03HW0fnVHXVCnCdkuoghYItKNzc/0A== +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== dependencies: - "@jest/types" "^29.3.1" + "@jest/types" "^29.6.3" "@types/graceful-fs" "^4.1.3" "@types/node" "*" anymatch "^3.0.3" fb-watchman "^2.0.0" graceful-fs "^4.2.9" - jest-regex-util "^29.2.0" - jest-util "^29.3.1" - jest-worker "^29.3.1" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" micromatch "^4.0.4" walker "^1.0.8" optionalDependencies: fsevents "^2.3.2" -jest-leak-detector@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.3.1.tgz" - integrity sha512-3DA/VVXj4zFOPagGkuqHnSQf1GZBmmlagpguxEERO6Pla2g84Q1MaVIB3YMxgUaFIaYag8ZnTyQgiZ35YEqAQA== +jest-leak-detector@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz" + integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== dependencies: - jest-get-type "^29.2.0" - pretty-format "^29.3.1" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" -jest-matcher-utils@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.3.1.tgz" - integrity sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ== +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== dependencies: chalk "^4.0.0" - jest-diff "^29.3.1" - jest-get-type "^29.2.0" - pretty-format "^29.3.1" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" -jest-message-util@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz" - integrity sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA== +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== dependencies: "@babel/code-frame" "^7.12.13" - "@jest/types" "^29.3.1" + "@jest/types" "^29.6.3" "@types/stack-utils" "^2.0.0" chalk "^4.0.0" graceful-fs "^4.2.9" micromatch "^4.0.4" - pretty-format "^29.3.1" + pretty-format "^29.7.0" slash "^3.0.0" stack-utils "^2.0.3" -jest-mock@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-29.3.1.tgz" - integrity sha512-H8/qFDtDVMFvFP4X8NuOT3XRDzOUTz+FeACjufHzsOIBAxivLqkB1PoLCaJx9iPPQ8dZThHPp/G3WRWyMgA3JA== +jest-mock@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz" + integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== dependencies: - "@jest/types" "^29.3.1" + "@jest/types" "^29.6.3" "@types/node" "*" - jest-util "^29.3.1" + jest-util "^29.7.0" jest-pnp-resolver@^1.2.2: - version "1.2.2" - resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz" - integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== + version "1.2.3" + resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== -jest-regex-util@^29.2.0: - version "29.2.0" - resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.2.0.tgz" - integrity sha512-6yXn0kg2JXzH30cr2NlThF+70iuO/3irbaB4mh5WyqNIvLLP+B6sFdluO1/1RJmslyh/f9osnefECflHvTbwVA== +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== -jest-resolve-dependencies@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.3.1.tgz" - integrity sha512-Vk0cYq0byRw2WluNmNWGqPeRnZ3p3hHmjJMp2dyyZeYIfiBskwq4rpiuGFR6QGAdbj58WC7HN4hQHjf2mpvrLA== +jest-resolve-dependencies@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz" + integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== dependencies: - jest-regex-util "^29.2.0" - jest-snapshot "^29.3.1" + jest-regex-util "^29.6.3" + jest-snapshot "^29.7.0" -jest-resolve@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.3.1.tgz" - integrity sha512-amXJgH/Ng712w3Uz5gqzFBBjxV8WFLSmNjoreBGMqxgCz5cH7swmBZzgBaCIOsvb0NbpJ0vgaSFdJqMdT+rADw== +jest-resolve@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz" + integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== dependencies: chalk "^4.0.0" graceful-fs "^4.2.9" - jest-haste-map "^29.3.1" + jest-haste-map "^29.7.0" jest-pnp-resolver "^1.2.2" - jest-util "^29.3.1" - jest-validate "^29.3.1" + jest-util "^29.7.0" + jest-validate "^29.7.0" resolve "^1.20.0" - resolve.exports "^1.1.0" + resolve.exports "^2.0.0" slash "^3.0.0" -jest-runner@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-29.3.1.tgz" - integrity sha512-oFvcwRNrKMtE6u9+AQPMATxFcTySyKfLhvso7Sdk/rNpbhg4g2GAGCopiInk1OP4q6gz3n6MajW4+fnHWlU3bA== +jest-runner@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz" + integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== dependencies: - "@jest/console" "^29.3.1" - "@jest/environment" "^29.3.1" - "@jest/test-result" "^29.3.1" - "@jest/transform" "^29.3.1" - "@jest/types" "^29.3.1" + "@jest/console" "^29.7.0" + "@jest/environment" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" emittery "^0.13.1" graceful-fs "^4.2.9" - jest-docblock "^29.2.0" - jest-environment-node "^29.3.1" - jest-haste-map "^29.3.1" - jest-leak-detector "^29.3.1" - jest-message-util "^29.3.1" - jest-resolve "^29.3.1" - jest-runtime "^29.3.1" - jest-util "^29.3.1" - jest-watcher "^29.3.1" - jest-worker "^29.3.1" + jest-docblock "^29.7.0" + jest-environment-node "^29.7.0" + jest-haste-map "^29.7.0" + jest-leak-detector "^29.7.0" + jest-message-util "^29.7.0" + jest-resolve "^29.7.0" + jest-runtime "^29.7.0" + jest-util "^29.7.0" + jest-watcher "^29.7.0" + jest-worker "^29.7.0" p-limit "^3.1.0" source-map-support "0.5.13" -jest-runtime@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.3.1.tgz" - integrity sha512-jLzkIxIqXwBEOZx7wx9OO9sxoZmgT2NhmQKzHQm1xwR1kNW/dn0OjxR424VwHHf1SPN6Qwlb5pp1oGCeFTQ62A== - dependencies: - "@jest/environment" "^29.3.1" - "@jest/fake-timers" "^29.3.1" - "@jest/globals" "^29.3.1" - "@jest/source-map" "^29.2.0" - "@jest/test-result" "^29.3.1" - "@jest/transform" "^29.3.1" - "@jest/types" "^29.3.1" +jest-runtime@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz" + integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/globals" "^29.7.0" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" cjs-module-lexer "^1.0.0" collect-v8-coverage "^1.0.0" glob "^7.1.3" graceful-fs "^4.2.9" - jest-haste-map "^29.3.1" - jest-message-util "^29.3.1" - jest-mock "^29.3.1" - jest-regex-util "^29.2.0" - jest-resolve "^29.3.1" - jest-snapshot "^29.3.1" - jest-util "^29.3.1" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" slash "^3.0.0" strip-bom "^4.0.0" -jest-snapshot@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.3.1.tgz" - integrity sha512-+3JOc+s28upYLI2OJM4PWRGK9AgpsMs/ekNryUV0yMBClT9B1DF2u2qay8YxcQd338PPYSFNb0lsar1B49sLDA== +jest-snapshot@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz" + integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== dependencies: "@babel/core" "^7.11.6" "@babel/generator" "^7.7.2" "@babel/plugin-syntax-jsx" "^7.7.2" "@babel/plugin-syntax-typescript" "^7.7.2" - "@babel/traverse" "^7.7.2" "@babel/types" "^7.3.3" - "@jest/expect-utils" "^29.3.1" - "@jest/transform" "^29.3.1" - "@jest/types" "^29.3.1" - "@types/babel__traverse" "^7.0.6" - "@types/prettier" "^2.1.5" + "@jest/expect-utils" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" babel-preset-current-node-syntax "^1.0.0" chalk "^4.0.0" - expect "^29.3.1" + expect "^29.7.0" graceful-fs "^4.2.9" - jest-diff "^29.3.1" - jest-get-type "^29.2.0" - jest-haste-map "^29.3.1" - jest-matcher-utils "^29.3.1" - jest-message-util "^29.3.1" - jest-util "^29.3.1" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" natural-compare "^1.4.0" - pretty-format "^29.3.1" - semver "^7.3.5" + pretty-format "^29.7.0" + semver "^7.5.3" -jest-util@^29.0.0, jest-util@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz" - integrity sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ== +jest-util@^29.0.0, jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== dependencies: - "@jest/types" "^29.3.1" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" ci-info "^3.2.0" graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-validate@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-29.3.1.tgz" - integrity sha512-N9Lr3oYR2Mpzuelp1F8negJR3YE+L1ebk1rYA5qYo9TTY3f9OWdptLoNSPP9itOCBIRBqjt/S5XHlzYglLN67g== +jest-validate@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz" + integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== dependencies: - "@jest/types" "^29.3.1" + "@jest/types" "^29.6.3" camelcase "^6.2.0" chalk "^4.0.0" - jest-get-type "^29.2.0" + jest-get-type "^29.6.3" leven "^3.1.0" - pretty-format "^29.3.1" + pretty-format "^29.7.0" -jest-watcher@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.3.1.tgz" - integrity sha512-RspXG2BQFDsZSRKGCT/NiNa8RkQ1iKAjrO0//soTMWx/QUt+OcxMqMSBxz23PYGqUuWm2+m2mNNsmj0eIoOaFg== +jest-watcher@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz" + integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== dependencies: - "@jest/test-result" "^29.3.1" - "@jest/types" "^29.3.1" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" emittery "^0.13.1" - jest-util "^29.3.1" + jest-util "^29.7.0" string-length "^4.0.1" jest-worker@^27.4.5: @@ -4771,25 +4790,25 @@ jest-worker@^27.4.5: merge-stream "^2.0.0" supports-color "^8.0.0" -jest-worker@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-29.3.1.tgz" - integrity sha512-lY4AnnmsEWeiXirAIA0c9SDPbuCBq8IYuDVL8PMm0MZ2PEs2yPvRA/J64QBXuZp7CYKrDM/rmNrc9/i3KJQncw== +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== dependencies: "@types/node" "*" - jest-util "^29.3.1" + jest-util "^29.7.0" merge-stream "^2.0.0" supports-color "^8.0.0" jest@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/jest/-/jest-29.3.1.tgz" - integrity sha512-6iWfL5DTT0Np6UYs/y5Niu7WIfNv/wRTtN5RSXt2DIEft3dx3zPuw/3WJQBCJfmEzvDiEKwoqMbGD9n49+qLSA== + version "29.7.0" + resolved "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== dependencies: - "@jest/core" "^29.3.1" - "@jest/types" "^29.3.1" + "@jest/core" "^29.7.0" + "@jest/types" "^29.6.3" import-local "^3.0.2" - jest-cli "^29.3.1" + jest-cli "^29.7.0" js-sdsl@^4.1.4: version "4.2.0" @@ -4942,10 +4961,10 @@ long@^4.0.0: resolved "https://registry.npmjs.org/long/-/long-4.0.0.tgz" integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== -long@^5.0.0, long@^5.2.1, long@^5.2.3: - version "5.2.3" - resolved "https://registry.npmjs.org/long/-/long-5.2.3.tgz" - integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== +long@^5.0.0, long@^5.2.1: + version "5.2.1" + resolved "https://registry.npmjs.org/long/-/long-5.2.1.tgz" + integrity sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A== lowercase-keys@1.0.0: version "1.0.0" @@ -4984,12 +5003,12 @@ make-dir@^2.1.0: pify "^4.0.1" semver "^5.6.0" -make-dir@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== dependencies: - semver "^6.0.0" + semver "^7.5.3" make-error@1.x, make-error@^1.1.1: version "1.3.6" @@ -5065,12 +5084,7 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" -minimist@^1.2.0: - version "1.2.8" - resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== - -minimist@^1.2.6: +minimist@^1.2.0, minimist@^1.2.6: version "1.2.7" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz" integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== @@ -5148,6 +5162,11 @@ object-assign@^4.0.1, object-assign@^4.1.0: resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== +object-hash@^1.3.1: + version "1.3.1" + resolved "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz" + integrity sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA== + object-keys@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" @@ -5373,12 +5392,12 @@ prettier@^2.8.0: resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.0.tgz" integrity sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA== -pretty-format@^29.0.0, pretty-format@^29.3.1: - version "29.3.1" - resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz" - integrity sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg== +pretty-format@^29.0.0, pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== dependencies: - "@jest/schemas" "^29.0.0" + "@jest/schemas" "^29.6.3" ansi-styles "^5.0.0" react-is "^18.0.0" @@ -5395,7 +5414,7 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -protobufjs@^6.8.8, protobufjs@~6.11.2: +protobufjs@^6.11.3, protobufjs@^6.8.8, protobufjs@~6.11.2: version "6.11.3" resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz" integrity sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg== @@ -5414,10 +5433,10 @@ protobufjs@^6.8.8, protobufjs@~6.11.2: "@types/node" ">=13.7.0" long "^4.0.0" -protobufjs@^7.0.0, protobufjs@^7.1.2, protobufjs@^7.2.4: - version "7.2.5" - resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz" - integrity sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A== +protobufjs@^7.0.0, protobufjs@^7.1.2: + version "7.1.2" + resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.2.tgz" + integrity sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ== dependencies: "@protobufjs/aspromise" "^1.1.2" "@protobufjs/base64" "^1.1.2" @@ -5472,6 +5491,11 @@ punycode@^2.1.0: resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +pure-rand@^6.0.0: + version "6.0.4" + resolved "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz" + integrity sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA== + qs@^6.4.0: version "6.5.3" resolved "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz" @@ -5576,21 +5600,12 @@ resolve-from@^5.0.0: resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== -resolve.exports@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz" - integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== - -resolve@^1.1.7: - version "1.22.4" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz" - integrity sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg== - dependencies: - is-core-module "^2.13.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" +resolve.exports@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz" + integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== -resolve@^1.20.0, resolve@^1.9.0: +resolve@^1.1.7, resolve@^1.20.0, resolve@^1.9.0: version "1.22.1" resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz" integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== @@ -5681,10 +5696,10 @@ seek-bzip@^1.0.5: dependencies: commander "^2.8.1" -semver@7.x, semver@^7.3.5, semver@^7.3.7: - version "7.3.8" - resolved "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz" - integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== +semver@7.x, semver@^7.3.7, semver@^7.5.3, semver@^7.5.4: + version "7.5.4" + resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== dependencies: lru-cache "^6.0.0" @@ -5693,7 +5708,7 @@ semver@^5.6.0: resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^6.0.0, semver@^6.3.0: +semver@^6.3.0: version "6.3.0" resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== @@ -6029,30 +6044,33 @@ ts-node@^10.9.1: v8-compile-cache-lib "^3.0.1" yn "3.1.1" -ts-poet@^6.5.0: - version "6.6.0" - resolved "https://registry.npmjs.org/ts-poet/-/ts-poet-6.6.0.tgz" - integrity sha512-4vEH/wkhcjRPFOdBwIh9ItO6jOoumVLRF4aABDX5JSNEubSqwOulihxQPqai+OkuygJm3WYMInxXQX4QwVNMuw== +ts-poet@^6.4.1: + version "6.4.1" + resolved "https://registry.npmjs.org/ts-poet/-/ts-poet-6.4.1.tgz" + integrity sha512-AjZEs4h2w4sDfwpHMxQKHrTlNh2wRbM5NRXmLz0RiH+yPGtSQFbe9hBpNocU8vqVNgfh0BIOiXR80xDz3kKxUQ== dependencies: dprint-node "^1.0.7" -ts-proto-descriptors@1.15.0: - version "1.15.0" - resolved "https://registry.npmjs.org/ts-proto-descriptors/-/ts-proto-descriptors-1.15.0.tgz" - integrity sha512-TYyJ7+H+7Jsqawdv+mfsEpZPTIj9siDHS6EMCzG/z3b/PZiphsX+mWtqFfFVe5/N0Th6V3elK9lQqjnrgTOfrg== +ts-proto-descriptors@1.8.0: + version "1.8.0" + resolved "https://registry.npmjs.org/ts-proto-descriptors/-/ts-proto-descriptors-1.8.0.tgz" + integrity sha512-iV20plcI8+GRkeZIAygxOOH0p2xpOsKfw9kI1W20NCwawi1/4bG/YRd9rQY9XSJP+lD9j7XbSy3tFFuikfsljw== dependencies: - long "^5.2.3" - protobufjs "^7.2.4" + long "^4.0.0" + protobufjs "^6.8.8" ts-proto@^1.145.0: - version "1.163.0" - resolved "https://registry.npmjs.org/ts-proto/-/ts-proto-1.163.0.tgz" - integrity sha512-jpC4oA86NkN015R2YHGj9bhOJEYOuop4JddmADixRxBcBBcfCgkh7mhxA10BWrmk3/oyczI3T//UNK4x3P9/Sw== - dependencies: - case-anything "^2.1.13" - protobufjs "^7.2.4" - ts-poet "^6.5.0" - ts-proto-descriptors "1.15.0" + version "1.145.0" + resolved "https://registry.npmjs.org/ts-proto/-/ts-proto-1.145.0.tgz" + integrity sha512-th0T5BN8Ytl//6L5ea5nbxtlcGQaqPP9MVm0lxT+t1Mn3Np0g/GMR1VUiOwZhtAo5N7xfuaX4AppWELR5rCF7g== + dependencies: + "@types/object-hash" "^1.3.0" + case-anything "^2.1.10" + dataloader "^1.4.0" + object-hash "^1.3.1" + protobufjs "^6.11.3" + ts-poet "^6.4.1" + ts-proto-descriptors "1.8.0" ts-protoc-gen@^0.15.0: version "0.15.0" @@ -6168,13 +6186,13 @@ v8-compile-cache-lib@^3.0.1: integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== v8-to-istanbul@^9.0.1: - version "9.0.1" - resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz" - integrity sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w== + version "9.1.3" + resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz" + integrity sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg== dependencies: "@jridgewell/trace-mapping" "^0.3.12" "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" + convert-source-map "^2.0.0" walker@^1.0.8: version "1.0.8" @@ -6290,7 +6308,7 @@ wrappy@1: resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -write-file-atomic@^4.0.1: +write-file-atomic@^4.0.2: version "4.0.2" resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz" integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== @@ -6350,9 +6368,9 @@ yargs@^16.2.0: yargs-parser "^20.2.2" yargs@^17.3.1: - version "17.6.2" - resolved "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz" - integrity sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw== + version "17.7.2" + resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== dependencies: cliui "^8.0.1" escalade "^3.1.1" diff --git a/go.mod b/go.mod index 1f300f6433..fc2626855b 100644 --- a/go.mod +++ b/go.mod @@ -42,6 +42,7 @@ require ( github.com/tidwall/sjson v1.2.5 gonum.org/v1/gonum v0.13.0 google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e + gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) require ( @@ -104,7 +105,6 @@ require ( google.golang.org/api v0.126.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e // indirect - gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect pgregory.net/rapid v0.5.5 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index 59d33ef286..7dc122f7e5 100644 --- a/go.sum +++ b/go.sum @@ -819,8 +819,6 @@ github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+ github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jhump/gopoet v0.1.0/go.mod h1:me9yfT6IJSlOL3FCfrg+L6yzUEZ+5jW6WHt4Sk+UPUI= -github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7UvLHRQ= github.com/jhump/protoreflect v1.10.1/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= @@ -842,7 +840,6 @@ github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= @@ -963,7 +960,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= diff --git a/protocol/lavasession/common.go b/protocol/lavasession/common.go index 349f0cfa94..a76526441b 100644 --- a/protocol/lavasession/common.go +++ b/protocol/lavasession/common.go @@ -10,9 +10,13 @@ import ( "math/big" "time" + "golang.org/x/exp/slices" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/gogo/status" "github.com/lavanet/lava/utils" + "github.com/lavanet/lava/x/pairing/keeper/scores" + planstypes "github.com/lavanet/lava/x/plans/types" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" @@ -139,3 +143,18 @@ func GetAllProviders(allAddresses []string, ignoredProviders map[string]struct{} } return returnedProviders } + +func SortByGeolocations(pairingEndpoints []*Endpoint, currentGeo planstypes.Geolocation) { + latencyToGeo := func(a, b planstypes.Geolocation) uint64 { + _, latency := scores.CalcGeoLatency(a, []planstypes.Geolocation{b}) + return latency + } + + // sort the endpoints by geolocation relevance: + lessFunc := func(a *Endpoint, b *Endpoint) bool { + latencyA := int(latencyToGeo(a.Geolocation, currentGeo)) + latencyB := int(latencyToGeo(b.Geolocation, currentGeo)) + return latencyA < latencyB + } + slices.SortStableFunc(pairingEndpoints, lessFunc) +} diff --git a/protocol/lavasession/common_test.go b/protocol/lavasession/common_test.go new file mode 100644 index 0000000000..bf6e09898a --- /dev/null +++ b/protocol/lavasession/common_test.go @@ -0,0 +1,113 @@ +package lavasession + +import ( + "strings" + "testing" + + planstypes "github.com/lavanet/lava/x/plans/types" + "github.com/stretchr/testify/require" +) + +type printGeos []*Endpoint + +func (pg printGeos) String() string { + stringsArr := []string{} + for _, endp := range pg { + stringsArr = append(stringsArr, endp.Geolocation.String()) + } + return strings.Join(stringsArr, ",") +} + +func TestGeoOrdering(t *testing.T) { + pairingEndpoints := []*Endpoint{ + { + NetworkAddress: "", + Enabled: true, + Geolocation: planstypes.Geolocation_EU, + }, + { + NetworkAddress: "", + Enabled: true, + Geolocation: planstypes.Geolocation_AF, + }, + { + NetworkAddress: "", + Enabled: true, + Geolocation: planstypes.Geolocation_AS, + }, + { + NetworkAddress: "", + Enabled: true, + Geolocation: planstypes.Geolocation_AU, + }, + { + NetworkAddress: "", + Enabled: true, + Geolocation: planstypes.Geolocation_USE, + }, + { + NetworkAddress: "", + Enabled: true, + Geolocation: planstypes.Geolocation_USC, + }, + { + NetworkAddress: "", + Enabled: true, + Geolocation: planstypes.Geolocation_USW, + }, + } + + playbook := []struct { + name string + currentGeo planstypes.Geolocation + expectedOrder []planstypes.Geolocation + }{ + { + name: "USC", + currentGeo: planstypes.Geolocation_USC, + expectedOrder: []planstypes.Geolocation{ + planstypes.Geolocation_USC, + planstypes.Geolocation_USE, + planstypes.Geolocation_USW, + planstypes.Geolocation_EU, + planstypes.Geolocation_AF, + planstypes.Geolocation_AS, + planstypes.Geolocation_AU, + }, + }, + { + name: "USW", + currentGeo: planstypes.Geolocation_USW, + expectedOrder: []planstypes.Geolocation{ + planstypes.Geolocation_USW, + planstypes.Geolocation_USC, + planstypes.Geolocation_USE, + planstypes.Geolocation_AU, + planstypes.Geolocation_EU, + planstypes.Geolocation_AF, + planstypes.Geolocation_AS, + }, + }, + { + name: "EU", + currentGeo: planstypes.Geolocation_EU, + expectedOrder: []planstypes.Geolocation{ + planstypes.Geolocation_EU, + planstypes.Geolocation_USE, + planstypes.Geolocation_AF, + planstypes.Geolocation_AS, + planstypes.Geolocation_USC, + }, + }, + } + + for _, play := range playbook { + t.Run(play.name, func(t *testing.T) { + SortByGeolocations(pairingEndpoints, play.currentGeo) + printme := printGeos(pairingEndpoints) + for idx := range play.expectedOrder { + require.Equal(t, play.expectedOrder[idx].String(), pairingEndpoints[idx].Geolocation.String(), "different order in index %d %s current Geo: %s", idx, printme, play.currentGeo) + } + }) + } +} diff --git a/protocol/lavasession/consumer_session_manager.go b/protocol/lavasession/consumer_session_manager.go index f987f23dbc..e001faf6de 100644 --- a/protocol/lavasession/consumer_session_manager.go +++ b/protocol/lavasession/consumer_session_manager.go @@ -638,6 +638,9 @@ func (csm *ConsumerSessionManager) verifyLock(consumerSession *SingleConsumerSes if consumerSession.lock.TryLock() { // verify. // if we managed to lock throw an error for misuse. defer consumerSession.lock.Unlock() + // if failed to lock we should block session as it seems like a very rare case. + consumerSession.BlockListed = true // block this session from future usages + utils.LavaFormatError("Verify Lock failed on session Failure, blocking session", nil, utils.LogAttr("consumerSession", consumerSession)) return LockMisUseDetectedError } return nil diff --git a/protocol/lavasession/consumer_types.go b/protocol/lavasession/consumer_types.go index b26b5cf62b..484650244e 100644 --- a/protocol/lavasession/consumer_types.go +++ b/protocol/lavasession/consumer_types.go @@ -13,6 +13,7 @@ import ( "github.com/lavanet/lava/utils" "github.com/lavanet/lava/utils/rand" pairingtypes "github.com/lavanet/lava/x/pairing/types" + planstypes "github.com/lavanet/lava/x/plans/types" "google.golang.org/grpc" "google.golang.org/grpc/connectivity" ) @@ -83,6 +84,7 @@ type Endpoint struct { ConnectionRefusals uint64 Addons map[string]struct{} Extensions map[string]struct{} + Geolocation planstypes.Geolocation } type SessionWithProvider struct { diff --git a/protocol/rpcprovider/rpcprovider_server.go b/protocol/rpcprovider/rpcprovider_server.go index 61511b93c3..00042add6a 100644 --- a/protocol/rpcprovider/rpcprovider_server.go +++ b/protocol/rpcprovider/rpcprovider_server.go @@ -259,7 +259,15 @@ func (rpcps *RPCProviderServer) ValidateRequest(chainMessage chainlib.ChainMessa // if after UpdateLatestBlockInMessage it's not aligned we have a problem reqBlock, _ = chainMessage.RequestedBlock() if reqBlock != request.RelayData.RequestBlock { - return utils.LavaFormatError("requested block mismatch between consumer and provider", nil, utils.Attribute{Key: "provider_parsed_block_pre_update", Value: providerRequestedBlockPreUpdate}, utils.Attribute{Key: "provider_requested_block", Value: reqBlock}, utils.Attribute{Key: "consumer_requested_block", Value: request.RelayData.RequestBlock}, utils.Attribute{Key: "GUID", Value: ctx}, utils.Attribute{Key: "metadata", Value: request.RelayData.Metadata}) + utils.LavaFormatDebug("requested block mismatch between consumer and provider", + utils.LogAttr("request data", request.RelayData.Data), + utils.LogAttr("request path", request.RelayData.ApiUrl), + utils.LogAttr("method", chainMessage.GetApi().Name), + utils.Attribute{Key: "provider_parsed_block_pre_update", Value: providerRequestedBlockPreUpdate}, + utils.Attribute{Key: "provider_requested_block", Value: reqBlock}, + utils.Attribute{Key: "consumer_requested_block", Value: request.RelayData.RequestBlock}, + utils.Attribute{Key: "GUID", Value: ctx}) + return utils.LavaFormatError("requested block mismatch between consumer and provider", nil, utils.LogAttr("method", chainMessage.GetApi().Name), utils.Attribute{Key: "provider_parsed_block_pre_update", Value: providerRequestedBlockPreUpdate}, utils.Attribute{Key: "provider_requested_block", Value: reqBlock}, utils.Attribute{Key: "consumer_requested_block", Value: request.RelayData.RequestBlock}, utils.Attribute{Key: "GUID", Value: ctx}, utils.Attribute{Key: "metadata", Value: request.RelayData.Metadata}) } } return nil diff --git a/protocol/statetracker/pairing_updater.go b/protocol/statetracker/pairing_updater.go index 628c81107b..e53a01bc4c 100644 --- a/protocol/statetracker/pairing_updater.go +++ b/protocol/statetracker/pairing_updater.go @@ -6,6 +6,7 @@ import ( "github.com/lavanet/lava/protocol/lavasession" "github.com/lavanet/lava/utils" epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" + planstypes "github.com/lavanet/lava/x/plans/types" "golang.org/x/net/context" ) @@ -117,7 +118,7 @@ func (pu *PairingUpdater) Update(latestBlock int64) { } func (pu *PairingUpdater) updateConsummerSessionManager(ctx context.Context, pairingList []epochstoragetypes.StakeEntry, consumerSessionManager *lavasession.ConsumerSessionManager, epoch uint64) (err error) { - pairingListForThisCSM, err := pu.filterPairingListByEndpoint(ctx, pairingList, consumerSessionManager.RPCEndpoint(), epoch) + pairingListForThisCSM, err := pu.filterPairingListByEndpoint(ctx, planstypes.Geolocation(consumerSessionManager.RPCEndpoint().Geolocation), pairingList, consumerSessionManager.RPCEndpoint(), epoch) if err != nil { return err } @@ -125,7 +126,7 @@ func (pu *PairingUpdater) updateConsummerSessionManager(ctx context.Context, pai return } -func (pu *PairingUpdater) filterPairingListByEndpoint(ctx context.Context, pairingList []epochstoragetypes.StakeEntry, rpcEndpoint lavasession.RPCEndpoint, epoch uint64) (filteredList map[uint64]*lavasession.ConsumerSessionsWithProvider, err error) { +func (pu *PairingUpdater) filterPairingListByEndpoint(ctx context.Context, currentGeo planstypes.Geolocation, pairingList []epochstoragetypes.StakeEntry, rpcEndpoint lavasession.RPCEndpoint, epoch uint64) (filteredList map[uint64]*lavasession.ConsumerSessionsWithProvider, err error) { // go over stake entries, and filter endpoints that match geolocation and api interface pairing := map[uint64]*lavasession.ConsumerSessionsWithProvider{} for providerIdx, provider := range pairingList { @@ -167,9 +168,11 @@ func (pu *PairingUpdater) filterPairingListByEndpoint(ctx context.Context, pairi for _, extension := range relevantEndpoint.Extensions { extensions[extension] = struct{}{} } - endp := &lavasession.Endpoint{NetworkAddress: relevantEndpoint.IPPORT, Enabled: true, Client: nil, ConnectionRefusals: 0, Addons: addons, Extensions: extensions} + + endp := &lavasession.Endpoint{Geolocation: planstypes.Geolocation(relevantEndpoint.Geolocation), NetworkAddress: relevantEndpoint.IPPORT, Enabled: true, Client: nil, ConnectionRefusals: 0, Addons: addons, Extensions: extensions} pairingEndpoints[idx] = endp } + lavasession.SortByGeolocations(pairingEndpoints, currentGeo) pairing[uint64(providerIdx)] = &lavasession.ConsumerSessionsWithProvider{ PublicLavaAddress: provider.Address, diff --git a/testutil/e2e/README.md b/testutil/e2e/README.md index 19c31e5a03..6cd7da0960 100644 --- a/testutil/e2e/README.md +++ b/testutil/e2e/README.md @@ -1,23 +1,32 @@ # Lava E2E +If you wish you can also run E2E tests independently -If you wish you can also run E2E tests independently: - -1. Lava Protocol E2: +## Lava Protocol E2 ``` go test ./testutil/e2e/ -run ^TestLavaProtocol$ -v -timeout 1200s ``` -2. Lava SDK E2E: +## Lava SDK E2E + +If this is the first time you run the e2e after fetching a branch and you didn't compile the protobufs first run +```bash +cd ecosystem/lava-sdk; ./init_sdk.sh ``` + +Now you can run the test running: +```bash yarn --cwd ./ecosystem/lava-sdk/ build; yarn --cwd ./ecosystem/lavajs/ e2e-setup; go test ./testutil/e2e/ -run ^TestLavaSDK -v -timeout 1200s ``` -Run all our E2E using the following command (from the root) - NOT STABLE +-------------------- -``` + +## Run all our E2E using the following command (from the root) {NOT STABLE} + +```bash yarn --cwd ./ecosystem/lava-sdk/ build; yarn --cwd ./ecosystem/lavajs/ e2e-setup; go test ./testutil/e2e/ -v -timeout 1200s ``` diff --git a/testutil/e2e/lava_fullFlow_test.go b/testutil/e2e/lava_fullFlow_test.go index c7e9ea61d4..1ae4478d5f 100644 --- a/testutil/e2e/lava_fullFlow_test.go +++ b/testutil/e2e/lava_fullFlow_test.go @@ -1,6 +1,7 @@ package e2e import ( + "fmt" "testing" "time" ) @@ -17,6 +18,7 @@ func TestLavaProtocol(t *testing.T) { } func TestLavaSDK(t *testing.T) { + fmt.Println("Starting SDK tests, what will happen, you will not see... until it's too late") // default timeout same as `go test` timeout := time.Minute * 10 diff --git a/testutil/e2e/sdk/e2e.go b/testutil/e2e/sdk/e2e.go index 926244b452..a7f12ee16d 100644 --- a/testutil/e2e/sdk/e2e.go +++ b/testutil/e2e/sdk/e2e.go @@ -34,6 +34,7 @@ type Pair struct { } func RunSDKTest(testFile string, privateKey string, publicKey string, logs *bytes.Buffer, badgePort string) error { + utils.LavaFormatInfo("[+] Starting SDK test", utils.LogAttr("test_file", testFile)) // Prepare command for running test cmd := exec.Command("ts-node", testFile) @@ -61,8 +62,7 @@ func RunSDKTest(testFile string, privateKey string, publicKey string, logs *byte utils.LavaFormatInfo(fmt.Sprintf("Running test: %s", testFile)) err := cmd.Run() if err != nil { - utils.LavaFormatError("Failed running test", err, utils.Attribute{Key: "test file", Value: testFile}) - return err + utils.LavaFormatPanic("Failed running test", err, utils.Attribute{Key: "test file", Value: testFile}) } else { utils.LavaFormatInfo(logs.String()) } diff --git a/testutil/e2e/sdk/tests/emergency_mode_badge.ts b/testutil/e2e/sdk/tests/emergency_mode_badge.ts index dd9cb72cf7..6838c9533e 100644 --- a/testutil/e2e/sdk/tests/emergency_mode_badge.ts +++ b/testutil/e2e/sdk/tests/emergency_mode_badge.ts @@ -1,4 +1,4 @@ -const { LavaSDK } = require("../../../../ecosystem/lava-sdk/bin/src/sdk/sdk"); +import { LavaSDK } from "../../../../ecosystem/lava-sdk/bin/src/sdk/sdk" function delay(ms: number) { return new Promise( resolve => setTimeout(resolve, ms) ); diff --git a/testutil/e2e/sdk/tests/emergency_mode_badge_err.ts b/testutil/e2e/sdk/tests/emergency_mode_badge_err.ts index 55d194535d..68c3a8330b 100644 --- a/testutil/e2e/sdk/tests/emergency_mode_badge_err.ts +++ b/testutil/e2e/sdk/tests/emergency_mode_badge_err.ts @@ -1,4 +1,4 @@ -const { LavaSDK } = require("../../../../ecosystem/lava-sdk/bin/src/sdk/sdk"); +import { LavaSDK } from "../../../../ecosystem/lava-sdk/bin/src/sdk/sdk" async function main() { // Initialize Lava SDK diff --git a/testutil/e2e/sdk/tests/emergency_mode_fetch.ts b/testutil/e2e/sdk/tests/emergency_mode_fetch.ts index 13a82f869f..021dcfdb49 100644 --- a/testutil/e2e/sdk/tests/emergency_mode_fetch.ts +++ b/testutil/e2e/sdk/tests/emergency_mode_fetch.ts @@ -1,4 +1,4 @@ -const { LavaSDK } = require("../../../../ecosystem/lava-sdk/bin/src/sdk/sdk"); +import { LavaSDK } from "../../../../ecosystem/lava-sdk/bin/src/sdk/sdk" function delay(ms: number) { return new Promise( resolve => setTimeout(resolve, ms) ); diff --git a/testutil/e2e/sdk/tests/emergency_mode_fetch_err.ts b/testutil/e2e/sdk/tests/emergency_mode_fetch_err.ts index 316820cc38..7dc15672c5 100644 --- a/testutil/e2e/sdk/tests/emergency_mode_fetch_err.ts +++ b/testutil/e2e/sdk/tests/emergency_mode_fetch_err.ts @@ -1,4 +1,4 @@ -const { LavaSDK } = require("../../../../ecosystem/lava-sdk/bin/src/sdk/sdk"); +import { LavaSDK } from "../../../../ecosystem/lava-sdk/bin/src/sdk/sdk" function delay(ms: number) { return new Promise( resolve => setTimeout(resolve, ms) ); diff --git a/testutil/e2e/sdk/tests/package.json b/testutil/e2e/sdk/tests/package.json new file mode 100644 index 0000000000..65a183796d --- /dev/null +++ b/testutil/e2e/sdk/tests/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "@types/node": "^20.7.1" + } +} diff --git a/testutil/e2e/sdkE2E.go b/testutil/e2e/sdkE2E.go index 6c9f06ad8e..4feb2285a3 100644 --- a/testutil/e2e/sdkE2E.go +++ b/testutil/e2e/sdkE2E.go @@ -151,90 +151,94 @@ func runSDKE2E(timeout time.Duration) { lt.logs["01_sdkTest"] = new(bytes.Buffer) sdk.RunSDKTests(ctx, grpcConn, privateKey, publicKey, lt.logs["01_sdkTest"], "7070") - // Emergency mode tests - utils.LavaFormatInfo("Sleeping Until New Epoch") - lt.sleepUntilNextEpoch() + /* + // ++++++++++ Uncomment After fix +++++++++++ + // Emergency mode tests + utils.LavaFormatInfo("Sleeping Until New Epoch") + lt.sleepUntilNextEpoch() - utils.LavaFormatInfo("Restarting lava to emergency mode") + utils.LavaFormatInfo("Restarting lava to emergency mode") - // wait 3 seconds to allow rpcproviders claim rewards before node will be restarted(after restarting node - // we have ctx.BlockHeight == 0, until new block will be created) - time.Sleep(time.Second * 3) + // wait 3 seconds to allow rpcproviders claim rewards before node will be restarted(after restarting node + // we have ctx.BlockHeight == 0, until new block will be created) + time.Sleep(time.Second * 3) - lt.stopLava() - go lt.startLavaInEmergencyMode(lavaContext, 100000) + lt.stopLava() + go lt.startLavaInEmergencyMode(lavaContext, 100000) - lt.checkLava(timeout) - utils.LavaFormatInfo("Starting Lava OK") + lt.checkLava(timeout) + utils.LavaFormatInfo("Starting Lava OK") - var epochDuration int64 = 20 * 1.2 - signalChannel := make(chan bool) - latestBlockTime := lt.getLatestBlockTime() + var epochDuration int64 = 20 * 1.2 + signalChannel := make(chan bool) + latestBlockTime := lt.getLatestBlockTime() - go func() { - epochCounter := (time.Now().Unix() - latestBlockTime.Unix()) / epochDuration + go func() { + epochCounter := (time.Now().Unix() - latestBlockTime.Unix()) / epochDuration - for { - time.Sleep(time.Until(latestBlockTime.Add(time.Second * time.Duration(epochDuration*(epochCounter+1))))) - utils.LavaFormatInfo(fmt.Sprintf("%d : VIRTUAL EPOCH ENDED", epochCounter)) + for { + time.Sleep(time.Until(latestBlockTime.Add(time.Second * time.Duration(epochDuration*(epochCounter+1))))) + utils.LavaFormatInfo(fmt.Sprintf("%d : VIRTUAL EPOCH ENDED", epochCounter)) - epochCounter++ - signalChannel <- true - } - }() + epochCounter++ + signalChannel <- true + } + }() - utils.LavaFormatInfo("Waiting for finishing current epoch") + utils.LavaFormatInfo("Waiting for finishing current epoch 1") - // we should have approximately (numOfProviders * epoch_cu_limit * 2) CU - // skip current epoch - <-signalChannel + // we should have approximately (numOfProviders * epoch_cu_limit * 2) CU + // skip current epoch + <-signalChannel - privateKey = exportUserPrivateKey(lt.lavadPath, "user5") - publicKey = exportUserPublicKey(lt.lavadPath, "user5") - lt.startBadgeServer(ctx, privateKey, publicKey, "5050", "60") + privateKey = exportUserPrivateKey(lt.lavadPath, "user5") + publicKey = exportUserPublicKey(lt.lavadPath, "user5") + lt.startBadgeServer(ctx, privateKey, publicKey, "5050", "60") - defer func() { - // Delete the file directly without checking if it exists - os.Remove("testutil/e2e/sdk/pairingList.json") - }() - sdk.GeneratePairingList(grpcConn, ctx) + defer func() { + // Delete the file directly without checking if it exists + os.Remove("testutil/e2e/sdk/pairingList.json") + }() + sdk.GeneratePairingList(grpcConn, ctx) - // Test without badge server - err = sdk.RunSDKTest("testutil/e2e/sdk/tests/emergency_mode_fetch.ts", privateKey, publicKey, lt.logs["01_sdkTest"], "5050") - if err != nil { - panic(fmt.Sprintf("Test File failed: %s\n", "testutil/e2e/sdk/tests/emergency_mode_fetch.ts")) - } + // Test without badge server + utils.LavaFormatInfo("Waiting for finishing current epoch 2") + err = sdk.RunSDKTest("testutil/e2e/sdk/tests/emergency_mode_fetch.ts", privateKey, publicKey, lt.logs["01_sdkTest"], "5050") + if err != nil { + panic(fmt.Sprintf("Test File failed: %s\n", "testutil/e2e/sdk/tests/emergency_mode_fetch.ts")) + } - // Trying to exceed CU limit - err = sdk.RunSDKTest("testutil/e2e/sdk/tests/emergency_mode_fetch_err.ts", privateKey, publicKey, lt.logs["01_sdkTest"], "5050") - if err == nil { - panic(fmt.Sprintf("Test File failed while trying to exceed CU limit: %s\n", "testutil/e2e/sdk/tests/emergency_mode_fetch_err.ts")) - } + // Trying to exceed CU limit + err = sdk.RunSDKTest("testutil/e2e/sdk/tests/emergency_mode_fetch_err.ts", privateKey, publicKey, lt.logs["01_sdkTest"], "5050") + if err == nil { + panic(fmt.Sprintf("Test File failed while trying to exceed CU limit: %s\n", "testutil/e2e/sdk/tests/emergency_mode_fetch_err.ts")) + } - utils.LavaFormatInfo("KEYS EMERGENCY MODE TEST OK") + utils.LavaFormatInfo("KEYS EMERGENCY MODE TEST OK") - utils.LavaFormatInfo("Waiting for finishing current epoch") + utils.LavaFormatInfo("Waiting for finishing current epoch 3") - // we should have approximately (numOfProviders * epoch_cu_limit * 3) CU - // skip current epoch - <-signalChannel - <-signalChannel - <-signalChannel + // we should have approximately (numOfProviders * epoch_cu_limit * 3) CU + // skip current epoch + <-signalChannel + <-signalChannel + <-signalChannel - // Test with badge server - err = sdk.RunSDKTest("testutil/e2e/sdk/tests/emergency_mode_badge.ts", privateKey, publicKey, lt.logs["01_sdkTest"], "5050") - if err != nil { - panic(fmt.Sprintf("Test File failed: %s\n", "testutil/e2e/sdk/tests/emergency_mode_badge.ts")) - } + // Test with badge server + err = sdk.RunSDKTest("testutil/e2e/sdk/tests/emergency_mode_badge.ts", privateKey, publicKey, lt.logs["01_sdkTest"], "5050") + if err != nil { + panic(fmt.Sprintf("Test File failed: %s\n", "testutil/e2e/sdk/tests/emergency_mode_badge.ts")) + } - // Trying to exceed CU limit - err = sdk.RunSDKTest("testutil/e2e/sdk/tests/emergency_mode_badge_err.ts", privateKey, publicKey, lt.logs["01_sdkTest"], "5050") - if err == nil { - panic(fmt.Sprintf("Test File failed while trying to exceed CU limit: %s\n", "testutil/e2e/sdk/tests/emergency_mode_badge_err.ts")) - } + // Trying to exceed CU limit + err = sdk.RunSDKTest("testutil/e2e/sdk/tests/emergency_mode_badge_err.ts", privateKey, publicKey, lt.logs["01_sdkTest"], "5050") + if err == nil { + panic(fmt.Sprintf("Test File failed while trying to exceed CU limit: %s\n", "testutil/e2e/sdk/tests/emergency_mode_badge_err.ts")) + } - utils.LavaFormatInfo("BADGE EMERGENCY MODE TEST OK") + utils.LavaFormatInfo("BADGE EMERGENCY MODE TEST OK") + */ lt.finishTestSuccessfully() // Cancel lava network using context diff --git a/x/pairing/keeper/pairing_test.go b/x/pairing/keeper/pairing_test.go index 1442e34546..579902670b 100644 --- a/x/pairing/keeper/pairing_test.go +++ b/x/pairing/keeper/pairing_test.go @@ -1139,7 +1139,7 @@ func verifyGeoScoreForTesting(providerScores []*pairingscores.PairingScore, slot return false } - sort.Slice(providerScores, func(i, j int) bool { + sort.SliceStable(providerScores, func(i, j int) bool { return providerScores[i].Score.GT(providerScores[j].Score) }) diff --git a/x/pairing/keeper/scores/geo_req.go b/x/pairing/keeper/scores/geo_req.go index 933ed15edb..8722f9c2ea 100644 --- a/x/pairing/keeper/scores/geo_req.go +++ b/x/pairing/keeper/scores/geo_req.go @@ -68,9 +68,20 @@ type GeoLatency struct { // CalcGeoCost() finds the minimal latency between the required geo and the provider's supported geolocations func CalcGeoCost(reqGeo planstypes.Geolocation, providerGeos []planstypes.Geolocation) (minLatencyGeo planstypes.Geolocation, minLatencyCost math.Uint) { + minGeo, minLatency := CalcGeoLatency(reqGeo, providerGeos) + + return minGeo, calculateCostFromLatency(minLatency) +} + +func CalcGeoLatency(reqGeo planstypes.Geolocation, providerGeos []planstypes.Geolocation) (planstypes.Geolocation, uint64) { minGeo := planstypes.Geolocation(-1) minLatency := uint64(maxGeoLatency) for _, pGeo := range providerGeos { + if pGeo == reqGeo { + minGeo = pGeo + minLatency = 1 + continue + } if inner, ok := GEO_LATENCY_MAP[reqGeo]; ok { if latency, ok := inner[pGeo]; ok { if latency < minLatency { @@ -80,8 +91,7 @@ func CalcGeoCost(reqGeo planstypes.Geolocation, providerGeos []planstypes.Geoloc } } } - - return minGeo, calculateCostFromLatency(minLatency) + return minGeo, minLatency } func calculateCostFromLatency(latency uint64) math.Uint { @@ -104,6 +114,7 @@ var GEO_LATENCY_MAP = map[planstypes.Geolocation]map[planstypes.Geolocation]uint planstypes.Geolocation_USE: { planstypes.Geolocation_USC: 42, planstypes.Geolocation_USW: 68, + planstypes.Geolocation_EU: 116, }, planstypes.Geolocation_USW: { planstypes.Geolocation_USC: 45, @@ -112,11 +123,13 @@ var GEO_LATENCY_MAP = map[planstypes.Geolocation]map[planstypes.Geolocation]uint planstypes.Geolocation_USC: { planstypes.Geolocation_USE: 42, planstypes.Geolocation_USW: 45, + planstypes.Geolocation_EU: 170, }, planstypes.Geolocation_EU: { planstypes.Geolocation_USE: 116, planstypes.Geolocation_AF: 138, planstypes.Geolocation_AS: 155, + planstypes.Geolocation_USC: 170, }, planstypes.Geolocation_AF: { planstypes.Geolocation_EU: 138, diff --git a/x/plans/types/geolocation.go b/x/plans/types/geolocation.go index 5352deec19..f625f53ecd 100644 --- a/x/plans/types/geolocation.go +++ b/x/plans/types/geolocation.go @@ -115,7 +115,7 @@ func PrintGeolocations() string { geos = append(geos, geoInt) } - sort.Slice(geos, func(i, j int) bool { + sort.SliceStable(geos, func(i, j int) bool { return geos[i] < geos[j] }) diff --git a/x/spec/types/spec.go b/x/spec/types/spec.go index ae25f19be2..f6f1013e74 100644 --- a/x/spec/types/spec.go +++ b/x/spec/types/spec.go @@ -142,7 +142,7 @@ func (spec *Spec) CombineCollections(parentsCollections map[CollectionData][]*Ap collectionDataList = append(collectionDataList, key) } // sort the slice so the order is deterministic - sort.Slice(collectionDataList, func(i, j int) bool { + sort.SliceStable(collectionDataList, func(i, j int) bool { return collectionDataList[i].String() < collectionDataList[j].String() }) From 50a81cbec3a41d703fe454609e5f5f5f39ac13d0 Mon Sep 17 00:00:00 2001 From: omerlavanet Date: Mon, 4 Dec 2023 10:28:16 +0200 Subject: [PATCH 28/85] added subsqd verification --- cookbook/specs/spec_add_sqdsubgraph.json | 61 ++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 5 deletions(-) diff --git a/cookbook/specs/spec_add_sqdsubgraph.json b/cookbook/specs/spec_add_sqdsubgraph.json index 7db4f8d6e2..fc527b78b5 100644 --- a/cookbook/specs/spec_add_sqdsubgraph.json +++ b/cookbook/specs/spec_add_sqdsubgraph.json @@ -44,6 +44,24 @@ "stateful": 0 }, "extra_compute_units": 0 + }, + { + "name": "/subgraphs/name/1", + "block_parsing": { + "parser_arg": [ + "" + ], + "parser_func": "EMPTY" + }, + "compute_units": 10, + "enabled": false, + "category": { + "deterministic": false, + "local": true, + "subscription": false, + "stateful": 0 + }, + "extra_compute_units": 0 } ], "inheritance_apis": [], @@ -52,23 +70,56 @@ { "name": "health", "parse_directive": { - "function_template": "/", + "function_template": "/subgraphs/name/1", "function_tag": "VERIFICATION", "result_parsing": { "parser_arg": [ - "latest" + "0", + "message" ], - "parser_func": "DEFAULT" + "parser_func": "PARSE_CANONICAL" }, - "api_name": "/subgraphs/name/health" + "api_name": "/subgraphs/name/1" }, "values": [ { - "expected_value": "*" + "expected_value": "Body is required" } ] } ] + }, + { + "enabled": true, + "collection_data": { + "api_interface": "rest", + "internal_path": "", + "type": "POST", + "add_on": "convex" + }, + "apis": [ + { + "name": "/subgraphs/name/convex", + "block_parsing": { + "parser_arg": [ + "" + ], + "parser_func": "EMPTY" + }, + "compute_units": 200, + "enabled": true, + "category": { + "deterministic": false, + "local": true, + "subscription": false, + "stateful": 0 + }, + "extra_compute_units": 0 + } + ], + "inheritance_apis": [], + "parse_directives": [], + "verifications": [] } ] } From 860cb2d0060b4f3f20060d7168f5596e0584fa5f Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Mon, 4 Dec 2023 13:27:01 +0000 Subject: [PATCH 29/85] add ante handler --- app/ante.go | 5 +- app/app.go | 1 + .../lava/dualstaking/delegation_que.proto | 11 + x/dualstaking/ante/ante_handler.go | 49 +++ x/dualstaking/keeper/delegate_que.go | 49 +++ x/dualstaking/keeper/hooks.go | 8 + x/dualstaking/types/delegation_que.go | 18 + x/dualstaking/types/delegation_que.pb.go | 364 ++++++++++++++++++ x/dualstaking/types/types.go | 4 + 9 files changed, 508 insertions(+), 1 deletion(-) create mode 100644 proto/lavanet/lava/dualstaking/delegation_que.proto create mode 100644 x/dualstaking/ante/ante_handler.go create mode 100644 x/dualstaking/keeper/delegate_que.go create mode 100644 x/dualstaking/types/delegation_que.go create mode 100644 x/dualstaking/types/delegation_que.pb.go diff --git a/app/ante.go b/app/ante.go index c3b81efdbe..362d4af8af 100644 --- a/app/ante.go +++ b/app/ante.go @@ -5,9 +5,11 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/ante" "github.com/cosmos/cosmos-sdk/x/auth/signing" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + dualstakingante "github.com/lavanet/lava/x/dualstaking/ante" + dualstakingkeeper "github.com/lavanet/lava/x/dualstaking/keeper" ) -func NewAnteHandler(accountKeeper ante.AccountKeeper, bankKeeper authtypes.BankKeeper, signModeHandler signing.SignModeHandler, feegrantKeeper ante.FeegrantKeeper, sigGasConsumer ante.SignatureVerificationGasConsumer) sdk.AnteHandler { +func NewAnteHandler(accountKeeper ante.AccountKeeper, bankKeeper authtypes.BankKeeper, dualstakingKeeper dualstakingkeeper.Keeper, signModeHandler signing.SignModeHandler, feegrantKeeper ante.FeegrantKeeper, sigGasConsumer ante.SignatureVerificationGasConsumer) sdk.AnteHandler { anteDecorators := []sdk.AnteDecorator{ ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first ante.NewExtensionOptionsDecorator(nil), @@ -21,6 +23,7 @@ func NewAnteHandler(accountKeeper ante.AccountKeeper, bankKeeper authtypes.BankK ante.NewSigGasConsumeDecorator(accountKeeper, sigGasConsumer), ante.NewSigVerificationDecorator(accountKeeper, signModeHandler), ante.NewIncrementSequenceDecorator(accountKeeper), + dualstakingante.NewRedelegationFlager(dualstakingKeeper), } return sdk.ChainAnteDecorators(anteDecorators...) } diff --git a/app/app.go b/app/app.go index 3c9bd06edc..c4a814f44b 100644 --- a/app/app.go +++ b/app/app.go @@ -800,6 +800,7 @@ func New( NewAnteHandler( app.AccountKeeper, app.BankKeeper, + app.DualstakingKeeper, encodingConfig.TxConfig.SignModeHandler(), app.FeeGrantKeeper, ante.DefaultSigVerificationGasConsumer), diff --git a/proto/lavanet/lava/dualstaking/delegation_que.proto b/proto/lavanet/lava/dualstaking/delegation_que.proto new file mode 100644 index 0000000000..0426845f7b --- /dev/null +++ b/proto/lavanet/lava/dualstaking/delegation_que.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; +package lavanet.lava.dualstaking; + +option go_package = "github.com/lavanet/lava/x/dualstaking/types"; + +import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; + +message DelegationQue { + repeated bool Que = 1; +} \ No newline at end of file diff --git a/x/dualstaking/ante/ante_handler.go b/x/dualstaking/ante/ante_handler.go new file mode 100644 index 0000000000..e6842cdc37 --- /dev/null +++ b/x/dualstaking/ante/ante_handler.go @@ -0,0 +1,49 @@ +package ante + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/lavanet/lava/x/dualstaking/keeper" + "github.com/lavanet/lava/x/dualstaking/types" +) + +// RedelegationFlager sets the GasMeter in the Context and wraps the next AnteHandler with a defer clause +// to recover from any downstream OutOfGas panics in the AnteHandler chain to return an error with information +// on gas provided and gas used. +// CONTRACT: Must be first decorator in the chain +// CONTRACT: Tx must implement GasTx interface +type RedelegationFlager struct { + keeper.Keeper +} + +func NewRedelegationFlager(dualstaking keeper.Keeper) RedelegationFlager { + return RedelegationFlager{Keeper: dualstaking} +} + +func (rf RedelegationFlager) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { + que := types.DelegationQue{} + msgs := tx.GetMsgs() + for _, msg := range msgs { + switch msg.(type) { + case *stakingtypes.MsgBeginRedelegate: + que.Redelegate() + case *stakingtypes.MsgCreateValidator: + que.DelegateUnbond() + case *stakingtypes.MsgDelegate: + que.DelegateUnbond() + case *stakingtypes.MsgUndelegate: + que.DelegateUnbond() + case *stakingtypes.MsgCancelUnbondingDelegation: + que.DelegateUnbond() + case *types.MsgDelegate: + que.DelegateUnbond() + case *types.MsgUnbond: + que.DelegateUnbond() + + default: + } + } + rf.SetDelegationQue(ctx, que) + return next(ctx, tx, simulate) +} diff --git a/x/dualstaking/keeper/delegate_que.go b/x/dualstaking/keeper/delegate_que.go new file mode 100644 index 0000000000..5ff946de53 --- /dev/null +++ b/x/dualstaking/keeper/delegate_que.go @@ -0,0 +1,49 @@ +package keeper + +// Delegation allows securing funds for a specific provider to effectively increase +// its stake so it will be paired with consumers more often. The delegators do not +// transfer the funds to the provider but only bestow the funds with it. In return +// to locking the funds there, delegators get some of the provider’s profit (after +// commission deduction). +// +// The delegated funds are stored in the module's BondedPoolName account. On request +// to terminate the delegation, they are then moved to the modules NotBondedPoolName +// account, and remain locked there for staking.UnbondingTime() witholding period +// before finally released back to the delegator. The timers for bonded funds are +// tracked are indexed by the delegator, provider, and chainID. +// +// The delegation state is stores with fixation using two maps: one for delegations +// indexed by the combination , used to track delegations +// and find/access delegations by provider (and chainID); and another for delegators +// tracking the list of providers for a delegator, indexed by the delegator. + +import ( + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/lavanet/lava/x/dualstaking/types" +) + +func (k Keeper) SetDelegationQue(ctx sdk.Context, que types.DelegationQue) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.DelegationQueKeyPrefix)) + b := k.cdc.MustMarshal(&que) + store.Set([]byte{0}, b) +} + +func (k Keeper) GetDelegationQue(ctx sdk.Context) (val types.DelegationQue, found bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.DelegationQueKeyPrefix)) + + b := store.Get([]byte{0}) + if b == nil { + return val, false + } + + k.cdc.MustUnmarshal(b, &val) + return val, true +} + +func (k Keeper) DelegationQuePop(ctx sdk.Context) bool { + que, _ := k.GetDelegationQue(ctx) + item := que.DeQue() + k.SetDelegationQue(ctx, que) + return item +} diff --git a/x/dualstaking/keeper/hooks.go b/x/dualstaking/keeper/hooks.go index 1fd8251741..551bc040ff 100644 --- a/x/dualstaking/keeper/hooks.go +++ b/x/dualstaking/keeper/hooks.go @@ -46,6 +46,10 @@ func (h Hooks) BeforeDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAd // create new delegation period record // add description func (h Hooks) AfterDelegationModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error { + if !h.k.DelegationQuePop(ctx) { + return nil + } + diff, err := h.k.VerifyDelegatorBalance(ctx, delAddr) if err != nil { return err @@ -138,6 +142,10 @@ func (h Hooks) AfterValidatorBeginUnbonding(_ sdk.Context, _ sdk.ConsAddress, _ } func (h Hooks) BeforeDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error { + if !h.k.DelegationQuePop(ctx) { + return nil + } + delegation, found := h.k.stakingKeeper.GetDelegation(ctx, delAddr, valAddr) if !found { return fmt.Errorf("could not find delegation for dualstaking hook") diff --git a/x/dualstaking/types/delegation_que.go b/x/dualstaking/types/delegation_que.go new file mode 100644 index 0000000000..32bbcb148d --- /dev/null +++ b/x/dualstaking/types/delegation_que.go @@ -0,0 +1,18 @@ +package types + +// mark the next to be a regular delegation/unbond, as stand alone we want to take action +func (dq *DelegationQue) DelegateUnbond() { + dq.Que = append(dq.Que, true) +} + +// redelegates does unbond and than redelegate, we dont want to take action in dual staking, mark them as false +func (dq *DelegationQue) Redelegate() { + dq.Que = append(dq.Que, false) + dq.Que = append(dq.Que, false) +} + +func (dq *DelegationQue) DeQue() bool { + item := dq.Que[0] + dq.Que = dq.Que[1:] + return item +} diff --git a/x/dualstaking/types/delegation_que.pb.go b/x/dualstaking/types/delegation_que.pb.go new file mode 100644 index 0000000000..823d3dc825 --- /dev/null +++ b/x/dualstaking/types/delegation_que.pb.go @@ -0,0 +1,364 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: lavanet/lava/dualstaking/delegation_que.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// 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 + +type DelegationQue struct { + Que []bool `protobuf:"varint,1,rep,packed,name=Que,proto3" json:"Que,omitempty"` +} + +func (m *DelegationQue) Reset() { *m = DelegationQue{} } +func (m *DelegationQue) String() string { return proto.CompactTextString(m) } +func (*DelegationQue) ProtoMessage() {} +func (*DelegationQue) Descriptor() ([]byte, []int) { + return fileDescriptor_a56a227bbc9f22a1, []int{0} +} +func (m *DelegationQue) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DelegationQue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DelegationQue.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 *DelegationQue) XXX_Merge(src proto.Message) { + xxx_messageInfo_DelegationQue.Merge(m, src) +} +func (m *DelegationQue) XXX_Size() int { + return m.Size() +} +func (m *DelegationQue) XXX_DiscardUnknown() { + xxx_messageInfo_DelegationQue.DiscardUnknown(m) +} + +var xxx_messageInfo_DelegationQue proto.InternalMessageInfo + +func (m *DelegationQue) GetQue() []bool { + if m != nil { + return m.Que + } + return nil +} + +func init() { + proto.RegisterType((*DelegationQue)(nil), "lavanet.lava.dualstaking.DelegationQue") +} + +func init() { + proto.RegisterFile("lavanet/lava/dualstaking/delegation_que.proto", fileDescriptor_a56a227bbc9f22a1) +} + +var fileDescriptor_a56a227bbc9f22a1 = []byte{ + // 201 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0xcd, 0x49, 0x2c, 0x4b, + 0xcc, 0x4b, 0x2d, 0xd1, 0x07, 0xd1, 0xfa, 0x29, 0xa5, 0x89, 0x39, 0xc5, 0x25, 0x89, 0xd9, 0x99, + 0x79, 0xe9, 0xfa, 0x29, 0xa9, 0x39, 0xa9, 0xe9, 0x89, 0x25, 0x99, 0xf9, 0x79, 0xf1, 0x85, 0xa5, + 0xa9, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0x12, 0x50, 0xe5, 0x7a, 0x20, 0x5a, 0x0f, 0x49, + 0xb9, 0x94, 0x48, 0x7a, 0x7e, 0x7a, 0x3e, 0x58, 0x91, 0x3e, 0x88, 0x05, 0x51, 0x2f, 0x25, 0x97, + 0x9c, 0x5f, 0x9c, 0x9b, 0x5f, 0xac, 0x9f, 0x94, 0x58, 0x9c, 0xaa, 0x5f, 0x66, 0x98, 0x94, 0x5a, + 0x92, 0x68, 0xa8, 0x9f, 0x9c, 0x9f, 0x99, 0x07, 0x91, 0x57, 0x52, 0xe4, 0xe2, 0x75, 0x81, 0xdb, + 0x13, 0x58, 0x9a, 0x2a, 0x24, 0xc0, 0xc5, 0x1c, 0x58, 0x9a, 0x2a, 0xc1, 0xa8, 0xc0, 0xac, 0xc1, + 0x11, 0x04, 0x62, 0x3a, 0xb9, 0x9e, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, + 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, + 0x76, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x3e, 0x8a, 0x37, 0x2a, 0x50, + 0x3c, 0x52, 0x52, 0x59, 0x90, 0x5a, 0x9c, 0xc4, 0x06, 0xb6, 0xd0, 0x18, 0x10, 0x00, 0x00, 0xff, + 0xff, 0xb6, 0xfd, 0xfd, 0xf9, 0xf1, 0x00, 0x00, 0x00, +} + +func (m *DelegationQue) 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 *DelegationQue) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DelegationQue) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Que) > 0 { + for iNdEx := len(m.Que) - 1; iNdEx >= 0; iNdEx-- { + i-- + if m.Que[iNdEx] { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + } + i = encodeVarintDelegationQue(dAtA, i, uint64(len(m.Que))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintDelegationQue(dAtA []byte, offset int, v uint64) int { + offset -= sovDelegationQue(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *DelegationQue) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Que) > 0 { + n += 1 + sovDelegationQue(uint64(len(m.Que))) + len(m.Que)*1 + } + return n +} + +func sovDelegationQue(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozDelegationQue(x uint64) (n int) { + return sovDelegationQue(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *DelegationQue) 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 ErrIntOverflowDelegationQue + } + 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: DelegationQue: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DelegationQue: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType == 0 { + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDelegationQue + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Que = append(m.Que, bool(v != 0)) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDelegationQue + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthDelegationQue + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthDelegationQue + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + elementCount = packedLen + if elementCount != 0 && len(m.Que) == 0 { + m.Que = make([]bool, 0, elementCount) + } + for iNdEx < postIndex { + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDelegationQue + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Que = append(m.Que, bool(v != 0)) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field Que", wireType) + } + default: + iNdEx = preIndex + skippy, err := skipDelegationQue(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthDelegationQue + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipDelegationQue(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, ErrIntOverflowDelegationQue + } + 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, ErrIntOverflowDelegationQue + } + 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, ErrIntOverflowDelegationQue + } + 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, ErrInvalidLengthDelegationQue + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupDelegationQue + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthDelegationQue + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthDelegationQue = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowDelegationQue = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupDelegationQue = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/dualstaking/types/types.go b/x/dualstaking/types/types.go index ca141ed0de..57fb29b5a0 100644 --- a/x/dualstaking/types/types.go +++ b/x/dualstaking/types/types.go @@ -14,3 +14,7 @@ const ( NotBondedPoolName = "not_bonded_dualstaking_pool" BondedPoolName = "bonded_dualstaking_pool" ) + +const ( + DelegationQueKeyPrefix = "DelegationQue/value/" +) From c517952d2ded2742c75045feb10ae71b9360967a Mon Sep 17 00:00:00 2001 From: oren-lava Date: Tue, 5 Dec 2023 11:10:46 +0200 Subject: [PATCH 30/85] CNS-755: added sepolia spec --- cookbook/specs/spec_add_ethereum.json | 43 +++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/cookbook/specs/spec_add_ethereum.json b/cookbook/specs/spec_add_ethereum.json index e8da015f45..d5ba54f454 100644 --- a/cookbook/specs/spec_add_ethereum.json +++ b/cookbook/specs/spec_add_ethereum.json @@ -1376,6 +1376,49 @@ ] } ] + }, + { + "index": "SEP1", + "name": "ethereum testnet sepolia", + "enabled": true, + "imports": [ + "ETH1" + ], + "reliability_threshold": 268435455, + "data_reliability_enabled": true, + "block_distance_for_finalized_data": 7, + "blocks_in_finalization_proof": 3, + "average_block_time": 13000, + "allowed_block_lag_for_qos_sync": 2, + "min_stake_provider": { + "denom": "ulava", + "amount": "50000000000" + }, + "api_collections": [ + { + "enabled": true, + "collection_data": { + "api_interface": "jsonrpc", + "internal_path": "", + "type": "POST", + "add_on": "" + }, + "apis": [], + "headers": [], + "inheritance_apis": [], + "parse_directives": [], + "verifications": [ + { + "name": "chain-id", + "values": [ + { + "expected_value": "0xaa36a7" + } + ] + } + ] + } + ] } ] }, From 7e593bfc73fcf96b440346b076a046008458f0b2 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Tue, 5 Dec 2023 09:16:01 +0000 Subject: [PATCH 31/85] fix linter issues --- ecosystem/lava-sdk/src/rpcconsumer/consumerConsistency.ts | 2 -- .../src/stateTracker/updaters/emergency_tracker.test.ts | 2 +- ecosystem/lava-sdk/src/util/apiCollection.ts | 1 - ecosystem/lava-sdk/src/util/transportNode.ts | 1 - 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/ecosystem/lava-sdk/src/rpcconsumer/consumerConsistency.ts b/ecosystem/lava-sdk/src/rpcconsumer/consumerConsistency.ts index 4dc00652e8..122f096510 100644 --- a/ecosystem/lava-sdk/src/rpcconsumer/consumerConsistency.ts +++ b/ecosystem/lava-sdk/src/rpcconsumer/consumerConsistency.ts @@ -1,5 +1,3 @@ -import { Logger } from "../logger/logger"; - export class ConsumerConsistency { private specId: string; private latestSeen: number; diff --git a/ecosystem/lava-sdk/src/stateTracker/updaters/emergency_tracker.test.ts b/ecosystem/lava-sdk/src/stateTracker/updaters/emergency_tracker.test.ts index b204efd360..a482a43b06 100644 --- a/ecosystem/lava-sdk/src/stateTracker/updaters/emergency_tracker.test.ts +++ b/ecosystem/lava-sdk/src/stateTracker/updaters/emergency_tracker.test.ts @@ -35,7 +35,7 @@ function setupConsumerSessionManager( relayer = setupRelayer(); jest .spyOn(relayer, "probeProvider") - .mockImplementation((providerAddress, apiInterface, guid, specId) => { + .mockImplementation((providerAddress, apiInterface, guid) => { const response: ProbeReply = new ProbeReply(); response.setLatestBlock(42); response.setLavaEpoch(20); diff --git a/ecosystem/lava-sdk/src/util/apiCollection.ts b/ecosystem/lava-sdk/src/util/apiCollection.ts index ea83098be0..12a79da350 100644 --- a/ecosystem/lava-sdk/src/util/apiCollection.ts +++ b/ecosystem/lava-sdk/src/util/apiCollection.ts @@ -1,5 +1,4 @@ import { - Api, SpecCategory, } from "../grpc_web_services/lavanet/lava/spec/api_collection_pb"; diff --git a/ecosystem/lava-sdk/src/util/transportNode.ts b/ecosystem/lava-sdk/src/util/transportNode.ts index f1230ed55a..d327ce8892 100644 --- a/ecosystem/lava-sdk/src/util/transportNode.ts +++ b/ecosystem/lava-sdk/src/util/transportNode.ts @@ -2,7 +2,6 @@ import * as http from "http"; import * as https from "https"; import * as url from "url"; import { grpc } from "@improbable-eng/grpc-web"; -import { Logger } from "../logger/logger"; export function NodeHttpTransport( httpsOptions?: https.RequestOptions From 6a3c380ae67c94f63e0091852c742ff08264005c Mon Sep 17 00:00:00 2001 From: oren-lava Date: Tue, 5 Dec 2023 11:36:17 +0200 Subject: [PATCH 32/85] CNS-755: fix e2e and update inich --- scripts/init_chain_commands.sh | 2 +- testutil/e2e/protocolE2E.go | 10 +++++----- testutil/e2e/sdkE2E.go | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/init_chain_commands.sh b/scripts/init_chain_commands.sh index e842cf3326..ec0372e9f9 100755 --- a/scripts/init_chain_commands.sh +++ b/scripts/init_chain_commands.sh @@ -38,7 +38,7 @@ lavad tx subscription buy DefaultPlan $(lavad keys show user1 -a) -y --from use # lavad tx project set-policy $(lavad keys show user1 -a)-admin ./cookbook/projects/policy_all_chains_with_addon.yml -y --from user1 --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE # MANTLE -CHAINS="ETH1,GTH1,COS3,FTM250,CELO,LAV1,COS4,ALFAJORES,ARB1,ARBN,APT1,STRK,JUN1,COS5,POLYGON1,EVMOS,OPTM,BASET,CANTO,SUIT,SOLANA,BSC,AXELAR,AVAX,FVM,NEAR,SQDSUBGRAPH" +CHAINS="ETH1,GTH1,SEP1,COS3,FTM250,CELO,LAV1,COS4,ALFAJORES,ARB1,ARBN,APT1,STRK,JUN1,COS5,POLYGON1,EVMOS,OPTM,BASET,CANTO,SUIT,SOLANA,BSC,AXELAR,AVAX,FVM,NEAR,SQDSUBGRAPH" BASE_CHAINS="ETH1,LAV1" # stake providers on all chains lavad tx pairing bulk-stake-provider $CHAINS $PROVIDERSTAKE "$PROVIDER1_LISTENER,1" 1 -y --delegate-commission 50 --delegate-limit $PROVIDERSTAKE --from servicer1 --provider-moniker "servicer1" --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE diff --git a/testutil/e2e/protocolE2E.go b/testutil/e2e/protocolE2E.go index 4a5c2360af..84a773f1e8 100644 --- a/testutil/e2e/protocolE2E.go +++ b/testutil/e2e/protocolE2E.go @@ -50,7 +50,7 @@ var ( checkedPlansE2E = []string{"DefaultPlan", "EmergencyModePlan"} checkedSubscriptions = []string{"user1", "user2", "user3", "user5"} checkedSpecsE2E = []string{"LAV1", "ETH1"} - checkedSpecsE2ELOL = []string{"GTH1"} + checkedSpecsE2ELOL = []string{"GTH1", "SEP1"} checkedSubscriptionsLOL = []string{"user4"} ) @@ -623,10 +623,10 @@ func (lt *lavaTest) lavaOverLava(ctx context.Context) { lt.execCommand(ctx, "startJSONRPCConsumer", "07_lavaOverLava", command, true) // scripts/init_e2e.sh will: - // - produce 4 specs: ETH1, GTH1, IBC, COSMOSSDK, LAV1 (via spec_add_{ethereum,cosmoshub,lava}) + // - produce 5 specs: ETH1, GTH1, SEP1, IBC, COSMOSSDK, LAV1 (via spec_add_{ethereum,cosmoshub,lava}) // - produce 2 plans: "DefaultPlan", "EmergencyModePlan" - lt.checkStakeLava(2, 5, 4, 5, checkedPlansE2E, checkedSpecsE2ELOL, checkedSubscriptionsLOL, "Lava Over Lava Test OK") + lt.checkStakeLava(2, 5, 5, 5, checkedPlansE2E, checkedSpecsE2ELOL, checkedSubscriptionsLOL, "Lava Over Lava Test OK") } func (lt *lavaTest) checkRESTConsumer(rpcURL string, timeout time.Duration) { @@ -1173,13 +1173,13 @@ func runProtocolE2E(timeout time.Duration) { lt.stakeLava(ctx) // scripts/init_e2e.sh will: - // - produce 4 specs: ETH1, GTH1, IBC, COSMOSSDK, LAV1 (via spec_add_{ethereum,cosmoshub,lava}) + // - produce 4 specs: ETH1, GTH1, SEP1, IBC, COSMOSSDK, LAV1 (via spec_add_{ethereum,cosmoshub,lava}) // - produce 2 plans: "DefaultPlan", "EmergencyModePlan" // - produce 5 staked providers (for each of ETH1, LAV1) // - produce 1 staked client (for each of ETH1, LAV1) // - produce 1 subscription (for both ETH1, LAV1) - lt.checkStakeLava(2, 5, 4, 5, checkedPlansE2E, checkedSpecsE2E, checkedSubscriptions, "Staking Lava OK") + lt.checkStakeLava(2, 5, 5, 5, checkedPlansE2E, checkedSpecsE2E, checkedSubscriptions, "Staking Lava OK") utils.LavaFormatInfo("RUNNING TESTS") diff --git a/testutil/e2e/sdkE2E.go b/testutil/e2e/sdkE2E.go index 4feb2285a3..49ce75aead 100644 --- a/testutil/e2e/sdkE2E.go +++ b/testutil/e2e/sdkE2E.go @@ -124,7 +124,7 @@ func runSDKE2E(timeout time.Duration) { utils.LavaFormatInfo("Staking Lava") lt.stakeLava(ctx) - lt.checkStakeLava(2, 5, 4, 5, checkedPlansE2E, checkedSpecsE2E, checkedSubscriptions, "Staking Lava OK") + lt.checkStakeLava(2, 5, 5, 5, checkedPlansE2E, checkedSpecsE2E, checkedSubscriptions, "Staking Lava OK") utils.LavaFormatInfo("RUNNING TESTS") From eac3b222d6b1dec6b47a3dd0aaa98877deb2c2b2 Mon Sep 17 00:00:00 2001 From: Ran Mishael <106548467+ranlavanet@users.noreply.github.com> Date: Tue, 5 Dec 2023 10:46:12 +0100 Subject: [PATCH 33/85] CNS-753 fixed emergency mode scripts adding also sync loss case for csm.ts (#1019) * fixed emergency mode scripts adding also sync loss case for csm.ts * removing error from list after fix. * fix requested block being overwritten in retries and session our of sync when there's a lock problem * Update testutil/e2e/sdk/tests/emergency_mode_fetch_err.ts Co-authored-by: Elad Gildnur <6321801+shleikes@users.noreply.github.com> * Move delay function to common.ts * Add comment about exit code * Update README --------- Co-authored-by: omerlavanet Co-authored-by: Elad Gildnur <6321801+shleikes@users.noreply.github.com> Co-authored-by: Elad Gildnur --- .../src/lavasession/consumerSessionManager.ts | 11 +- .../src/rpcconsumer/rpcconsumer_server.ts | 8 +- ecosystem/lava-sdk/yarn.lock | 418 +++++++++++------- protocol/lavasession/errors.go | 2 +- testutil/e2e/README.md | 30 +- testutil/e2e/allowedErrorList.go | 1 - testutil/e2e/sdk/tests/common.ts | 3 + .../e2e/sdk/tests/emergency_mode_badge.ts | 14 +- .../e2e/sdk/tests/emergency_mode_badge_err.ts | 10 +- .../e2e/sdk/tests/emergency_mode_fetch.ts | 15 +- .../e2e/sdk/tests/emergency_mode_fetch_err.ts | 17 +- testutil/e2e/sdk/tests/package.json | 4 +- testutil/e2e/sdkE2E.go | 132 +++--- 13 files changed, 376 insertions(+), 289 deletions(-) create mode 100644 testutil/e2e/sdk/tests/common.ts diff --git a/ecosystem/lava-sdk/src/lavasession/consumerSessionManager.ts b/ecosystem/lava-sdk/src/lavasession/consumerSessionManager.ts index 557935f649..ffa1f55678 100644 --- a/ecosystem/lava-sdk/src/lavasession/consumerSessionManager.ts +++ b/ecosystem/lava-sdk/src/lavasession/consumerSessionManager.ts @@ -399,6 +399,7 @@ export class ConsumerSessionManager { errorReceived?: Error | null ): Error | undefined { if (!consumerSession.isLocked()) { + consumerSession.blockListed = true; return new Error("Session is not locked"); } @@ -410,10 +411,16 @@ export class ConsumerSessionManager { consumerSession.consecutiveNumberOfFailures++; let consumerSessionBlockListed = false; - // TODO: Verify if code == SessionOutOfSyncError.ABCICode() (from go) + let syncLoss = false; + if (errorReceived) { + syncLoss = errorReceived.message.includes( + "codespace SessionOutOfSync Error code 677" + ); + } if ( consumerSession.consecutiveNumberOfFailures > - MAXIMUM_NUMBER_OF_FAILURES_ALLOWED_PER_CONSUMER_SESSION + MAXIMUM_NUMBER_OF_FAILURES_ALLOWED_PER_CONSUMER_SESSION || + syncLoss ) { Logger.debug( `Blocking consumer session id: ${consumerSession.sessionId}` diff --git a/ecosystem/lava-sdk/src/rpcconsumer/rpcconsumer_server.ts b/ecosystem/lava-sdk/src/rpcconsumer/rpcconsumer_server.ts index 4acdc2184a..35aa5104d8 100644 --- a/ecosystem/lava-sdk/src/rpcconsumer/rpcconsumer_server.ts +++ b/ecosystem/lava-sdk/src/rpcconsumer/rpcconsumer_server.ts @@ -241,7 +241,7 @@ export class RPCConsumerServer { relayResult.request = constructRelayRequest( lavaChainId, chainID, - relayData, + relayData.clone(), // clone here so we can modify the query without affecting retries providerPublicAddress, singleConsumerSession, epoch, @@ -268,6 +268,10 @@ export class RPCConsumerServer { chainMessage, relayTimeout ) + .catch((err: any) => { + responsesReceived++; + throw err; + }) .then((relayResponse: RelayResponse) => { responsesReceived++; @@ -346,7 +350,7 @@ export class RPCConsumerServer { // this should never happen, but we need to satisfy the typescript compiler if (finalRelayResult === undefined) { - return new Error("finalRelayResult is undefined"); + return new Error("UnreachableCode finalRelayResult is undefined"); } return finalRelayResult; diff --git a/ecosystem/lava-sdk/yarn.lock b/ecosystem/lava-sdk/yarn.lock index 9caa30111e..665752b56b 100644 --- a/ecosystem/lava-sdk/yarn.lock +++ b/ecosystem/lava-sdk/yarn.lock @@ -22,7 +22,7 @@ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz" integrity sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ== -"@babel/core@^7.11.6", "@babel/core@^7.12.3": +"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.8.0", "@babel/core@>=7.0.0-beta.0 <8": version "7.20.2" resolved "https://registry.npmjs.org/@babel/core/-/core-7.20.2.tgz" integrity sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g== @@ -305,6 +305,16 @@ "@noble/hashes" "^1.0.0" protobufjs "^6.8.8" +"@cosmjs/amino@^0.29.4", "@cosmjs/amino@^0.29.5": + version "0.29.5" + resolved "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.29.5.tgz" + integrity sha512-Qo8jpC0BiziTSUqpkNatBcwtKNhCovUnFul9SlT/74JUCdLYaeG5hxr3q1cssQt++l4LvlcpF+OUXL48XjNjLw== + dependencies: + "@cosmjs/crypto" "^0.29.5" + "@cosmjs/encoding" "^0.29.5" + "@cosmjs/math" "^0.29.5" + "@cosmjs/utils" "^0.29.5" + "@cosmjs/amino@0.27.1": version "0.27.1" resolved "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.27.1.tgz" @@ -325,15 +335,18 @@ "@cosmjs/math" "0.28.2" "@cosmjs/utils" "0.28.2" -"@cosmjs/amino@^0.29.4", "@cosmjs/amino@^0.29.5": +"@cosmjs/crypto@^0.29.4", "@cosmjs/crypto@^0.29.5": version "0.29.5" - resolved "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.29.5.tgz" - integrity sha512-Qo8jpC0BiziTSUqpkNatBcwtKNhCovUnFul9SlT/74JUCdLYaeG5hxr3q1cssQt++l4LvlcpF+OUXL48XjNjLw== + resolved "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.29.5.tgz" + integrity sha512-2bKkaLGictaNL0UipQCL6C1afaisv6k8Wr/GCLx9FqiyFkh9ZgRHDyetD64ZsjnWV/N/D44s/esI+k6oPREaiQ== dependencies: - "@cosmjs/crypto" "^0.29.5" "@cosmjs/encoding" "^0.29.5" "@cosmjs/math" "^0.29.5" "@cosmjs/utils" "^0.29.5" + "@noble/hashes" "^1" + bn.js "^5.2.0" + elliptic "^6.5.4" + libsodium-wrappers "^0.7.6" "@cosmjs/crypto@0.27.1": version "0.27.1" @@ -364,18 +377,14 @@ elliptic "^6.5.3" libsodium-wrappers "^0.7.6" -"@cosmjs/crypto@^0.29.4", "@cosmjs/crypto@^0.29.5": +"@cosmjs/encoding@^0.29.4", "@cosmjs/encoding@^0.29.5": version "0.29.5" - resolved "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.29.5.tgz" - integrity sha512-2bKkaLGictaNL0UipQCL6C1afaisv6k8Wr/GCLx9FqiyFkh9ZgRHDyetD64ZsjnWV/N/D44s/esI+k6oPREaiQ== + resolved "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.29.5.tgz" + integrity sha512-G4rGl/Jg4dMCw5u6PEZHZcoHnUBlukZODHbm/wcL4Uu91fkn5jVo5cXXZcvs4VCkArVGrEj/52eUgTZCmOBGWQ== dependencies: - "@cosmjs/encoding" "^0.29.5" - "@cosmjs/math" "^0.29.5" - "@cosmjs/utils" "^0.29.5" - "@noble/hashes" "^1" - bn.js "^5.2.0" - elliptic "^6.5.4" - libsodium-wrappers "^0.7.6" + base64-js "^1.3.0" + bech32 "^1.1.4" + readonly-date "^1.0.0" "@cosmjs/encoding@0.27.1": version "0.27.1" @@ -395,15 +404,6 @@ bech32 "^1.1.4" readonly-date "^1.0.0" -"@cosmjs/encoding@^0.29.4", "@cosmjs/encoding@^0.29.5": - version "0.29.5" - resolved "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.29.5.tgz" - integrity sha512-G4rGl/Jg4dMCw5u6PEZHZcoHnUBlukZODHbm/wcL4Uu91fkn5jVo5cXXZcvs4VCkArVGrEj/52eUgTZCmOBGWQ== - dependencies: - base64-js "^1.3.0" - bech32 "^1.1.4" - readonly-date "^1.0.0" - "@cosmjs/json-rpc@0.28.2": version "0.28.2" resolved "https://registry.npmjs.org/@cosmjs/json-rpc/-/json-rpc-0.28.2.tgz" @@ -425,6 +425,13 @@ axios "^0.21.2" fast-deep-equal "^3.1.3" +"@cosmjs/math@^0.29.5": + version "0.29.5" + resolved "https://registry.npmjs.org/@cosmjs/math/-/math-0.29.5.tgz" + integrity sha512-2GjKcv+A9f86MAWYLUkjhw1/WpRl2R1BTb3m9qPG7lzMA7ioYff9jY5SPCfafKdxM4TIQGxXQlYGewQL16O68Q== + dependencies: + bn.js "^5.2.0" + "@cosmjs/math@0.27.1": version "0.27.1" resolved "https://registry.npmjs.org/@cosmjs/math/-/math-0.27.1.tgz" @@ -439,12 +446,18 @@ dependencies: bn.js "^5.2.0" -"@cosmjs/math@^0.29.5": +"@cosmjs/proto-signing@^0.29.4": version "0.29.5" - resolved "https://registry.npmjs.org/@cosmjs/math/-/math-0.29.5.tgz" - integrity sha512-2GjKcv+A9f86MAWYLUkjhw1/WpRl2R1BTb3m9qPG7lzMA7ioYff9jY5SPCfafKdxM4TIQGxXQlYGewQL16O68Q== + resolved "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.29.5.tgz" + integrity sha512-QRrS7CiKaoETdgIqvi/7JC2qCwCR7lnWaUsTzh/XfRy3McLkEd+cXbKAW3cygykv7IN0VAEIhZd2lyIfT8KwNA== dependencies: - bn.js "^5.2.0" + "@cosmjs/amino" "^0.29.5" + "@cosmjs/crypto" "^0.29.5" + "@cosmjs/encoding" "^0.29.5" + "@cosmjs/math" "^0.29.5" + "@cosmjs/utils" "^0.29.5" + cosmjs-types "^0.5.2" + long "^4.0.0" "@cosmjs/proto-signing@0.28.2": version "0.28.2" @@ -460,19 +473,6 @@ long "^4.0.0" protobufjs "~6.10.2" -"@cosmjs/proto-signing@^0.29.4": - version "0.29.5" - resolved "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.29.5.tgz" - integrity sha512-QRrS7CiKaoETdgIqvi/7JC2qCwCR7lnWaUsTzh/XfRy3McLkEd+cXbKAW3cygykv7IN0VAEIhZd2lyIfT8KwNA== - dependencies: - "@cosmjs/amino" "^0.29.5" - "@cosmjs/crypto" "^0.29.5" - "@cosmjs/encoding" "^0.29.5" - "@cosmjs/math" "^0.29.5" - "@cosmjs/utils" "^0.29.5" - cosmjs-types "^0.5.2" - long "^4.0.0" - "@cosmjs/socket@0.28.2": version "0.28.2" resolved "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.28.2.tgz" @@ -524,6 +524,11 @@ readonly-date "^1.0.0" xstream "^11.14.0" +"@cosmjs/utils@^0.29.5": + version "0.29.5" + resolved "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.29.5.tgz" + integrity sha512-m7h+RXDUxOzEOGt4P+3OVPX7PuakZT3GBmaM/Y2u+abN3xZkziykD/NvedYFvvCCdQo714XcGl33bwifS9FZPQ== + "@cosmjs/utils@0.27.1": version "0.27.1" resolved "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.27.1.tgz" @@ -534,11 +539,6 @@ resolved "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.28.2.tgz" integrity sha512-2/1UeE4djz6tt4B0j3YQS+k7BYoMkblfRa3+t3lht9N5/yj05ZxVUiP7hD0lQtNmeCSQgFFmtX6zXWPes+aKQg== -"@cosmjs/utils@^0.29.5": - version "0.29.5" - resolved "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.29.5.tgz" - integrity sha512-m7h+RXDUxOzEOGt4P+3OVPX7PuakZT3GBmaM/Y2u+abN3xZkziykD/NvedYFvvCCdQo714XcGl33bwifS9FZPQ== - "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" @@ -609,7 +609,7 @@ resolved "https://registry.npmjs.org/@improbable-eng/grpc-web-node-http-transport/-/grpc-web-node-http-transport-0.15.0.tgz" integrity sha512-HLgJfVolGGpjc9DWPhmMmXJx8YGzkek7jcCFO1YYkSOoO81MWRZentPOd/JiKiZuU08wtc4BG+WNuGzsQB5jZA== -"@improbable-eng/grpc-web@^0.15.0": +"@improbable-eng/grpc-web@^0.15.0", "@improbable-eng/grpc-web@>=0.13.0": version "0.15.0" resolved "https://registry.npmjs.org/@improbable-eng/grpc-web/-/grpc-web-0.15.0.tgz" integrity sha512-ERft9/0/8CmYalqOVnJnpdDry28q+j+nAlFFARdjyxXDJ+Mhgv9+F600QC8BR9ygOfrXRlAk6CvST2j+JCpQPg== @@ -812,7 +812,7 @@ slash "^3.0.0" write-file-atomic "^4.0.2" -"@jest/types@^29.6.3": +"@jest/types@^29.0.0", "@jest/types@^29.6.3": version "29.6.3" resolved "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz" integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== @@ -864,14 +864,6 @@ resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== -"@jridgewell/trace-mapping@0.3.9": - version "0.3.9" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" - integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.14", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.9": version "0.3.19" resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz" @@ -880,6 +872,14 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@noble/hashes@^1", "@noble/hashes@^1.0.0", "@noble/hashes@^1.2.0": version "1.3.0" resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz" @@ -893,7 +893,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": +"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": version "2.0.5" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -1732,18 +1732,6 @@ resolved "https://registry.npmjs.org/@stdlib/math-base-special-gamma-lanczos-sum-expg-scaled/-/math-base-special-gamma-lanczos-sum-expg-scaled-0.0.7.tgz" integrity sha512-zjdpS8owElpxosiEs78XawbJ/+pvMsUdEN7ThLiGpTToSqffb/L9FGlD3uD/LiXHgiqs4CwsU1xBaX8cI6tn2A== -"@stdlib/math-base-special-gamma1pm1@^0.0.x": - version "0.0.6" - resolved "https://registry.npmjs.org/@stdlib/math-base-special-gamma1pm1/-/math-base-special-gamma1pm1-0.0.6.tgz" - integrity sha512-MAyGncYTJjdSAUCjezMq9ah+hEc4A3yiyTmBMtJ60xkFzRiMOgI+KZV8Yb3brtRWtMayGmRsarqbroXeAnzJKQ== - dependencies: - "@stdlib/constants-float64-eps" "^0.0.x" - "@stdlib/math-base-assert-is-nan" "^0.0.x" - "@stdlib/math-base-special-expm1" "^0.0.x" - "@stdlib/math-base-special-gamma" "^0.0.x" - "@stdlib/math-base-special-ln" "^0.0.x" - "@stdlib/math-base-special-log1p" "^0.0.x" - "@stdlib/math-base-special-gamma@^0.0.x": version "0.0.6" resolved "https://registry.npmjs.org/@stdlib/math-base-special-gamma/-/math-base-special-gamma-0.0.6.tgz" @@ -1763,6 +1751,18 @@ "@stdlib/math-base-special-pow" "^0.0.x" "@stdlib/math-base-special-sin" "^0.0.x" +"@stdlib/math-base-special-gamma1pm1@^0.0.x": + version "0.0.6" + resolved "https://registry.npmjs.org/@stdlib/math-base-special-gamma1pm1/-/math-base-special-gamma1pm1-0.0.6.tgz" + integrity sha512-MAyGncYTJjdSAUCjezMq9ah+hEc4A3yiyTmBMtJ60xkFzRiMOgI+KZV8Yb3brtRWtMayGmRsarqbroXeAnzJKQ== + dependencies: + "@stdlib/constants-float64-eps" "^0.0.x" + "@stdlib/math-base-assert-is-nan" "^0.0.x" + "@stdlib/math-base-special-expm1" "^0.0.x" + "@stdlib/math-base-special-gamma" "^0.0.x" + "@stdlib/math-base-special-ln" "^0.0.x" + "@stdlib/math-base-special-log1p" "^0.0.x" + "@stdlib/math-base-special-gammainc@^0.0.6": version "0.0.6" resolved "https://registry.npmjs.org/@stdlib/math-base-special-gammainc/-/math-base-special-gammainc-0.0.6.tgz" @@ -2486,23 +2486,18 @@ resolved "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz" integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== -"@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0": - version "17.0.31" - resolved "https://registry.npmjs.org/@types/node/-/node-17.0.31.tgz" - integrity sha512-AR0x5HbXGqkEx9CadRH3EBYx/VkiUgZIhP4wvPn/+5KIsgpNoyFaRlVe0Zlx9gRtg8fA06a9tskE2MSN7TcG4Q== +"@types/node@*", "@types/node@^20.10.1", "@types/node@>=12.12.47", "@types/node@>=13.7.0": + version "20.10.3" + resolved "https://registry.npmjs.org/@types/node/-/node-20.10.3.tgz" + integrity sha512-XJavIpZqiXID5Yxnxv3RUDKTN5b81ddNC3ecsA0SoFXz/QU8OGBwZGMomiq0zw+uuqbL/krztv/DINAQ/EV4gg== + dependencies: + undici-types "~5.26.4" "@types/node@^13.7.0": version "13.13.52" resolved "https://registry.npmjs.org/@types/node/-/node-13.13.52.tgz" integrity sha512-s3nugnZumCC//n4moGGe6tkNMyYEdaDBitVjwPxXmR5lnMG5dHePinH2EdxkG3Rh1ghFHHixAG4NJhpJW1rthQ== -"@types/node@^20.10.1": - version "20.10.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.1.tgz#d2c96f356c3125fedc983d74c424910c3767141c" - integrity sha512-T2qwhjWwGH81vUEx4EXmBKsTJRXFXNZTL4v0gi01+zyBmCwzE6TyHszqX01m+QHTEq+EZNo13NeJIdEqf+Myrg== - dependencies: - undici-types "~5.26.4" - "@types/object-hash@^1.3.0": version "1.3.4" resolved "https://registry.npmjs.org/@types/object-hash/-/object-hash-1.3.4.tgz" @@ -2550,7 +2545,7 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/parser@^5.45.0": +"@typescript-eslint/parser@^5.0.0", "@typescript-eslint/parser@^5.45.0": version "5.46.0" resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.46.0.tgz" integrity sha512-joNO6zMGUZg+C73vwrKXCd8usnsmOYmgW/w5ZW0pG0RGvqeznjtGDk61EqqTpNrFLUYBW2RSBFrxdAZMqA4OZA== @@ -2781,7 +2776,7 @@ acorn-walk@^8.1.1: resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== -acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.1, acorn@^8.8.0: +"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8, acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.1, acorn@^8.8.0: version "8.8.1" resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz" integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA== @@ -2796,7 +2791,7 @@ ajv-keywords@^3.5.2: resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5: +ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5, ajv@^6.9.1: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -2888,7 +2883,7 @@ axios@^0.21.2: dependencies: follow-redirects "^1.14.0" -babel-jest@^29.7.0: +babel-jest@^29.0.0, babel-jest@^29.7.0: version "29.7.0" resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz" integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== @@ -3025,7 +3020,7 @@ browser-headers@^0.4.1: resolved "https://registry.npmjs.org/browser-headers/-/browser-headers-0.4.1.tgz" integrity sha512-CA9hsySZVo9371qEHjHZtYxV2cFtVj5Wj/ZHi8ooEsrtm4vOnl9Y9HmyYWk9q+05d7K3rdoAE0j3MVEFVvtQtg== -browserslist@^4.14.5, browserslist@^4.21.3: +browserslist@^4.14.5, browserslist@^4.21.3, "browserslist@>= 4.21.0": version "4.21.4" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz" integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw== @@ -3123,14 +3118,6 @@ case-anything@^2.1.10: resolved "https://registry.npmjs.org/case-anything/-/case-anything-2.1.10.tgz" integrity sha512-JczJwVrCP0jPKh05McyVsuOg6AYosrB9XWZKbQzXeDAm2ClE/PJE/BcrrQrVyGYH7Jg8V/LDupmyL4kFlVsVFQ== -chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.2: - version "4.1.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - chalk@^2.0.0: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" @@ -3140,6 +3127,14 @@ chalk@^2.0.0: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^4.0.0, chalk@^4.1.2, chalk@4.1.2: + version "4.1.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + char-regex@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz" @@ -3218,22 +3213,27 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - color-name@~1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + colorette@^2.0.14: version "2.0.19" resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz" integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== -commander@^2.20.0, commander@^2.8.1: +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^2.8.1: version "2.20.3" resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -3565,7 +3565,12 @@ escalade@^3.1.1: resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.2: + version "1.0.5" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== @@ -3592,7 +3597,7 @@ eslint-plugin-prettier@^4.2.1: dependencies: prettier-linter-helpers "^1.0.0" -eslint-scope@5.1.1, eslint-scope@^5.1.1: +eslint-scope@^5.1.1, eslint-scope@5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== @@ -3625,7 +3630,7 @@ eslint-visitor-keys@^3.3.0: resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@^8.29.0: +eslint@*, "eslint@^6.0.0 || ^7.0.0 || ^8.0.0", eslint@^8.29.0, eslint@>=5, eslint@>=7.0.0, eslint@>=7.28.0: version "8.29.0" resolved "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz" integrity sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg== @@ -3790,7 +3795,7 @@ fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: +fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0, fast-json-stable-stringify@2.x: version "2.1.0" resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -3931,11 +3936,6 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^2.3.2: - version "2.3.3" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - function-bind@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" @@ -3965,11 +3965,6 @@ get-package-type@^0.1.0: resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== -get-stream@3.0.0, get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz" - integrity sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ== - get-stream@^2.2.0: version "2.3.1" resolved "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz" @@ -3978,6 +3973,11 @@ get-stream@^2.2.0: object-assign "^4.0.1" pinkie-promise "^2.0.0" +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz" + integrity sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ== + get-stream@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz" @@ -3990,6 +3990,11 @@ get-stream@^6.0.0: resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +get-stream@3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz" + integrity sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ== + glob-parent@^5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" @@ -4052,7 +4057,7 @@ globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" -google-protobuf@^3.15.5, google-protobuf@^3.21.2: +google-protobuf@^3.14.0, google-protobuf@^3.15.5, google-protobuf@^3.21.2: version "3.21.2" resolved "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz" integrity sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA== @@ -4263,7 +4268,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: +inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3, inherits@2: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -4647,7 +4652,7 @@ jest-resolve-dependencies@^29.7.0: jest-regex-util "^29.6.3" jest-snapshot "^29.7.0" -jest-resolve@^29.7.0: +jest-resolve@*, jest-resolve@^29.7.0: version "29.7.0" resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz" integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== @@ -4800,7 +4805,7 @@ jest-worker@^29.7.0: merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^29.3.1: +jest@^29.0.0, jest@^29.3.1: version "29.7.0" resolved "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz" integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== @@ -4966,16 +4971,16 @@ long@^5.0.0, long@^5.2.1: resolved "https://registry.npmjs.org/long/-/long-5.2.1.tgz" integrity sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A== -lowercase-keys@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz" - integrity sha512-RPlX0+PHuvxVDZ7xX+EBVAp4RsVxP/TdDSN2mJYdiq1Lc4Hz7EUSjUI7RZrKKlmrIzVhf6Jo2stj7++gVarS0A== - lowercase-keys@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz" integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== +lowercase-keys@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz" + integrity sha512-RPlX0+PHuvxVDZ7xX+EBVAp4RsVxP/TdDSN2mJYdiq1Lc4Hz7EUSjUI7RZrKKlmrIzVhf6Jo2stj7++gVarS0A== + lru-cache@^10.0.1: version "10.0.1" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz" @@ -5010,7 +5015,7 @@ make-dir@^4.0.0: dependencies: semver "^7.5.3" -make-error@1.x, make-error@^1.1.1: +make-error@^1.1.1, make-error@1.x: version "1.3.6" resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== @@ -5040,7 +5045,7 @@ micromatch@^4.0.4: braces "^3.0.2" picomatch "^2.3.1" -mime-db@1.52.0, mime-db@^1.28.0: +mime-db@^1.28.0, mime-db@1.52.0: version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== @@ -5096,6 +5101,11 @@ mkdirp@^0.5.6: dependencies: minimist "^1.2.6" +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + ms@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" @@ -5106,11 +5116,6 @@ ms@2.1.2: resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.1.1: - version "2.1.3" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - natural-compare-lite@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz" @@ -5387,7 +5392,7 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@^2.8.0: +prettier@^2.8.0, prettier@>=2.0.0: version "2.8.0" resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.0.tgz" integrity sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA== @@ -5414,7 +5419,26 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -protobufjs@^6.11.3, protobufjs@^6.8.8, protobufjs@~6.11.2: +protobufjs@^6.11.3: + version "6.11.3" + resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz" + integrity sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/long" "^4.0.1" + "@types/node" ">=13.7.0" + long "^4.0.0" + +protobufjs@^6.8.8: version "6.11.3" resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz" integrity sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg== @@ -5470,6 +5494,25 @@ protobufjs@~6.10.2: "@types/node" "^13.7.0" long "^4.0.0" +protobufjs@~6.11.2: + version "6.11.3" + resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz" + integrity sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/long" "^4.0.1" + "@types/node" ">=13.7.0" + long "^4.0.0" + protoc-gen-js@^3.21.2: version "3.21.2" resolved "https://registry.npmjs.org/protoc-gen-js/-/protoc-gen-js-3.21.2.tgz" @@ -5534,7 +5577,33 @@ react-is@^18.0.0: resolved "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== -readable-stream@^2.0.0, readable-stream@^2.3.0, readable-stream@^2.3.5: +readable-stream@^2.0.0: + version "2.3.8" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^2.3.0: + version "2.3.8" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^2.3.5: version "2.3.8" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -5655,15 +5724,20 @@ rxjs@^7.5.7: dependencies: tslib "^2.1.0" -safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.2.0, safe-buffer@~5.2.0, safe-buffer@5.2.1: + version "5.2.1" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.2.0, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +safe-buffer@5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" @@ -5696,13 +5770,6 @@ seek-bzip@^1.0.5: dependencies: commander "^2.8.1" -semver@7.x, semver@^7.3.7, semver@^7.5.3, semver@^7.5.4: - version "7.5.4" - resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz" - integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== - dependencies: - lru-cache "^6.0.0" - semver@^5.6.0: version "5.7.2" resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" @@ -5713,6 +5780,13 @@ semver@^6.3.0: resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^7.3.7, semver@^7.5.3, semver@^7.5.4, semver@7.x: + version "7.5.4" + resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + serialize-javascript@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz" @@ -5783,14 +5857,6 @@ sort-keys@^2.0.0: dependencies: is-plain-obj "^1.0.0" -source-map-support@0.5.13: - version "0.5.13" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz" - integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" @@ -5799,6 +5865,14 @@ source-map-support@~0.5.20: buffer-from "^1.0.0" source-map "^0.6.0" +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map@^0.6.0, source-map@^0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" @@ -5821,6 +5895,20 @@ strict-uri-encode@^1.0.0: resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz" integrity sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ== +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + string-length@^4.0.1: version "4.0.2" resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz" @@ -5838,20 +5926,6 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" @@ -6025,7 +6099,7 @@ ts-jest@^29.0.3: semver "7.x" yargs-parser "^21.0.1" -ts-node@^10.9.1: +ts-node@^10.9.1, ts-node@>=9.0.0: version "10.9.1" resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz" integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== @@ -6118,7 +6192,7 @@ type-fest@^0.21.3: resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== -typescript@^4.8.4: +typescript@^4.8.4, typescript@>=2.7, "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta", typescript@>=4.3: version "4.8.4" resolved "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz" integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== @@ -6133,7 +6207,7 @@ unbzip2-stream@^1.0.9: undici-types@~5.26.4: version "5.26.5" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== union@~0.5.0: @@ -6209,7 +6283,7 @@ watchpack@^2.4.0: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" -webpack-cli@^4.10.0: +webpack-cli@^4.10.0, webpack-cli@4.x.x: version "4.10.0" resolved "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz" integrity sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w== @@ -6240,7 +6314,7 @@ webpack-sources@^3.2.3: resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@^5.74.0: +webpack@^5.1.0, webpack@^5.74.0, "webpack@4.x.x || 5.x.x": version "5.74.0" resolved "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz" integrity sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA== @@ -6316,7 +6390,7 @@ write-file-atomic@^4.0.2: imurmurhash "^0.1.4" signal-exit "^3.0.7" -ws@^7: +ws@*, ws@^7: version "7.5.9" resolved "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz" integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== diff --git a/protocol/lavasession/errors.go b/protocol/lavasession/errors.go index 0361deda7e..cd61818680 100644 --- a/protocol/lavasession/errors.go +++ b/protocol/lavasession/errors.go @@ -17,7 +17,7 @@ var ( // Consumer Side Errors NegativeComputeUnitsAmountError = sdkerrors.New("NegativeComputeUnitsAmount", 674, "Tried to subtract to negative compute units amount") ReportAndBlockProviderError = sdkerrors.New("ReportAndBlockProvider Error", 675, "Report and block the provider") BlockProviderError = sdkerrors.New("BlockProvider Error", 676, "Block the provider") - SessionOutOfSyncError = sdkerrors.New("SessionOutOfSync Error", 677, "Session went out of sync with the provider") + SessionOutOfSyncError = sdkerrors.New("SessionOutOfSync Error", 677, "Session went out of sync with the provider") // do no change the name, before also fixing the consumerSessionManager.ts file as it relies on the error message MaximumNumberOfBlockListedSessionsError = sdkerrors.New("MaximumNumberOfBlockListedSessions Error", 678, "Provider reached maximum number of block listed sessions.") SendRelayError = sdkerrors.New("SendRelay Error", 679, "Failed To Send Relay") DataReliabilityIndexRequestedIsOriginalProviderError = sdkerrors.New("DataReliabilityIndexRequestedIsOriginalProvider Error", 680, "Data reliability session index belongs to the original provider") diff --git a/testutil/e2e/README.md b/testutil/e2e/README.md index 6cd7da0960..c62ceb3db0 100644 --- a/testutil/e2e/README.md +++ b/testutil/e2e/README.md @@ -1,7 +1,8 @@ # Lava E2E + If you wish you can also run E2E tests independently -## Lava Protocol E2 +## Lava Protocol E2E ``` go test ./testutil/e2e/ -run ^TestLavaProtocol$ -v -timeout 1200s @@ -9,20 +10,34 @@ go test ./testutil/e2e/ -run ^TestLavaProtocol$ -v -timeout 1200s ## Lava SDK E2E -If this is the first time you run the e2e after fetching a branch and you didn't compile the protobufs first run +If this is the first time you run the e2e after fetching a branch and you didn't compile the protobufs first run: + +(Make sure that GOPATH is defined in your environment) + +Init and build the SDK: ```bash -cd ecosystem/lava-sdk; ./init_sdk.sh +cd ecosystem/lava-sdk +./scripts/init_sdk.sh +yarn build +cd - +``` + +Build lavajs: + +```bash +cd ./ecosystem/lavajs +yarn e2e-setup +cd - ``` Now you can run the test running: + ```bash -yarn --cwd ./ecosystem/lava-sdk/ build; yarn --cwd ./ecosystem/lavajs/ e2e-setup; go test ./testutil/e2e/ -run ^TestLavaSDK -v -timeout 1200s ``` --------------------- - +--- ## Run all our E2E using the following command (from the root) {NOT STABLE} @@ -31,7 +46,6 @@ yarn --cwd ./ecosystem/lava-sdk/ build; yarn --cwd ./ecosystem/lavajs/ e2e-setup go test ./testutil/e2e/ -v -timeout 1200s ``` - This E2E performs the steps below to test if the system is working as expected. 1. Start lava in developer mode (equivalent to running the command "ignite chain serve" ). @@ -59,4 +73,4 @@ After the steps above are finished (even if a step fails and the E2E ends) the E # Allowed Error List -The allowed error list contains a list of errors that is allowed to happen during tests. The key is the error substring that can be seen in the logs. The value is the description on why this error is allowed. +The allowed error list contains a list of errors that is allowed to happen during tests. The key is the error substring that can be seen in the logs. The value is the description on why this error is allowed. diff --git a/testutil/e2e/allowedErrorList.go b/testutil/e2e/allowedErrorList.go index 7deb2cdb21..93e55680f1 100644 --- a/testutil/e2e/allowedErrorList.go +++ b/testutil/e2e/allowedErrorList.go @@ -9,5 +9,4 @@ var allowedErrors = map[string]string{ "purging provider after all endpoints are disabled provider": "This error is allowed because it is caused by the initial bootup, continuous failure would be caught by the e2e so we can allowed this error.", "Provider Side Failed Sending Message, Reason: Unavailable": "This error is allowed because it is caused by the lavad restart to turn on emergency mode", "Maximum cu exceeded PrepareSessionForUsage": "This error is allowed because it is caused by switching between providers, continuous failure would be caught by the e2e so we can allowed this error.", - "Trying to update provider list for older epoch": "This error is allowed because it is caused by virtual epoch having started and epoch not having changed", } diff --git a/testutil/e2e/sdk/tests/common.ts b/testutil/e2e/sdk/tests/common.ts new file mode 100644 index 0000000000..38a9cf4ee3 --- /dev/null +++ b/testutil/e2e/sdk/tests/common.ts @@ -0,0 +1,3 @@ +export function delay(ms: number) { + return new Promise( resolve => setTimeout(resolve, ms) ); +} \ No newline at end of file diff --git a/testutil/e2e/sdk/tests/emergency_mode_badge.ts b/testutil/e2e/sdk/tests/emergency_mode_badge.ts index 6838c9533e..c01cc3e6e7 100644 --- a/testutil/e2e/sdk/tests/emergency_mode_badge.ts +++ b/testutil/e2e/sdk/tests/emergency_mode_badge.ts @@ -1,9 +1,5 @@ import { LavaSDK } from "../../../../ecosystem/lava-sdk/bin/src/sdk/sdk" - -function delay(ms: number) { - return new Promise( resolve => setTimeout(resolve, ms) ); -} - +import { delay } from "./common"; async function main() { // Initialize Lava SDK @@ -38,12 +34,12 @@ async function main() { // Validate chainID if (chainID !== "lava") { - throw new Error(" ERR [tendermintrpc_chainid_fetch_badge] Chain ID is not equal to lava"); + throw new Error(" ERR [emergency_mode_badge] Chain ID is not equal to lava"); } else { - console.log(i, "[tendermintrpc_chainid_fetch_badge] Success: Fetching Lava chain ID using tendermintrpc passed. Chain ID correctly matches 'lava'"); + console.log(i, "[emergency_mode_badge] Success: Fetching Lava chain ID using tendermintrpc passed. Chain ID correctly matches 'lava'"); } } catch (error) { - throw new Error(` ERR ${i} [tendermintrpc_chainid_fetch_badge] failed sending relay tendermint test: ${error.message}`); + throw new Error(` ERR ${i} [emergency_mode_badge] failed sending relay tendermint test: ${error.message}`); } } } @@ -53,7 +49,7 @@ async function main() { await main(); process.exit(0); } catch (error) { - console.error(" ERR [tendermintrpc_chainid_fetch_badge] " + error.message); + console.error(" ERR [emergency_mode_badge] " + error.message); process.exit(1); } })(); \ No newline at end of file diff --git a/testutil/e2e/sdk/tests/emergency_mode_badge_err.ts b/testutil/e2e/sdk/tests/emergency_mode_badge_err.ts index 68c3a8330b..f802ec1ed2 100644 --- a/testutil/e2e/sdk/tests/emergency_mode_badge_err.ts +++ b/testutil/e2e/sdk/tests/emergency_mode_badge_err.ts @@ -31,12 +31,12 @@ async function main() { // Validate chainID if (chainID !== "lava") { - throw new Error(" ERR [tendermintrpc_chainid_fetch_badge] Chain ID is not equal to lava"); + throw new Error(" ERR [emergency_mode_badge_err] Chain ID is not equal to lava"); } else { - console.log(i, "[tendermintrpc_chainid_fetch_badge_1] Success: Fetching Lava chain ID using tendermintrpc passed. Chain ID correctly matches 'lava'"); + console.log(i, "[emergency_mode_badge_err] Success: Fetching Lava chain ID using tendermintrpc passed. Chain ID correctly matches 'lava'"); } } catch (error) { - throw new Error(` ERR ${i} [tendermintrpc_chainid_fetch_badge] failed sending relay tendermint test: ${error.message}`); + throw new Error(` ERR ${i} [emergency_mode_badge_err] failed sending relay tendermint test: ${error.message}`); } } } @@ -46,7 +46,7 @@ async function main() { await main(); process.exit(0); } catch (error) { - //console.error(" ERR [tendermintrpc_chainid_fetch_badge] " + error.message); - process.exit(1); + //console.error(" ERR [emergency_mode_badge_err] " + error.message); + process.exit(0); } })(); \ No newline at end of file diff --git a/testutil/e2e/sdk/tests/emergency_mode_fetch.ts b/testutil/e2e/sdk/tests/emergency_mode_fetch.ts index 021dcfdb49..2523dc6eec 100644 --- a/testutil/e2e/sdk/tests/emergency_mode_fetch.ts +++ b/testutil/e2e/sdk/tests/emergency_mode_fetch.ts @@ -1,8 +1,5 @@ import { LavaSDK } from "../../../../ecosystem/lava-sdk/bin/src/sdk/sdk" - -function delay(ms: number) { - return new Promise( resolve => setTimeout(resolve, ms) ); -} +import { delay } from "./common"; async function main() { // Initialize Lava SDK @@ -14,7 +11,7 @@ async function main() { allowInsecureTransport: true, logLevel: "debug", }).catch((e) => { - throw new Error(" ERR [tendermintrpc_chainid_fetch] failed setting lava-sdk tendermint test"); + throw new Error(" ERR [emergency_mode_fetch] failed setting lava-sdk tendermint test"); }); await delay(40000); @@ -34,12 +31,12 @@ async function main() { // Validate chainID if (chainID !== "lava") { - throw new Error(" ERR [tendermintrpc_chainid_fetch] Chain ID is not equal to lava"); + throw new Error(" ERR [emergency_mode_fetch] Chain ID is not equal to lava"); } else { - console.log(i, "[tendermintrpc_chainid_fetch] Success: Fetching Lava chain ID using tendermintrpc passed. Chain ID correctly matches 'lava'"); + console.log(i, "[emergency_mode_fetch] Success: Fetching Lava chain ID using tendermintrpc passed. Chain ID correctly matches 'lava'"); } } catch (error) { - throw new Error(` ERR ${i} [tendermintrpc_chainid_fetch] failed sending relay tendermint test: ${error.message}`); + throw new Error(` ERR ${i} [emergency_mode_fetch] failed sending relay tendermint test: ${error.message}`); } } } @@ -49,7 +46,7 @@ async function main() { await main(); process.exit(0); } catch (error) { - console.error(" ERR [tendermintrpc_chainid_fetch] " + error.message); + console.error(" ERR [emergency_mode_fetch] " + error.message); process.exit(1); } })(); \ No newline at end of file diff --git a/testutil/e2e/sdk/tests/emergency_mode_fetch_err.ts b/testutil/e2e/sdk/tests/emergency_mode_fetch_err.ts index 7dc15672c5..936616265f 100644 --- a/testutil/e2e/sdk/tests/emergency_mode_fetch_err.ts +++ b/testutil/e2e/sdk/tests/emergency_mode_fetch_err.ts @@ -1,9 +1,5 @@ import { LavaSDK } from "../../../../ecosystem/lava-sdk/bin/src/sdk/sdk" -function delay(ms: number) { - return new Promise( resolve => setTimeout(resolve, ms) ); -} - async function main() { // Initialize Lava SDK const lavaSDKTendermint = await LavaSDK.create({ @@ -14,7 +10,7 @@ async function main() { allowInsecureTransport: true, logLevel: "debug", }).catch((e) => { - throw new Error(" ERR [tendermintrpc_chainid_fetch] failed setting lava-sdk tendermint test"); + throw new Error(" ERR [emergency_mode_fetch_err] failed setting lava-sdk tendermint test"); }); // Fetch chain id @@ -32,12 +28,12 @@ async function main() { // Validate chainID if (chainID !== "lava") { - throw new Error(" ERR [tendermintrpc_chainid_fetch] Chain ID is not equal to lava"); + throw new Error(" ERR [emergency_mode_fetch_err] Chain ID is not equal to lava"); } else { - console.log(i, "[tendermintrpc_chainid_fetch] Success: Fetching Lava chain ID using tendermintrpc passed. Chain ID correctly matches 'lava'"); + console.log(i, "[emergency_mode_fetch_err] Success: Fetching Lava chain ID using tendermintrpc passed. Chain ID correctly matches 'lava'"); } } catch (error) { - throw new Error(` ERR ${i} [tendermintrpc_chainid_fetch] failed sending relay tendermint test: ${error.message}`); + throw new Error(` ERR ${i} [emergency_mode_fetch_err] failed sending relay tendermint test: ${error.message}`); } } } @@ -47,7 +43,8 @@ async function main() { await main(); process.exit(0); } catch (error) { - //console.error(" ERR [tendermintrpc_chainid_fetch] " + error.message); - process.exit(1); + // This is a _err script, meaning it desires an error + // Therefore, a failure is acceptable + process.exit(0); } })(); \ No newline at end of file diff --git a/testutil/e2e/sdk/tests/package.json b/testutil/e2e/sdk/tests/package.json index 65a183796d..0934d6b90d 100644 --- a/testutil/e2e/sdk/tests/package.json +++ b/testutil/e2e/sdk/tests/package.json @@ -1,5 +1,5 @@ { - "dependencies": { - "@types/node": "^20.7.1" + "devDependencies": { + "@types/node": "^20.10.3" } } diff --git a/testutil/e2e/sdkE2E.go b/testutil/e2e/sdkE2E.go index 4feb2285a3..9b53219749 100644 --- a/testutil/e2e/sdkE2E.go +++ b/testutil/e2e/sdkE2E.go @@ -151,94 +151,90 @@ func runSDKE2E(timeout time.Duration) { lt.logs["01_sdkTest"] = new(bytes.Buffer) sdk.RunSDKTests(ctx, grpcConn, privateKey, publicKey, lt.logs["01_sdkTest"], "7070") - /* - // ++++++++++ Uncomment After fix +++++++++++ - // Emergency mode tests - utils.LavaFormatInfo("Sleeping Until New Epoch") - lt.sleepUntilNextEpoch() + // Emergency mode tests + utils.LavaFormatInfo("Sleeping Until New Epoch") + lt.sleepUntilNextEpoch() - utils.LavaFormatInfo("Restarting lava to emergency mode") + utils.LavaFormatInfo("Restarting lava to emergency mode") - // wait 3 seconds to allow rpcproviders claim rewards before node will be restarted(after restarting node - // we have ctx.BlockHeight == 0, until new block will be created) - time.Sleep(time.Second * 3) + // wait 3 seconds to allow rpcproviders claim rewards before node will be restarted(after restarting node + // we have ctx.BlockHeight == 0, until new block will be created) + time.Sleep(time.Second * 3) - lt.stopLava() - go lt.startLavaInEmergencyMode(lavaContext, 100000) + lt.stopLava() + go lt.startLavaInEmergencyMode(lavaContext, 100000) - lt.checkLava(timeout) - utils.LavaFormatInfo("Starting Lava OK") - - var epochDuration int64 = 20 * 1.2 - signalChannel := make(chan bool) - latestBlockTime := lt.getLatestBlockTime() + lt.checkLava(timeout) + utils.LavaFormatInfo("Starting Lava OK") - go func() { - epochCounter := (time.Now().Unix() - latestBlockTime.Unix()) / epochDuration + var epochDuration int64 = 20 * 1.2 + signalChannel := make(chan bool) + latestBlockTime := lt.getLatestBlockTime() - for { - time.Sleep(time.Until(latestBlockTime.Add(time.Second * time.Duration(epochDuration*(epochCounter+1))))) - utils.LavaFormatInfo(fmt.Sprintf("%d : VIRTUAL EPOCH ENDED", epochCounter)) + go func() { + epochCounter := (time.Now().Unix() - latestBlockTime.Unix()) / epochDuration - epochCounter++ - signalChannel <- true - } - }() + for { + time.Sleep(time.Until(latestBlockTime.Add(time.Second * time.Duration(epochDuration*(epochCounter+1))))) + utils.LavaFormatInfo(fmt.Sprintf("%d : VIRTUAL EPOCH ENDED", epochCounter)) + epochCounter++ + signalChannel <- true + } + }() - utils.LavaFormatInfo("Waiting for finishing current epoch 1") + utils.LavaFormatInfo("Waiting for finishing current epoch 1") - // we should have approximately (numOfProviders * epoch_cu_limit * 2) CU - // skip current epoch - <-signalChannel + // we should have approximately (numOfProviders * epoch_cu_limit * 2) CU + // skip current epoch + <-signalChannel - privateKey = exportUserPrivateKey(lt.lavadPath, "user5") - publicKey = exportUserPublicKey(lt.lavadPath, "user5") - lt.startBadgeServer(ctx, privateKey, publicKey, "5050", "60") + privateKey = exportUserPrivateKey(lt.lavadPath, "user5") + publicKey = exportUserPublicKey(lt.lavadPath, "user5") + lt.startBadgeServer(ctx, privateKey, publicKey, "5050", "60") - defer func() { - // Delete the file directly without checking if it exists - os.Remove("testutil/e2e/sdk/pairingList.json") - }() - sdk.GeneratePairingList(grpcConn, ctx) + defer func() { + // Delete the file directly without checking if it exists + os.Remove("testutil/e2e/sdk/pairingList.json") + }() + sdk.GeneratePairingList(grpcConn, ctx) - // Test without badge server - utils.LavaFormatInfo("Waiting for finishing current epoch 2") - err = sdk.RunSDKTest("testutil/e2e/sdk/tests/emergency_mode_fetch.ts", privateKey, publicKey, lt.logs["01_sdkTest"], "5050") - if err != nil { - panic(fmt.Sprintf("Test File failed: %s\n", "testutil/e2e/sdk/tests/emergency_mode_fetch.ts")) - } + // Test without badge server + utils.LavaFormatInfo("Waiting for finishing current epoch 2") + err = sdk.RunSDKTest("testutil/e2e/sdk/tests/emergency_mode_fetch.ts", privateKey, publicKey, lt.logs["01_sdkTest"], "5050") + if err != nil { + panic(fmt.Sprintf("Test File failed: %s\n", "testutil/e2e/sdk/tests/emergency_mode_fetch.ts")) + } - // Trying to exceed CU limit - err = sdk.RunSDKTest("testutil/e2e/sdk/tests/emergency_mode_fetch_err.ts", privateKey, publicKey, lt.logs["01_sdkTest"], "5050") - if err == nil { - panic(fmt.Sprintf("Test File failed while trying to exceed CU limit: %s\n", "testutil/e2e/sdk/tests/emergency_mode_fetch_err.ts")) - } + // Trying to exceed CU limit + err = sdk.RunSDKTest("testutil/e2e/sdk/tests/emergency_mode_fetch_err.ts", privateKey, publicKey, lt.logs["01_sdkTest"], "5050") + if err != nil { + panic(fmt.Sprintf("Test File failed while trying to exceed CU limit: %s\n", "testutil/e2e/sdk/tests/emergency_mode_fetch_err.ts")) + } - utils.LavaFormatInfo("KEYS EMERGENCY MODE TEST OK") + utils.LavaFormatInfo("KEYS EMERGENCY MODE TEST OK") - utils.LavaFormatInfo("Waiting for finishing current epoch 3") + utils.LavaFormatInfo("Waiting for finishing current epoch 3") - // we should have approximately (numOfProviders * epoch_cu_limit * 3) CU - // skip current epoch - <-signalChannel - <-signalChannel - <-signalChannel + // we should have approximately (numOfProviders * epoch_cu_limit * 3) CU + // skip current epoch + <-signalChannel + <-signalChannel + <-signalChannel - // Test with badge server - err = sdk.RunSDKTest("testutil/e2e/sdk/tests/emergency_mode_badge.ts", privateKey, publicKey, lt.logs["01_sdkTest"], "5050") - if err != nil { - panic(fmt.Sprintf("Test File failed: %s\n", "testutil/e2e/sdk/tests/emergency_mode_badge.ts")) - } + // Test with badge server + err = sdk.RunSDKTest("testutil/e2e/sdk/tests/emergency_mode_badge.ts", privateKey, publicKey, lt.logs["01_sdkTest"], "5050") + if err != nil { + panic(fmt.Sprintf("Test File failed: %s\n", "testutil/e2e/sdk/tests/emergency_mode_badge.ts")) + } - // Trying to exceed CU limit - err = sdk.RunSDKTest("testutil/e2e/sdk/tests/emergency_mode_badge_err.ts", privateKey, publicKey, lt.logs["01_sdkTest"], "5050") - if err == nil { - panic(fmt.Sprintf("Test File failed while trying to exceed CU limit: %s\n", "testutil/e2e/sdk/tests/emergency_mode_badge_err.ts")) - } + // Trying to exceed CU limit + err = sdk.RunSDKTest("testutil/e2e/sdk/tests/emergency_mode_badge_err.ts", privateKey, publicKey, lt.logs["01_sdkTest"], "5050") + if err != nil { + panic(fmt.Sprintf("Test File failed while trying to exceed CU limit: %s\n", "testutil/e2e/sdk/tests/emergency_mode_badge_err.ts")) + } - utils.LavaFormatInfo("BADGE EMERGENCY MODE TEST OK") + utils.LavaFormatInfo("BADGE EMERGENCY MODE TEST OK") - */ lt.finishTestSuccessfully() // Cancel lava network using context From 8d8d5f615cc870e34b109ca3fd54ebb16eab2ebd Mon Sep 17 00:00:00 2001 From: Elad Gildnur <6321801+shleikes@users.noreply.github.com> Date: Tue, 5 Dec 2023 05:07:20 -0500 Subject: [PATCH 34/85] CNS-729 Verification on spec change (#1002) * Add unique name to spec updatable * Wrap relay receiver with enabled flag * Add SpecValidator and use it in RpcProvider PRT-1020 * Fix lint * CNS-739 - Add test for enabling receiver --- go.mod | 2 +- go.sum | 5 +- protocol/badgegenerator/server.go | 4 + protocol/chainlib/chain_fetcher_mock.go | 98 +++++++++++ protocol/chainlib/chainlib.go | 1 + protocol/chainlib/grpc.go | 4 + protocol/chainlib/jsonRPC.go | 4 + protocol/chainlib/rest.go | 4 + protocol/chainlib/tendermintRPC.go | 4 + protocol/rpcprovider/provider_listener.go | 16 +- .../rpcprovider/provider_listener_mock.go | 84 ++++++++++ protocol/rpcprovider/rpcprovider.go | 42 +++-- protocol/rpcprovider/spec_validator.go | 155 ++++++++++++++++++ protocol/rpcprovider/spec_validator_test.go | 151 +++++++++++++++++ protocol/statetracker/spec_updater.go | 12 +- 15 files changed, 562 insertions(+), 24 deletions(-) create mode 100644 protocol/chainlib/chain_fetcher_mock.go create mode 100644 protocol/rpcprovider/provider_listener_mock.go create mode 100644 protocol/rpcprovider/spec_validator.go create mode 100644 protocol/rpcprovider/spec_validator_test.go diff --git a/go.mod b/go.mod index fc2626855b..23ae3f87b0 100644 --- a/go.mod +++ b/go.mod @@ -40,6 +40,7 @@ require ( github.com/spf13/pflag v1.0.5 github.com/tidwall/gjson v1.16.0 github.com/tidwall/sjson v1.2.5 + go.uber.org/mock v0.3.0 gonum.org/v1/gonum v0.13.0 google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e gopkg.in/natefinch/lumberjack.v2 v2.2.1 @@ -100,7 +101,6 @@ require ( github.com/tidwall/pretty v1.2.0 // indirect github.com/ulikunitz/xz v0.5.11 // indirect github.com/zondax/ledger-go v0.14.1 // indirect - golang.org/x/mod v0.9.0 // indirect golang.org/x/oauth2 v0.10.0 // indirect google.golang.org/api v0.126.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 7dc122f7e5..7954a370ef 100644 --- a/go.sum +++ b/go.sum @@ -1269,6 +1269,8 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= +go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= @@ -1350,8 +1352,7 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/protocol/badgegenerator/server.go b/protocol/badgegenerator/server.go index ce81371d92..e57ff6fbee 100644 --- a/protocol/badgegenerator/server.go +++ b/protocol/badgegenerator/server.go @@ -60,6 +60,10 @@ func NewServer(ipService *IpService, grpcUrl, chainId, userData string) (*Server return server, nil } +func (s *Server) GetUniqueName() string { + return "badge_server" +} + func (s *Server) InitializeStateTracker(tracker *BadgeStateTracker) { if s.stateTracker != nil { utils.LavaFormatFatal("state tracker already initialized", nil) diff --git a/protocol/chainlib/chain_fetcher_mock.go b/protocol/chainlib/chain_fetcher_mock.go new file mode 100644 index 0000000000..0de5103435 --- /dev/null +++ b/protocol/chainlib/chain_fetcher_mock.go @@ -0,0 +1,98 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: protocol/chainlib/chain_fetcher.go +// +// Generated by this command: +// +// mockgen -source=protocol/chainlib/chain_fetcher.go -destination protocol/chainlib/chain_fetcher_mock.go -package chainlib +// +// Package chainlib is a generated GoMock package. +package chainlib + +import ( + context "context" + reflect "reflect" + + lavasession "github.com/lavanet/lava/protocol/lavasession" + gomock "go.uber.org/mock/gomock" +) + +// MockChainFetcherIf is a mock of ChainFetcherIf interface. +type MockChainFetcherIf struct { + ctrl *gomock.Controller + recorder *MockChainFetcherIfMockRecorder +} + +// MockChainFetcherIfMockRecorder is the mock recorder for MockChainFetcherIf. +type MockChainFetcherIfMockRecorder struct { + mock *MockChainFetcherIf +} + +// NewMockChainFetcherIf creates a new mock instance. +func NewMockChainFetcherIf(ctrl *gomock.Controller) *MockChainFetcherIf { + mock := &MockChainFetcherIf{ctrl: ctrl} + mock.recorder = &MockChainFetcherIfMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockChainFetcherIf) EXPECT() *MockChainFetcherIfMockRecorder { + return m.recorder +} + +// FetchBlockHashByNum mocks base method. +func (m *MockChainFetcherIf) FetchBlockHashByNum(ctx context.Context, blockNum int64) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FetchBlockHashByNum", ctx, blockNum) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FetchBlockHashByNum indicates an expected call of FetchBlockHashByNum. +func (mr *MockChainFetcherIfMockRecorder) FetchBlockHashByNum(ctx, blockNum any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchBlockHashByNum", reflect.TypeOf((*MockChainFetcherIf)(nil).FetchBlockHashByNum), ctx, blockNum) +} + +// FetchEndpoint mocks base method. +func (m *MockChainFetcherIf) FetchEndpoint() lavasession.RPCProviderEndpoint { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FetchEndpoint") + ret0, _ := ret[0].(lavasession.RPCProviderEndpoint) + return ret0 +} + +// FetchEndpoint indicates an expected call of FetchEndpoint. +func (mr *MockChainFetcherIfMockRecorder) FetchEndpoint() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchEndpoint", reflect.TypeOf((*MockChainFetcherIf)(nil).FetchEndpoint)) +} + +// FetchLatestBlockNum mocks base method. +func (m *MockChainFetcherIf) FetchLatestBlockNum(ctx context.Context) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FetchLatestBlockNum", ctx) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FetchLatestBlockNum indicates an expected call of FetchLatestBlockNum. +func (mr *MockChainFetcherIfMockRecorder) FetchLatestBlockNum(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchLatestBlockNum", reflect.TypeOf((*MockChainFetcherIf)(nil).FetchLatestBlockNum), ctx) +} + +// Validate mocks base method. +func (m *MockChainFetcherIf) Validate(ctx context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Validate", ctx) + ret0, _ := ret[0].(error) + return ret0 +} + +// Validate indicates an expected call of Validate. +func (mr *MockChainFetcherIfMockRecorder) Validate(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Validate", reflect.TypeOf((*MockChainFetcherIf)(nil).Validate), ctx) +} diff --git a/protocol/chainlib/chainlib.go b/protocol/chainlib/chainlib.go index 05773b9086..19ca1464cd 100644 --- a/protocol/chainlib/chainlib.go +++ b/protocol/chainlib/chainlib.go @@ -62,6 +62,7 @@ type ChainParser interface { Active() bool Activate() UpdateBlockTime(newBlockTime time.Duration) + GetUniqueName() string } type ChainMessage interface { diff --git a/protocol/chainlib/grpc.go b/protocol/chainlib/grpc.go index a007b6f62d..e8974addb0 100644 --- a/protocol/chainlib/grpc.go +++ b/protocol/chainlib/grpc.go @@ -77,6 +77,10 @@ func NewGrpcChainParser() (chainParser *GrpcChainParser, err error) { return &GrpcChainParser{}, nil } +func (bcp *GrpcChainParser) GetUniqueName() string { + return "grpc_chain_parser" +} + func (apip *GrpcChainParser) getApiCollection(connectionType, internalPath, addon string) (*spectypes.ApiCollection, error) { if apip == nil { return nil, errors.New("ChainParser not defined") diff --git a/protocol/chainlib/jsonRPC.go b/protocol/chainlib/jsonRPC.go index dfe4a741be..f752f580f0 100644 --- a/protocol/chainlib/jsonRPC.go +++ b/protocol/chainlib/jsonRPC.go @@ -36,6 +36,10 @@ func NewJrpcChainParser() (chainParser *JsonRPCChainParser, err error) { return &JsonRPCChainParser{}, nil } +func (bcp *JsonRPCChainParser) GetUniqueName() string { + return "jsonrpc_chain_parser" +} + func (apip *JsonRPCChainParser) getApiCollection(connectionType, internalPath, addon string) (*spectypes.ApiCollection, error) { if apip == nil { return nil, errors.New("ChainParser not defined") diff --git a/protocol/chainlib/rest.go b/protocol/chainlib/rest.go index 952a559417..2cb687ba55 100644 --- a/protocol/chainlib/rest.go +++ b/protocol/chainlib/rest.go @@ -38,6 +38,10 @@ func NewRestChainParser() (chainParser *RestChainParser, err error) { return &RestChainParser{}, nil } +func (bcp *RestChainParser) GetUniqueName() string { + return "rest_chain_parser" +} + func (apip *RestChainParser) CraftMessage(parsing *spectypes.ParseDirective, connectionType string, craftData *CraftData, metadata []pairingtypes.Metadata) (ChainMessageForSend, error) { if craftData != nil { // chain fetcher sends the replaced request inside data diff --git a/protocol/chainlib/tendermintRPC.go b/protocol/chainlib/tendermintRPC.go index c4650ec646..017a791379 100644 --- a/protocol/chainlib/tendermintRPC.go +++ b/protocol/chainlib/tendermintRPC.go @@ -38,6 +38,10 @@ func NewTendermintRpcChainParser() (chainParser *TendermintChainParser, err erro return &TendermintChainParser{}, nil } +func (bcp *TendermintChainParser) GetUniqueName() string { + return "tendermint_chain_parser" +} + func (apip *TendermintChainParser) getApiCollection(connectionType, internalPath, addon string) (*spectypes.ApiCollection, error) { if apip == nil { return nil, errors.New("ChainParser not defined") diff --git a/protocol/rpcprovider/provider_listener.go b/protocol/rpcprovider/provider_listener.go index 7f23f77ffb..416b609f94 100644 --- a/protocol/rpcprovider/provider_listener.go +++ b/protocol/rpcprovider/provider_listener.go @@ -36,7 +36,7 @@ func (pl *ProviderListener) RegisterReceiver(existingReceiver RelayReceiver, end // there was already a receiver defined return utils.LavaFormatError("double_receiver_setup receiver already defined on this address with the same chainID and apiInterface", nil, utils.Attribute{Key: "chainID", Value: endpoint.ChainID}, utils.Attribute{Key: "apiInterface", Value: endpoint.ApiInterface}) } - pl.relayServer.relayReceivers[listen_endpoint.Key()] = existingReceiver + pl.relayServer.relayReceivers[listen_endpoint.Key()] = &relayReceiverWrapper{relayReceiver: &existingReceiver, enabled: true} utils.LavaFormatInfo("Provider Listening on Address", utils.Attribute{Key: "chainID", Value: endpoint.ChainID}, utils.Attribute{Key: "apiInterface", Value: endpoint.ApiInterface}, utils.Attribute{Key: "Address", Value: endpoint.NetworkAddress}) return nil } @@ -77,7 +77,7 @@ func NewProviderListener(ctx context.Context, networkAddress lavasession.Network serveExecutor = func() error { return pl.httpServer.ServeTLS(lis, "", "") } } - relayServer := &relayServer{relayReceivers: map[string]RelayReceiver{}} + relayServer := &relayServer{relayReceivers: map[string]*relayReceiverWrapper{}} pl.relayServer = relayServer pairingtypes.RegisterRelayerServer(grpcServer, relayServer) go func() { @@ -90,9 +90,14 @@ func NewProviderListener(ctx context.Context, networkAddress lavasession.Network return pl } +type relayReceiverWrapper struct { + relayReceiver *RelayReceiver + enabled bool +} + type relayServer struct { pairingtypes.UnimplementedRelayerServer - relayReceivers map[string]RelayReceiver + relayReceivers map[string]*relayReceiverWrapper lock sync.RWMutex } @@ -141,5 +146,8 @@ func (rs *relayServer) findReceiver(apiInterface string, specID string) (RelayRe } return nil, utils.LavaFormatError("got called with unhandled relay receiver", nil, utils.Attribute{Key: "requested_receiver", Value: endpoint.Key()}, utils.Attribute{Key: "handled_receivers", Value: strings.Join(keys, ",")}) } - return relayReceiver, nil + if !relayReceiver.enabled { + return nil, utils.LavaFormatError("relayReceiver is disabled", nil, utils.Attribute{Key: "relayReceiver", Value: endpoint.Key()}) + } + return *relayReceiver.relayReceiver, nil } diff --git a/protocol/rpcprovider/provider_listener_mock.go b/protocol/rpcprovider/provider_listener_mock.go new file mode 100644 index 0000000000..e6f9255856 --- /dev/null +++ b/protocol/rpcprovider/provider_listener_mock.go @@ -0,0 +1,84 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: protocol/rpcprovider/provider_listener.go +// +// Generated by this command: +// +// mockgen -source=protocol/rpcprovider/provider_listener.go -destination protocol/rpcprovider/provider_listener_mock.go -package rpcprovider +// +// Package rpcprovider is a generated GoMock package. +package rpcprovider + +import ( + context "context" + reflect "reflect" + + types "github.com/lavanet/lava/x/pairing/types" + gomock "go.uber.org/mock/gomock" +) + +// MockRelayReceiver is a mock of RelayReceiver interface. +type MockRelayReceiver struct { + ctrl *gomock.Controller + recorder *MockRelayReceiverMockRecorder +} + +// MockRelayReceiverMockRecorder is the mock recorder for MockRelayReceiver. +type MockRelayReceiverMockRecorder struct { + mock *MockRelayReceiver +} + +// NewMockRelayReceiver creates a new mock instance. +func NewMockRelayReceiver(ctrl *gomock.Controller) *MockRelayReceiver { + mock := &MockRelayReceiver{ctrl: ctrl} + mock.recorder = &MockRelayReceiverMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockRelayReceiver) EXPECT() *MockRelayReceiverMockRecorder { + return m.recorder +} + +// Probe mocks base method. +func (m *MockRelayReceiver) Probe(ctx context.Context, probeReq *types.ProbeRequest) (*types.ProbeReply, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Probe", ctx, probeReq) + ret0, _ := ret[0].(*types.ProbeReply) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Probe indicates an expected call of Probe. +func (mr *MockRelayReceiverMockRecorder) Probe(ctx, probeReq any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Probe", reflect.TypeOf((*MockRelayReceiver)(nil).Probe), ctx, probeReq) +} + +// Relay mocks base method. +func (m *MockRelayReceiver) Relay(ctx context.Context, request *types.RelayRequest) (*types.RelayReply, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Relay", ctx, request) + ret0, _ := ret[0].(*types.RelayReply) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Relay indicates an expected call of Relay. +func (mr *MockRelayReceiverMockRecorder) Relay(ctx, request any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Relay", reflect.TypeOf((*MockRelayReceiver)(nil).Relay), ctx, request) +} + +// RelaySubscribe mocks base method. +func (m *MockRelayReceiver) RelaySubscribe(request *types.RelayRequest, srv types.Relayer_RelaySubscribeServer) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RelaySubscribe", request, srv) + ret0, _ := ret[0].(error) + return ret0 +} + +// RelaySubscribe indicates an expected call of RelaySubscribe. +func (mr *MockRelayReceiverMockRecorder) RelaySubscribe(request, srv any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RelaySubscribe", reflect.TypeOf((*MockRelayReceiver)(nil).RelaySubscribe), request, srv) +} diff --git a/protocol/rpcprovider/rpcprovider.go b/protocol/rpcprovider/rpcprovider.go index 8e3e9436ef..cb50d4db0b 100644 --- a/protocol/rpcprovider/rpcprovider.go +++ b/protocol/rpcprovider/rpcprovider.go @@ -163,7 +163,9 @@ func (rpcp *RPCProvider) Start(ctx context.Context, txFactory tx.Factory, client } } - disabledEndpointsList := rpcp.SetupProviderEndpoints(rpcProviderEndpoints, true) + specValidator := NewSpecValidator() + disabledEndpointsList := rpcp.SetupProviderEndpoints(rpcProviderEndpoints, specValidator, true) + specValidator.Start(ctx) utils.LavaFormatInfo("RPCProvider done setting up endpoints, ready for service") if len(disabledEndpointsList) > 0 { utils.LavaFormatError(utils.FormatStringerList("[-] RPCProvider running with disabled endpoints:", disabledEndpointsList, "[-]"), nil) @@ -173,7 +175,7 @@ func (rpcp *RPCProvider) Start(ctx context.Context, txFactory tx.Factory, client activeEndpointsList := getActiveEndpoints(rpcProviderEndpoints, disabledEndpointsList) utils.LavaFormatInfo(utils.FormatStringerList("[+] active endpoints:", activeEndpointsList, "[+]")) // try to save disabled endpoints - go rpcp.RetryDisabledEndpoints(disabledEndpointsList, 1) + go rpcp.RetryDisabledEndpoints(disabledEndpointsList, specValidator, 1) } else { utils.LavaFormatInfo("[+] all endpoints up and running") } @@ -215,14 +217,14 @@ func getActiveEndpoints(rpcProviderEndpoints []*lavasession.RPCProviderEndpoint, return activeEndpointsList } -func (rpcp *RPCProvider) RetryDisabledEndpoints(disabledEndpoints []*lavasession.RPCProviderEndpoint, retryCount int) { +func (rpcp *RPCProvider) RetryDisabledEndpoints(disabledEndpoints []*lavasession.RPCProviderEndpoint, specValidator *SpecValidator, retryCount int) { time.Sleep(time.Duration(retryCount) * time.Second) parallel := retryCount > 2 utils.LavaFormatInfo("Retrying disabled endpoints", utils.Attribute{Key: "disabled endpoints list", Value: disabledEndpoints}, utils.Attribute{Key: "parallel", Value: parallel}) - disabledEndpointsAfterRetry := rpcp.SetupProviderEndpoints(disabledEndpoints, parallel) + disabledEndpointsAfterRetry := rpcp.SetupProviderEndpoints(disabledEndpoints, specValidator, parallel) if len(disabledEndpointsAfterRetry) > 0 { utils.LavaFormatError(utils.FormatStringerList("RPCProvider running with disabled endpoints:", disabledEndpointsAfterRetry, "[-]"), nil) - rpcp.RetryDisabledEndpoints(disabledEndpointsAfterRetry, retryCount+1) + rpcp.RetryDisabledEndpoints(disabledEndpointsAfterRetry, specValidator, retryCount+1) activeEndpointsList := getActiveEndpoints(disabledEndpoints, disabledEndpointsAfterRetry) utils.LavaFormatInfo(utils.FormatStringerList("[+] active endpoints:", activeEndpointsList, "[+]")) } else { @@ -230,24 +232,24 @@ func (rpcp *RPCProvider) RetryDisabledEndpoints(disabledEndpoints []*lavasession } } -func (rpcp *RPCProvider) SetupProviderEndpoints(rpcProviderEndpoints []*lavasession.RPCProviderEndpoint, parallel bool) (disabledEndpointsRet []*lavasession.RPCProviderEndpoint) { +func (rpcp *RPCProvider) SetupProviderEndpoints(rpcProviderEndpoints []*lavasession.RPCProviderEndpoint, specValidator *SpecValidator, parallel bool) (disabledEndpointsRet []*lavasession.RPCProviderEndpoint) { var wg sync.WaitGroup parallelJobs := len(rpcProviderEndpoints) wg.Add(parallelJobs) disabledEndpoints := make(chan *lavasession.RPCProviderEndpoint, parallelJobs) for _, rpcProviderEndpoint := range rpcProviderEndpoints { - setupEndpoint := func(rpcProviderEndpoint *lavasession.RPCProviderEndpoint) { + setupEndpoint := func(rpcProviderEndpoint *lavasession.RPCProviderEndpoint, specValidator *SpecValidator) { defer wg.Done() - err := rpcp.SetupEndpoint(context.Background(), rpcProviderEndpoint) + err := rpcp.SetupEndpoint(context.Background(), rpcProviderEndpoint, specValidator) if err != nil { rpcp.providerMetricsManager.SetDisabledChain(rpcProviderEndpoint.ChainID, rpcProviderEndpoint.ApiInterface) disabledEndpoints <- rpcProviderEndpoint } } if parallel { - go setupEndpoint(rpcProviderEndpoint) + go setupEndpoint(rpcProviderEndpoint, specValidator) } else { - setupEndpoint(rpcProviderEndpoint) + setupEndpoint(rpcProviderEndpoint, specValidator) } } wg.Wait() @@ -259,7 +261,7 @@ func (rpcp *RPCProvider) SetupProviderEndpoints(rpcProviderEndpoints []*lavasess return disabledEndpointsList } -func (rpcp *RPCProvider) SetupEndpoint(ctx context.Context, rpcProviderEndpoint *lavasession.RPCProviderEndpoint) error { +func (rpcp *RPCProvider) SetupEndpoint(ctx context.Context, rpcProviderEndpoint *lavasession.RPCProviderEndpoint, specValidator *SpecValidator) error { err := rpcProviderEndpoint.Validate() if err != nil { return utils.LavaFormatError("panic severity critical error, aborting support for chain api due to invalid node url definition, continuing with others", err, utils.Attribute{Key: "endpoint", Value: rpcProviderEndpoint.String()}) @@ -272,7 +274,8 @@ func (rpcp *RPCProvider) SetupEndpoint(ctx context.Context, rpcProviderEndpoint return utils.LavaFormatError("panic severity critical error, aborting support for chain api due to invalid chain parser, continuing with others", err, utils.Attribute{Key: "endpoint", Value: rpcProviderEndpoint.String()}) } - err = rpcp.providerStateTracker.RegisterForSpecUpdates(ctx, chainParser, lavasession.RPCEndpoint{ChainID: chainID, ApiInterface: rpcProviderEndpoint.ApiInterface}) + rpcEndpoint := lavasession.RPCEndpoint{ChainID: chainID, ApiInterface: rpcProviderEndpoint.ApiInterface} + err = rpcp.providerStateTracker.RegisterForSpecUpdates(ctx, chainParser, rpcEndpoint) if err != nil { return utils.LavaFormatError("failed to RegisterForSpecUpdates, panic severity critical error, aborting support for chain api due to invalid chain parser, continuing with others", err, utils.Attribute{Key: "endpoint", Value: rpcProviderEndpoint.String()}) } @@ -301,11 +304,12 @@ func (rpcp *RPCProvider) SetupEndpoint(ctx context.Context, rpcProviderEndpoint chainFetcher = chainlib.NewVerificationsOnlyChainFetcher(ctx, chainRouter, chainParser, rpcProviderEndpoint) } - // Fetch and validate all verifications - err = chainFetcher.Validate(ctx) + // Add the chain fetcher to the spec validator + err := specValidator.AddChainFetcher(ctx, &chainFetcher, chainID) if err != nil { - return utils.LavaFormatError("panic severity critical error, aborting support for chain api due to failing to validate, continuing with other endpoints", err, utils.Attribute{Key: "endpoint", Value: rpcProviderEndpoint}) + return err } + var found bool chainTracker, found = rpcp.chainTrackers.GetTrackerPerChain(chainID) if !found { @@ -331,8 +335,14 @@ func (rpcp *RPCProvider) SetupEndpoint(ctx context.Context, rpcProviderEndpoint if err != nil { return utils.LavaFormatError("panic severity critical error, aborting support for chain api due to node access, continuing with other endpoints", err, utils.Attribute{Key: "chainTrackerConfig", Value: chainTrackerConfig}, utils.Attribute{Key: "endpoint", Value: rpcProviderEndpoint}) } + // Any validation needs to be before we store chain tracker for given chain id rpcp.chainTrackers.SetTrackerForChain(rpcProviderEndpoint.ChainID, chainTracker) + + err = rpcp.providerStateTracker.RegisterForSpecUpdates(ctx, specValidator, rpcEndpoint) + if err != nil { + return utils.LavaFormatError("failed to RegisterForSpecUpdates, panic severity critical error, aborting support for chain api due to invalid chain parser, continuing with others", err, utils.Attribute{Key: "endpoint", Value: rpcProviderEndpoint.String()}) + } } else { utils.LavaFormatDebug("reusing chain tracker", utils.Attribute{Key: "chain", Value: rpcProviderEndpoint.ChainID}) } @@ -363,6 +373,7 @@ func (rpcp *RPCProvider) SetupEndpoint(ctx context.Context, rpcProviderEndpoint if !ok { utils.LavaFormatDebug("creating new listener", utils.Attribute{Key: "NetworkAddress", Value: rpcProviderEndpoint.NetworkAddress}) listener = NewProviderListener(ctx, rpcProviderEndpoint.NetworkAddress) + specValidator.AddRPCProviderListener(rpcProviderEndpoint.NetworkAddress.Address, listener) rpcp.rpcProviderListeners[rpcProviderEndpoint.NetworkAddress.Address] = listener } }() @@ -585,6 +596,7 @@ rpcprovider 127.0.0.1:3333 COS3 tendermintrpc "wss://www.node-path.com:80,https: cmdRPCProvider.Flags().Uint(rewardserver.RewardsSnapshotTimeoutSecFlagName, rewardserver.DefaultRewardsSnapshotTimeoutSec, "the seconds to wait until making snapshot of the rewards memory") cmdRPCProvider.Flags().String(StickinessHeaderName, RPCProviderStickinessHeaderName, "the name of the header to be attacked to requests for stickiness by consumer, used for consistency") cmdRPCProvider.Flags().Uint64Var(&chaintracker.PollingMultiplier, chaintracker.PollingMultiplierFlagName, 1, "when set, forces the chain tracker to poll more often, improving the sync at the cost of more queries") + cmdRPCProvider.Flags().Uint64Var(&SpecValidationIntervalSec, SpecValidationIntervalSecFlagName, SpecValidationIntervalSec, "determines the interval of which to run validation on the spec for all connected chains") common.AddRollingLogConfig(cmdRPCProvider) return cmdRPCProvider } diff --git a/protocol/rpcprovider/spec_validator.go b/protocol/rpcprovider/spec_validator.go new file mode 100644 index 0000000000..9f779b6a7f --- /dev/null +++ b/protocol/rpcprovider/spec_validator.go @@ -0,0 +1,155 @@ +package rpcprovider + +import ( + "context" + "sync" + "time" + + "github.com/lavanet/lava/protocol/chainlib" + "github.com/lavanet/lava/protocol/lavasession" + "github.com/lavanet/lava/utils" + spectypes "github.com/lavanet/lava/x/spec/types" +) + +const ( + SpecValidationIntervalSecFlagName = "spec-validation-interval-sec" +) + +var SpecValidationIntervalSec = uint64(10800) // 3 Hours + +type SpecValidator struct { + lock sync.RWMutex + + chainFetchers map[string][]*chainlib.ChainFetcherIf // key is chainId + providerListeners map[string]*ProviderListener // key is address +} + +func NewSpecValidator() *SpecValidator { + return &SpecValidator{ + lock: sync.RWMutex{}, + chainFetchers: make(map[string][]*chainlib.ChainFetcherIf), + providerListeners: make(map[string]*ProviderListener), + } +} + +func (sv *SpecValidator) GetUniqueName() string { + return "spec_validator" +} + +func (sv *SpecValidator) Start(ctx context.Context) { + go sv.validateAllChainsLoop(ctx) +} + +func (sv *SpecValidator) validateAllChainsLoop(ctx context.Context) { + timerInterval := time.Duration(SpecValidationIntervalSec) * time.Second + ticker := time.NewTicker(timerInterval) + for { + select { + case <-ticker.C: + func() { + sv.lock.Lock() + defer sv.lock.Unlock() + sv.validateAllChains(ctx) + }() + case <-ctx.Done(): + ticker.Stop() + return + } + } +} + +func (sv *SpecValidator) AddChainFetcher(ctx context.Context, chainFetcher *chainlib.ChainFetcherIf, chainId string) error { + sv.lock.Lock() + defer sv.lock.Unlock() + err := (*chainFetcher).Validate(ctx) + if err != nil { + return err + } + + if _, found := sv.chainFetchers[chainId]; !found { + sv.chainFetchers[chainId] = []*chainlib.ChainFetcherIf{} + } + sv.chainFetchers[chainId] = append(sv.chainFetchers[chainId], chainFetcher) + + return nil +} + +func (sv *SpecValidator) AddRPCProviderListener(address string, providerListener *ProviderListener) { + sv.lock.Lock() + defer sv.lock.Unlock() + sv.providerListeners[address] = providerListener +} + +func (sv *SpecValidator) SetSpec(spec spectypes.Spec) { + sv.lock.Lock() + defer sv.lock.Unlock() + + chainId := spec.Index + if _, found := sv.chainFetchers[chainId]; !found { + utils.LavaFormatError("Could not find chainFetchers with given chainId", nil, utils.Attribute{Key: "chainId", Value: chainId}) + return + } + sv.validateChain(context.Background(), chainId) +} + +func (sv *SpecValidator) Active() bool { + return true +} + +func (sv *SpecValidator) getRpcProviderEndpointFromChainFetcher(chainFetcher *chainlib.ChainFetcherIf) *lavasession.RPCEndpoint { + endpoint := (*chainFetcher).FetchEndpoint() + return &lavasession.RPCEndpoint{ + NetworkAddress: endpoint.NetworkAddress.Address, + ChainID: endpoint.ChainID, + ApiInterface: endpoint.ApiInterface, + Geolocation: endpoint.Geolocation, + } +} + +func (sv *SpecValidator) validateAllChains(ctx context.Context) { + for chainId := range sv.chainFetchers { + sv.validateChain(ctx, chainId) + } +} + +func (sv *SpecValidator) validateChain(ctx context.Context, chainId string) error { + errors := []error{} + for _, chainFetcher := range sv.chainFetchers[chainId] { + err := (*chainFetcher).Validate(ctx) + rpcEndpoint := sv.getRpcProviderEndpointFromChainFetcher(chainFetcher) + providerListener, found := sv.providerListeners[rpcEndpoint.NetworkAddress] + if !found { + if err != nil { + utils.LavaFormatWarning("Verification failed for endpoint", nil, utils.Attribute{Key: "endpoint", Value: rpcEndpoint}) + errors = append(errors, err) + } + continue + } + + relayReceiver, found := providerListener.relayServer.relayReceivers[rpcEndpoint.Key()] + if !found { + if err != nil { + utils.LavaFormatWarning("Verification failed for endpoint", nil, utils.Attribute{Key: "endpoint", Value: rpcEndpoint}) + errors = append(errors, err) + } + continue + } + + if err != nil { + relayReceiver.enabled = false + utils.LavaFormatError("[-] Verification failed for endpoint. Disabling endpoint.", nil, utils.Attribute{Key: "endpoint", Value: rpcEndpoint}) + errors = append(errors, err) + } else if !relayReceiver.enabled { + relayReceiver.enabled = true + utils.LavaFormatError("[+] Verification passed for disabled endpoint. Enabling endpoint.", nil, utils.Attribute{Key: "endpoint", Value: rpcEndpoint}) + } + } + + if len(errors) > 0 { + return utils.LavaFormatError("Validation chainId failed with errors", nil, + utils.Attribute{Key: "chainId", Value: chainId}, + utils.Attribute{Key: "errors", Value: errors}, + ) + } + return nil +} diff --git a/protocol/rpcprovider/spec_validator_test.go b/protocol/rpcprovider/spec_validator_test.go new file mode 100644 index 0000000000..0a0b0c2e5f --- /dev/null +++ b/protocol/rpcprovider/spec_validator_test.go @@ -0,0 +1,151 @@ +package rpcprovider + +import ( + "context" + "errors" + "testing" + "time" + + "github.com/lavanet/lava/protocol/chainlib" + "github.com/lavanet/lava/protocol/lavasession" + testcommon "github.com/lavanet/lava/testutil/common" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" +) + +func TestSetSpecWithoutChainFetchersNorProviderListenerNoErrors(t *testing.T) { + spec := testcommon.CreateMockSpec() + + specValidator := NewSpecValidator() + require.NotPanics(t, func() { specValidator.SetSpec(spec) }) +} + +func TestSetSpecWithoutRelayReceiversNoErrors(t *testing.T) { + spec := testcommon.CreateMockSpec() + + providerListener := NewProviderListener(context.Background(), lavasession.NetworkAddressData{}) + providerListener.RegisterReceiver(&RPCProviderServer{}, &lavasession.RPCProviderEndpoint{}) + + specValidator := NewSpecValidator() + specValidator.AddRPCProviderListener("", providerListener) + require.NotPanics(t, func() { specValidator.SetSpec(spec) }) +} + +func TestAddChainFetcherAndSetSpecCallsValidate(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + spec := testcommon.CreateMockSpec() + specValidator := NewSpecValidator() + + specName := "LAV1" + spec.Index = specName + + ctx := context.Background() + + chainFetcher := chainlib.NewMockChainFetcherIf(ctrl) + var chainFetcherIf chainlib.ChainFetcherIf = chainFetcher + + chainFetcher.EXPECT().FetchEndpoint().AnyTimes() + + firstCall := chainFetcher.EXPECT().Validate(gomock.Any()).Times(1) + specValidator.AddChainFetcher(ctx, &chainFetcherIf, specName) + + chainFetcher.EXPECT().Validate(gomock.Any()).Times(1).After(firstCall) + specValidator.SetSpec(spec) +} + +func TestStartCallsAllValidateFunctions(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + spec := testcommon.CreateMockSpec() + specValidator := NewSpecValidator() + + specName := "LAV1" + spec.Index = specName + + ctx := context.Background() + + done := make(chan bool) + calls := 0 + + raiseCallCount := func(data interface{}) { + calls++ + if calls == 10 { + done <- true + } + } + + for i := 0; i < 10; i++ { + chainFetcher := chainlib.NewMockChainFetcherIf(ctrl) + + chainFetcher.EXPECT().FetchEndpoint().AnyTimes() + firstCall := chainFetcher.EXPECT().Validate(gomock.Any()).Times(1) + + var chainFetcherIf chainlib.ChainFetcherIf = chainFetcher + specValidator.AddChainFetcher(ctx, &chainFetcherIf, specName) + + chainFetcher.EXPECT().Validate(gomock.Any()).Times(1).After(firstCall).Do(raiseCallCount) + } + SpecValidationIntervalSec = 1 + ctx, cancel := context.WithTimeout(ctx, 5*time.Second) + defer cancel() + specValidator.Start(ctx) + + select { + case <-done: + t.Log("Done validations") + case <-ctx.Done(): + t.Fatal("The operation timed out") + } +} + +func TestFailedThenSuccessVerificationDisablesThenEnablesReceiver(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + spec := testcommon.CreateMockSpec() + specValidator := NewSpecValidator() + + specName := "LAV1" + spec.Index = specName + + ctx := context.Background() + + chainFetcher := chainlib.NewMockChainFetcherIf(ctrl) + chainFetcher.EXPECT().FetchEndpoint().AnyTimes() + + firstCall := chainFetcher.EXPECT().Validate(gomock.Any()).Times(1) + + var chainFetcherIf chainlib.ChainFetcherIf = chainFetcher + specValidator.AddChainFetcher(ctx, &chainFetcherIf, specName) + + secondCall := chainFetcher.EXPECT().Validate(gomock.Any()).Times(1).After(firstCall).Return(errors.New("")) + + addressData := lavasession.NetworkAddressData{} + providerListener := NewProviderListener(context.Background(), addressData) + + relayReceiver := NewMockRelayReceiver(ctrl) + rpcProviderEndpoint := &lavasession.RPCProviderEndpoint{} + providerListener.RegisterReceiver(relayReceiver, rpcProviderEndpoint) + specValidator.AddRPCProviderListener(addressData.Address, providerListener) + + // Check that the receiver is first enabled + rpcEndpoint := specValidator.getRpcProviderEndpointFromChainFetcher(&chainFetcherIf) + require.True(t, providerListener.relayServer.relayReceivers[rpcEndpoint.Key()].enabled) + + specValidator.validateChain(ctx, specName) + + // Check that the receiver is disabled + rpcEndpoint = specValidator.getRpcProviderEndpointFromChainFetcher(&chainFetcherIf) + require.False(t, providerListener.relayServer.relayReceivers[rpcEndpoint.Key()].enabled) + + chainFetcher.EXPECT().Validate(gomock.Any()).Times(1).After(secondCall).Return(nil) + + specValidator.validateChain(ctx, specName) + + // Check that the receiver is enabled + rpcEndpoint = specValidator.getRpcProviderEndpointFromChainFetcher(&chainFetcherIf) + require.True(t, providerListener.relayServer.relayReceivers[rpcEndpoint.Key()].enabled) +} diff --git a/protocol/statetracker/spec_updater.go b/protocol/statetracker/spec_updater.go index 84bb2751d4..dd9908abf6 100644 --- a/protocol/statetracker/spec_updater.go +++ b/protocol/statetracker/spec_updater.go @@ -2,6 +2,7 @@ package statetracker import ( "context" + "strings" "sync" "github.com/lavanet/lava/protocol/lavasession" @@ -20,6 +21,7 @@ type SpecGetter interface { type SpecUpdatable interface { SetSpec(spectypes.Spec) Active() bool + GetUniqueName() string } type SpecUpdater struct { @@ -48,10 +50,16 @@ func (su *SpecUpdater) RegisterSpecUpdatable(ctx context.Context, specUpdatable if su.chainId != endpoint.ChainID { return utils.LavaFormatError("panic level error Trying to register spec for wrong chain id stored in spec_updater", nil, utils.Attribute{Key: "endpoint", Value: endpoint}, utils.Attribute{Key: "stored_spec", Value: su.chainId}) } - existingSpecUpdatable, found := su.specUpdatables[endpoint.Key()] + + updatableUniqueName := (*specUpdatable).GetUniqueName() + key := strings.Join([]string{updatableUniqueName, endpoint.Key()}, "_") + existingSpecUpdatable, found := su.specUpdatables[key] if found { if (*existingSpecUpdatable).Active() { - return utils.LavaFormatError("panic level error Trying to register to spec updates on already registered chain + API interfcae", nil, utils.Attribute{Key: "endpoint", Value: endpoint}, utils.Attribute{Key: "specUpdatable", Value: existingSpecUpdatable}) + return utils.LavaFormatError("panic level error Trying to register to spec updates on already registered updatable unique name + chain + API interface", nil, + utils.Attribute{Key: "updatableUniqueName", Value: updatableUniqueName}, + utils.Attribute{Key: "endpoint", Value: endpoint}, + utils.Attribute{Key: "specUpdatable", Value: existingSpecUpdatable}) } } From 55fe68de4d50dc34ff6fc788b208c9059a430597 Mon Sep 17 00:00:00 2001 From: oren-lava Date: Tue, 5 Dec 2023 12:29:31 +0200 Subject: [PATCH 35/85] CNS-755: another e2e fix --- testutil/e2e/protocolE2E.go | 6 +++--- testutil/e2e/sdkE2E.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/testutil/e2e/protocolE2E.go b/testutil/e2e/protocolE2E.go index 84a773f1e8..7dc20b0121 100644 --- a/testutil/e2e/protocolE2E.go +++ b/testutil/e2e/protocolE2E.go @@ -50,7 +50,7 @@ var ( checkedPlansE2E = []string{"DefaultPlan", "EmergencyModePlan"} checkedSubscriptions = []string{"user1", "user2", "user3", "user5"} checkedSpecsE2E = []string{"LAV1", "ETH1"} - checkedSpecsE2ELOL = []string{"GTH1", "SEP1"} + checkedSpecsE2ELOL = []string{"GTH1"} checkedSubscriptionsLOL = []string{"user4"} ) @@ -626,7 +626,7 @@ func (lt *lavaTest) lavaOverLava(ctx context.Context) { // - produce 5 specs: ETH1, GTH1, SEP1, IBC, COSMOSSDK, LAV1 (via spec_add_{ethereum,cosmoshub,lava}) // - produce 2 plans: "DefaultPlan", "EmergencyModePlan" - lt.checkStakeLava(2, 5, 5, 5, checkedPlansE2E, checkedSpecsE2ELOL, checkedSubscriptionsLOL, "Lava Over Lava Test OK") + lt.checkStakeLava(2, 6, 4, 5, checkedPlansE2E, checkedSpecsE2ELOL, checkedSubscriptionsLOL, "Lava Over Lava Test OK") } func (lt *lavaTest) checkRESTConsumer(rpcURL string, timeout time.Duration) { @@ -1179,7 +1179,7 @@ func runProtocolE2E(timeout time.Duration) { // - produce 1 staked client (for each of ETH1, LAV1) // - produce 1 subscription (for both ETH1, LAV1) - lt.checkStakeLava(2, 5, 5, 5, checkedPlansE2E, checkedSpecsE2E, checkedSubscriptions, "Staking Lava OK") + lt.checkStakeLava(2, 6, 4, 5, checkedPlansE2E, checkedSpecsE2E, checkedSubscriptions, "Staking Lava OK") utils.LavaFormatInfo("RUNNING TESTS") diff --git a/testutil/e2e/sdkE2E.go b/testutil/e2e/sdkE2E.go index 49ce75aead..4d29eb7bb1 100644 --- a/testutil/e2e/sdkE2E.go +++ b/testutil/e2e/sdkE2E.go @@ -124,7 +124,7 @@ func runSDKE2E(timeout time.Duration) { utils.LavaFormatInfo("Staking Lava") lt.stakeLava(ctx) - lt.checkStakeLava(2, 5, 5, 5, checkedPlansE2E, checkedSpecsE2E, checkedSubscriptions, "Staking Lava OK") + lt.checkStakeLava(2, 6, 4, 5, checkedPlansE2E, checkedSpecsE2E, checkedSubscriptions, "Staking Lava OK") utils.LavaFormatInfo("RUNNING TESTS") From 64c17fad28a610f1a102cdfd1b9ec1f821a81753 Mon Sep 17 00:00:00 2001 From: Omer <100387053+omerlavanet@users.noreply.github.com> Date: Tue, 5 Dec 2023 12:42:24 +0200 Subject: [PATCH 36/85] CNS-improve the verification for subsquid (#1021) * improve the verification * bump target version --- cookbook/specs/spec_add_sqdsubgraph.json | 6 +++--- protocol/chainlib/rest.go | 9 ++++++++- protocol/parser/parser.go | 5 +++-- x/protocol/types/params.go | 2 +- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/cookbook/specs/spec_add_sqdsubgraph.json b/cookbook/specs/spec_add_sqdsubgraph.json index fc527b78b5..b535e5a76d 100644 --- a/cookbook/specs/spec_add_sqdsubgraph.json +++ b/cookbook/specs/spec_add_sqdsubgraph.json @@ -70,12 +70,12 @@ { "name": "health", "parse_directive": { - "function_template": "/subgraphs/name/1", + "function_template": "{\"query\":\"{\n pools(first: 5) {\n id\n poolid\n platform {\n id\n }\n name\n }\n}\"}", "function_tag": "VERIFICATION", "result_parsing": { "parser_arg": [ "0", - "message" + "error" ], "parser_func": "PARSE_CANONICAL" }, @@ -83,7 +83,7 @@ }, "values": [ { - "expected_value": "Body is required" + "expected_value": "GraphQL server error (client error): Invalid subgraph name \"1\"" } ] } diff --git a/protocol/chainlib/rest.go b/protocol/chainlib/rest.go index 2cb687ba55..813219568c 100644 --- a/protocol/chainlib/rest.go +++ b/protocol/chainlib/rest.go @@ -44,8 +44,15 @@ func (bcp *RestChainParser) GetUniqueName() string { func (apip *RestChainParser) CraftMessage(parsing *spectypes.ParseDirective, connectionType string, craftData *CraftData, metadata []pairingtypes.Metadata) (ChainMessageForSend, error) { if craftData != nil { + var data []byte = nil + urlPath := string(craftData.Data) + if craftData.ConnectionType == http.MethodPost { + // on post we need to send the data provided in the templace with the api as method + data = craftData.Data + urlPath = craftData.Path + } // chain fetcher sends the replaced request inside data - chainMessage, err := apip.ParseMsg(string(craftData.Data), nil, craftData.ConnectionType, metadata, 0) + chainMessage, err := apip.ParseMsg(urlPath, data, craftData.ConnectionType, metadata, 0) if err == nil { chainMessage.AppendHeader(metadata) } diff --git a/protocol/parser/parser.go b/protocol/parser/parser.go index dcd53001cd..e613e0337e 100644 --- a/protocol/parser/parser.go +++ b/protocol/parser/parser.go @@ -79,10 +79,11 @@ func ParseFromReply(rpcInput RPCInput, blockParser spectypes.BlockParser) (strin } if strings.Contains(response, "\"") { - response, err = strconv.Unquote(response) + responseUnquoted, err := strconv.Unquote(response) if err != nil { - return "", err + return response, nil } + return responseUnquoted, nil } return response, nil diff --git a/x/protocol/types/params.go b/x/protocol/types/params.go index 615ffb748d..58f968de99 100644 --- a/x/protocol/types/params.go +++ b/x/protocol/types/params.go @@ -12,7 +12,7 @@ import ( var _ paramtypes.ParamSet = (*Params)(nil) const ( - TARGET_VERSION = "0.30.2" + TARGET_VERSION = "0.30.3" MIN_VERSION = "0.27.1" ) From 4b89d23eb400c17d748570e4250c42d8af5b251b Mon Sep 17 00:00:00 2001 From: oren-lava Date: Tue, 5 Dec 2023 19:12:37 +0200 Subject: [PATCH 37/85] CNS-756: replaced GetClientContextFromCmd with GetClientQueryContext --- cmd/lavad/cmd/genaccounts.go | 5 ++++- x/conflict/client/cli/query_conflict_vote.go | 10 ++++++++-- x/conflict/client/cli/query_consumer_conflicts.go | 5 ++++- x/conflict/client/cli/query_params.go | 5 ++++- x/conflict/client/cli/query_provider_conflicts.go | 5 ++++- x/downtime/client/cli/query.go | 10 ++++++++-- x/epochstorage/client/cli/query_epoch_details.go | 5 ++++- x/epochstorage/client/cli/query_fixated_params.go | 10 ++++++++-- x/epochstorage/client/cli/query_params.go | 5 ++++- x/epochstorage/client/cli/query_stake_storage.go | 10 ++++++++-- x/pairing/client/cli/query_epoch_payments.go | 10 ++++++++-- x/pairing/client/cli/query_params.go | 5 ++++- x/pairing/client/cli/query_provider_payment_storage.go | 10 ++++++++-- .../query_unique_payment_storage_client_provider.go | 10 ++++++++-- x/plans/client/cli/query_params.go | 5 ++++- x/projects/client/cli/query_params.go | 5 ++++- x/protocol/client/cli/query_params.go | 5 ++++- x/spec/client/cli/query_params.go | 5 ++++- x/spec/client/cli/query_spec.go | 10 ++++++++-- x/subscription/client/cli/query_params.go | 5 ++++- 20 files changed, 112 insertions(+), 28 deletions(-) diff --git a/cmd/lavad/cmd/genaccounts.go b/cmd/lavad/cmd/genaccounts.go index c1e6f49170..d607b33b19 100644 --- a/cmd/lavad/cmd/genaccounts.go +++ b/cmd/lavad/cmd/genaccounts.go @@ -37,7 +37,10 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa `, Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } cdc := clientCtx.Codec serverCtx := server.GetServerContextFromCmd(cmd) diff --git a/x/conflict/client/cli/query_conflict_vote.go b/x/conflict/client/cli/query_conflict_vote.go index 28d73ccc74..5ca6c9bb4d 100644 --- a/x/conflict/client/cli/query_conflict_vote.go +++ b/x/conflict/client/cli/query_conflict_vote.go @@ -14,7 +14,10 @@ func CmdListConflictVote() *cobra.Command { Use: "list-conflict-vote", Short: "list all ConflictVote", RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } pageReq, err := client.ReadPageRequest(cmd.Flags()) if err != nil { @@ -48,7 +51,10 @@ func CmdShowConflictVote() *cobra.Command { Short: "shows a ConflictVote", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := types.NewQueryClient(clientCtx) diff --git a/x/conflict/client/cli/query_consumer_conflicts.go b/x/conflict/client/cli/query_consumer_conflicts.go index e949403bb6..9e1caea30c 100644 --- a/x/conflict/client/cli/query_consumer_conflicts.go +++ b/x/conflict/client/cli/query_consumer_conflicts.go @@ -13,7 +13,10 @@ func CmdConsumerConflicts() *cobra.Command { Short: "Gets a consumer's active conflict list", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := types.NewQueryClient(clientCtx) diff --git a/x/conflict/client/cli/query_params.go b/x/conflict/client/cli/query_params.go index 9c3ecb97e6..cd77709b31 100644 --- a/x/conflict/client/cli/query_params.go +++ b/x/conflict/client/cli/query_params.go @@ -15,7 +15,10 @@ func CmdQueryParams() *cobra.Command { Short: "shows the parameters of the module", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := types.NewQueryClient(clientCtx) diff --git a/x/conflict/client/cli/query_provider_conflicts.go b/x/conflict/client/cli/query_provider_conflicts.go index 3997235c31..6ce5d6c970 100644 --- a/x/conflict/client/cli/query_provider_conflicts.go +++ b/x/conflict/client/cli/query_provider_conflicts.go @@ -13,7 +13,10 @@ func CmdProviderConflicts() *cobra.Command { Short: "Queries a provider's conflict list (ones that the provider was reported in and ones that the provider needs to vote)", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := types.NewQueryClient(clientCtx) diff --git a/x/downtime/client/cli/query.go b/x/downtime/client/cli/query.go index 6672230797..9b2a7cc108 100644 --- a/x/downtime/client/cli/query.go +++ b/x/downtime/client/cli/query.go @@ -23,7 +23,10 @@ func CmdQueryParams() *cobra.Command { Use: "params", Short: "Query downtime module params", RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := v1.NewQueryClient(clientCtx) resp, err := queryClient.QueryParams(cmd.Context(), &v1.QueryParamsRequest{}) if err != nil { @@ -45,7 +48,10 @@ func CmdQueryDowntime() *cobra.Command { if err != nil { return err } - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := v1.NewQueryClient(clientCtx) resp, err := queryClient.QueryDowntime(cmd.Context(), &v1.QueryDowntimeRequest{ EpochStartBlock: start, diff --git a/x/epochstorage/client/cli/query_epoch_details.go b/x/epochstorage/client/cli/query_epoch_details.go index 7d646236a9..f949343354 100644 --- a/x/epochstorage/client/cli/query_epoch_details.go +++ b/x/epochstorage/client/cli/query_epoch_details.go @@ -15,7 +15,10 @@ func CmdShowEpochDetails() *cobra.Command { Short: "shows epochDetails", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := types.NewQueryClient(clientCtx) diff --git a/x/epochstorage/client/cli/query_fixated_params.go b/x/epochstorage/client/cli/query_fixated_params.go index b7dea71d8d..e6300c5f79 100644 --- a/x/epochstorage/client/cli/query_fixated_params.go +++ b/x/epochstorage/client/cli/query_fixated_params.go @@ -14,7 +14,10 @@ func CmdListFixatedParams() *cobra.Command { Use: "list-fixated-params", Short: "list all fixatedParams", RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } pageReq, err := client.ReadPageRequest(cmd.Flags()) if err != nil { @@ -48,7 +51,10 @@ func CmdShowFixatedParams() *cobra.Command { Short: "shows a fixatedParams", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := types.NewQueryClient(clientCtx) diff --git a/x/epochstorage/client/cli/query_params.go b/x/epochstorage/client/cli/query_params.go index 58ecd17dec..618e9c4f33 100644 --- a/x/epochstorage/client/cli/query_params.go +++ b/x/epochstorage/client/cli/query_params.go @@ -15,7 +15,10 @@ func CmdQueryParams() *cobra.Command { Short: "shows the parameters of the module", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := types.NewQueryClient(clientCtx) diff --git a/x/epochstorage/client/cli/query_stake_storage.go b/x/epochstorage/client/cli/query_stake_storage.go index 39e6ba9f4f..ae4d338348 100644 --- a/x/epochstorage/client/cli/query_stake_storage.go +++ b/x/epochstorage/client/cli/query_stake_storage.go @@ -14,7 +14,10 @@ func CmdListStakeStorage() *cobra.Command { Use: "list-stake-storage", Short: "list all StakeStorage", RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } pageReq, err := client.ReadPageRequest(cmd.Flags()) if err != nil { @@ -48,7 +51,10 @@ func CmdShowStakeStorage() *cobra.Command { Short: "shows a StakeStorage", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := types.NewQueryClient(clientCtx) diff --git a/x/pairing/client/cli/query_epoch_payments.go b/x/pairing/client/cli/query_epoch_payments.go index 531dac3e7f..1d1215e55b 100644 --- a/x/pairing/client/cli/query_epoch_payments.go +++ b/x/pairing/client/cli/query_epoch_payments.go @@ -14,7 +14,10 @@ func CmdListEpochPayments() *cobra.Command { Use: "list-epoch-payments", Short: "list all EpochPayments", RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } pageReq, err := client.ReadPageRequest(cmd.Flags()) if err != nil { @@ -48,7 +51,10 @@ func CmdShowEpochPayments() *cobra.Command { Short: "shows a EpochPayments", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := types.NewQueryClient(clientCtx) diff --git a/x/pairing/client/cli/query_params.go b/x/pairing/client/cli/query_params.go index 7850cd35a8..4a9c9a1e3f 100644 --- a/x/pairing/client/cli/query_params.go +++ b/x/pairing/client/cli/query_params.go @@ -15,7 +15,10 @@ func CmdQueryParams() *cobra.Command { Short: "shows the parameters of the module", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := types.NewQueryClient(clientCtx) diff --git a/x/pairing/client/cli/query_provider_payment_storage.go b/x/pairing/client/cli/query_provider_payment_storage.go index 89837d1b03..e77f7e9670 100644 --- a/x/pairing/client/cli/query_provider_payment_storage.go +++ b/x/pairing/client/cli/query_provider_payment_storage.go @@ -14,7 +14,10 @@ func CmdListProviderPaymentStorage() *cobra.Command { Use: "list-provider-payment-storage", Short: "list all ProviderPaymentStorage", RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } pageReq, err := client.ReadPageRequest(cmd.Flags()) if err != nil { @@ -48,7 +51,10 @@ func CmdShowProviderPaymentStorage() *cobra.Command { Short: "shows a ProviderPaymentStorage", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := types.NewQueryClient(clientCtx) diff --git a/x/pairing/client/cli/query_unique_payment_storage_client_provider.go b/x/pairing/client/cli/query_unique_payment_storage_client_provider.go index 2b830cbb83..77c1ec4f29 100644 --- a/x/pairing/client/cli/query_unique_payment_storage_client_provider.go +++ b/x/pairing/client/cli/query_unique_payment_storage_client_provider.go @@ -14,7 +14,10 @@ func CmdListUniquePaymentStorageClientProvider() *cobra.Command { Use: "list-unique-payment-storage-client-provider", Short: "list all UniquePaymentStorageClientProvider", RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } pageReq, err := client.ReadPageRequest(cmd.Flags()) if err != nil { @@ -48,7 +51,10 @@ func CmdShowUniquePaymentStorageClientProvider() *cobra.Command { Short: "shows a UniquePaymentStorageClientProvider", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := types.NewQueryClient(clientCtx) diff --git a/x/plans/client/cli/query_params.go b/x/plans/client/cli/query_params.go index cc90028cf4..2355a2488d 100644 --- a/x/plans/client/cli/query_params.go +++ b/x/plans/client/cli/query_params.go @@ -15,7 +15,10 @@ func CmdQueryParams() *cobra.Command { Short: "shows the parameters of the module", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := types.NewQueryClient(clientCtx) diff --git a/x/projects/client/cli/query_params.go b/x/projects/client/cli/query_params.go index b021f9250c..7cde526252 100644 --- a/x/projects/client/cli/query_params.go +++ b/x/projects/client/cli/query_params.go @@ -15,7 +15,10 @@ func CmdQueryParams() *cobra.Command { Short: "shows the parameters of the module", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := types.NewQueryClient(clientCtx) diff --git a/x/protocol/client/cli/query_params.go b/x/protocol/client/cli/query_params.go index 5fc5430daa..1fa05c0513 100644 --- a/x/protocol/client/cli/query_params.go +++ b/x/protocol/client/cli/query_params.go @@ -15,7 +15,10 @@ func CmdQueryParams() *cobra.Command { Short: "shows the parameters of the module", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := types.NewQueryClient(clientCtx) diff --git a/x/spec/client/cli/query_params.go b/x/spec/client/cli/query_params.go index af2a9eb90f..7eee2cd29b 100644 --- a/x/spec/client/cli/query_params.go +++ b/x/spec/client/cli/query_params.go @@ -15,7 +15,10 @@ func CmdQueryParams() *cobra.Command { Short: "shows the parameters of the module", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := types.NewQueryClient(clientCtx) diff --git a/x/spec/client/cli/query_spec.go b/x/spec/client/cli/query_spec.go index 55a552e916..1bddcdcda0 100644 --- a/x/spec/client/cli/query_spec.go +++ b/x/spec/client/cli/query_spec.go @@ -16,7 +16,10 @@ func CmdListSpec() *cobra.Command { Use: "list-spec", Short: "list all Spec", RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } pageReq, err := client.ReadPageRequest(cmd.Flags()) if err != nil { @@ -59,7 +62,10 @@ func CmdShowSpec() *cobra.Command { Short: "shows a Spec", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := types.NewQueryClient(clientCtx) diff --git a/x/subscription/client/cli/query_params.go b/x/subscription/client/cli/query_params.go index 29edb28b47..e7b32a244d 100644 --- a/x/subscription/client/cli/query_params.go +++ b/x/subscription/client/cli/query_params.go @@ -15,7 +15,10 @@ func CmdQueryParams() *cobra.Command { Short: "shows the parameters of the module", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.GetClientContextFromCmd(cmd) + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } queryClient := types.NewQueryClient(clientCtx) From f01ff7a5edcc38a07a1cc62eaec585293c37b1e6 Mon Sep 17 00:00:00 2001 From: Elad Gildnur <6321801+shleikes@users.noreply.github.com> Date: Wed, 6 Dec 2023 09:58:43 -0500 Subject: [PATCH 38/85] Update SDK version to 0.30.3 (#1031) --- ecosystem/lava-sdk/package.json | 4 +- ecosystem/lava-sdk/yarn.lock | 401 +++++++++++++------------------- 2 files changed, 163 insertions(+), 242 deletions(-) diff --git a/ecosystem/lava-sdk/package.json b/ecosystem/lava-sdk/package.json index ddb97e0f6b..96f9d33b14 100644 --- a/ecosystem/lava-sdk/package.json +++ b/ecosystem/lava-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@lavanet/lava-sdk", - "version": "0.27.3", + "version": "0.30.3", "description": "An SDK for interacting with Lava provider", "main": "./bin/src/sdk/sdk.js", "author": "Lava Protocol Inc", @@ -113,4 +113,4 @@ "node": ">=18", "npm": ">=6.12.0" } -} +} \ No newline at end of file diff --git a/ecosystem/lava-sdk/yarn.lock b/ecosystem/lava-sdk/yarn.lock index 665752b56b..b0b8d3a208 100644 --- a/ecosystem/lava-sdk/yarn.lock +++ b/ecosystem/lava-sdk/yarn.lock @@ -22,7 +22,7 @@ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz" integrity sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ== -"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.8.0", "@babel/core@>=7.0.0-beta.0 <8": +"@babel/core@^7.11.6", "@babel/core@^7.12.3": version "7.20.2" resolved "https://registry.npmjs.org/@babel/core/-/core-7.20.2.tgz" integrity sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g== @@ -305,16 +305,6 @@ "@noble/hashes" "^1.0.0" protobufjs "^6.8.8" -"@cosmjs/amino@^0.29.4", "@cosmjs/amino@^0.29.5": - version "0.29.5" - resolved "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.29.5.tgz" - integrity sha512-Qo8jpC0BiziTSUqpkNatBcwtKNhCovUnFul9SlT/74JUCdLYaeG5hxr3q1cssQt++l4LvlcpF+OUXL48XjNjLw== - dependencies: - "@cosmjs/crypto" "^0.29.5" - "@cosmjs/encoding" "^0.29.5" - "@cosmjs/math" "^0.29.5" - "@cosmjs/utils" "^0.29.5" - "@cosmjs/amino@0.27.1": version "0.27.1" resolved "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.27.1.tgz" @@ -335,18 +325,15 @@ "@cosmjs/math" "0.28.2" "@cosmjs/utils" "0.28.2" -"@cosmjs/crypto@^0.29.4", "@cosmjs/crypto@^0.29.5": +"@cosmjs/amino@^0.29.4", "@cosmjs/amino@^0.29.5": version "0.29.5" - resolved "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.29.5.tgz" - integrity sha512-2bKkaLGictaNL0UipQCL6C1afaisv6k8Wr/GCLx9FqiyFkh9ZgRHDyetD64ZsjnWV/N/D44s/esI+k6oPREaiQ== + resolved "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.29.5.tgz" + integrity sha512-Qo8jpC0BiziTSUqpkNatBcwtKNhCovUnFul9SlT/74JUCdLYaeG5hxr3q1cssQt++l4LvlcpF+OUXL48XjNjLw== dependencies: + "@cosmjs/crypto" "^0.29.5" "@cosmjs/encoding" "^0.29.5" "@cosmjs/math" "^0.29.5" "@cosmjs/utils" "^0.29.5" - "@noble/hashes" "^1" - bn.js "^5.2.0" - elliptic "^6.5.4" - libsodium-wrappers "^0.7.6" "@cosmjs/crypto@0.27.1": version "0.27.1" @@ -377,14 +364,18 @@ elliptic "^6.5.3" libsodium-wrappers "^0.7.6" -"@cosmjs/encoding@^0.29.4", "@cosmjs/encoding@^0.29.5": +"@cosmjs/crypto@^0.29.4", "@cosmjs/crypto@^0.29.5": version "0.29.5" - resolved "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.29.5.tgz" - integrity sha512-G4rGl/Jg4dMCw5u6PEZHZcoHnUBlukZODHbm/wcL4Uu91fkn5jVo5cXXZcvs4VCkArVGrEj/52eUgTZCmOBGWQ== + resolved "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.29.5.tgz" + integrity sha512-2bKkaLGictaNL0UipQCL6C1afaisv6k8Wr/GCLx9FqiyFkh9ZgRHDyetD64ZsjnWV/N/D44s/esI+k6oPREaiQ== dependencies: - base64-js "^1.3.0" - bech32 "^1.1.4" - readonly-date "^1.0.0" + "@cosmjs/encoding" "^0.29.5" + "@cosmjs/math" "^0.29.5" + "@cosmjs/utils" "^0.29.5" + "@noble/hashes" "^1" + bn.js "^5.2.0" + elliptic "^6.5.4" + libsodium-wrappers "^0.7.6" "@cosmjs/encoding@0.27.1": version "0.27.1" @@ -404,6 +395,15 @@ bech32 "^1.1.4" readonly-date "^1.0.0" +"@cosmjs/encoding@^0.29.4", "@cosmjs/encoding@^0.29.5": + version "0.29.5" + resolved "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.29.5.tgz" + integrity sha512-G4rGl/Jg4dMCw5u6PEZHZcoHnUBlukZODHbm/wcL4Uu91fkn5jVo5cXXZcvs4VCkArVGrEj/52eUgTZCmOBGWQ== + dependencies: + base64-js "^1.3.0" + bech32 "^1.1.4" + readonly-date "^1.0.0" + "@cosmjs/json-rpc@0.28.2": version "0.28.2" resolved "https://registry.npmjs.org/@cosmjs/json-rpc/-/json-rpc-0.28.2.tgz" @@ -425,13 +425,6 @@ axios "^0.21.2" fast-deep-equal "^3.1.3" -"@cosmjs/math@^0.29.5": - version "0.29.5" - resolved "https://registry.npmjs.org/@cosmjs/math/-/math-0.29.5.tgz" - integrity sha512-2GjKcv+A9f86MAWYLUkjhw1/WpRl2R1BTb3m9qPG7lzMA7ioYff9jY5SPCfafKdxM4TIQGxXQlYGewQL16O68Q== - dependencies: - bn.js "^5.2.0" - "@cosmjs/math@0.27.1": version "0.27.1" resolved "https://registry.npmjs.org/@cosmjs/math/-/math-0.27.1.tgz" @@ -446,18 +439,12 @@ dependencies: bn.js "^5.2.0" -"@cosmjs/proto-signing@^0.29.4": +"@cosmjs/math@^0.29.5": version "0.29.5" - resolved "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.29.5.tgz" - integrity sha512-QRrS7CiKaoETdgIqvi/7JC2qCwCR7lnWaUsTzh/XfRy3McLkEd+cXbKAW3cygykv7IN0VAEIhZd2lyIfT8KwNA== + resolved "https://registry.npmjs.org/@cosmjs/math/-/math-0.29.5.tgz" + integrity sha512-2GjKcv+A9f86MAWYLUkjhw1/WpRl2R1BTb3m9qPG7lzMA7ioYff9jY5SPCfafKdxM4TIQGxXQlYGewQL16O68Q== dependencies: - "@cosmjs/amino" "^0.29.5" - "@cosmjs/crypto" "^0.29.5" - "@cosmjs/encoding" "^0.29.5" - "@cosmjs/math" "^0.29.5" - "@cosmjs/utils" "^0.29.5" - cosmjs-types "^0.5.2" - long "^4.0.0" + bn.js "^5.2.0" "@cosmjs/proto-signing@0.28.2": version "0.28.2" @@ -473,6 +460,19 @@ long "^4.0.0" protobufjs "~6.10.2" +"@cosmjs/proto-signing@^0.29.4": + version "0.29.5" + resolved "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.29.5.tgz" + integrity sha512-QRrS7CiKaoETdgIqvi/7JC2qCwCR7lnWaUsTzh/XfRy3McLkEd+cXbKAW3cygykv7IN0VAEIhZd2lyIfT8KwNA== + dependencies: + "@cosmjs/amino" "^0.29.5" + "@cosmjs/crypto" "^0.29.5" + "@cosmjs/encoding" "^0.29.5" + "@cosmjs/math" "^0.29.5" + "@cosmjs/utils" "^0.29.5" + cosmjs-types "^0.5.2" + long "^4.0.0" + "@cosmjs/socket@0.28.2": version "0.28.2" resolved "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.28.2.tgz" @@ -524,11 +524,6 @@ readonly-date "^1.0.0" xstream "^11.14.0" -"@cosmjs/utils@^0.29.5": - version "0.29.5" - resolved "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.29.5.tgz" - integrity sha512-m7h+RXDUxOzEOGt4P+3OVPX7PuakZT3GBmaM/Y2u+abN3xZkziykD/NvedYFvvCCdQo714XcGl33bwifS9FZPQ== - "@cosmjs/utils@0.27.1": version "0.27.1" resolved "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.27.1.tgz" @@ -539,6 +534,11 @@ resolved "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.28.2.tgz" integrity sha512-2/1UeE4djz6tt4B0j3YQS+k7BYoMkblfRa3+t3lht9N5/yj05ZxVUiP7hD0lQtNmeCSQgFFmtX6zXWPes+aKQg== +"@cosmjs/utils@^0.29.5": + version "0.29.5" + resolved "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.29.5.tgz" + integrity sha512-m7h+RXDUxOzEOGt4P+3OVPX7PuakZT3GBmaM/Y2u+abN3xZkziykD/NvedYFvvCCdQo714XcGl33bwifS9FZPQ== + "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" @@ -609,7 +609,7 @@ resolved "https://registry.npmjs.org/@improbable-eng/grpc-web-node-http-transport/-/grpc-web-node-http-transport-0.15.0.tgz" integrity sha512-HLgJfVolGGpjc9DWPhmMmXJx8YGzkek7jcCFO1YYkSOoO81MWRZentPOd/JiKiZuU08wtc4BG+WNuGzsQB5jZA== -"@improbable-eng/grpc-web@^0.15.0", "@improbable-eng/grpc-web@>=0.13.0": +"@improbable-eng/grpc-web@^0.15.0": version "0.15.0" resolved "https://registry.npmjs.org/@improbable-eng/grpc-web/-/grpc-web-0.15.0.tgz" integrity sha512-ERft9/0/8CmYalqOVnJnpdDry28q+j+nAlFFARdjyxXDJ+Mhgv9+F600QC8BR9ygOfrXRlAk6CvST2j+JCpQPg== @@ -812,7 +812,7 @@ slash "^3.0.0" write-file-atomic "^4.0.2" -"@jest/types@^29.0.0", "@jest/types@^29.6.3": +"@jest/types@^29.6.3": version "29.6.3" resolved "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz" integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== @@ -864,14 +864,6 @@ resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.14", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.19" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz" - integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - "@jridgewell/trace-mapping@0.3.9": version "0.3.9" resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" @@ -880,6 +872,14 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.14", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.19" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz" + integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + "@noble/hashes@^1", "@noble/hashes@^1.0.0", "@noble/hashes@^1.2.0": version "1.3.0" resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz" @@ -893,7 +893,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -1732,6 +1732,18 @@ resolved "https://registry.npmjs.org/@stdlib/math-base-special-gamma-lanczos-sum-expg-scaled/-/math-base-special-gamma-lanczos-sum-expg-scaled-0.0.7.tgz" integrity sha512-zjdpS8owElpxosiEs78XawbJ/+pvMsUdEN7ThLiGpTToSqffb/L9FGlD3uD/LiXHgiqs4CwsU1xBaX8cI6tn2A== +"@stdlib/math-base-special-gamma1pm1@^0.0.x": + version "0.0.6" + resolved "https://registry.npmjs.org/@stdlib/math-base-special-gamma1pm1/-/math-base-special-gamma1pm1-0.0.6.tgz" + integrity sha512-MAyGncYTJjdSAUCjezMq9ah+hEc4A3yiyTmBMtJ60xkFzRiMOgI+KZV8Yb3brtRWtMayGmRsarqbroXeAnzJKQ== + dependencies: + "@stdlib/constants-float64-eps" "^0.0.x" + "@stdlib/math-base-assert-is-nan" "^0.0.x" + "@stdlib/math-base-special-expm1" "^0.0.x" + "@stdlib/math-base-special-gamma" "^0.0.x" + "@stdlib/math-base-special-ln" "^0.0.x" + "@stdlib/math-base-special-log1p" "^0.0.x" + "@stdlib/math-base-special-gamma@^0.0.x": version "0.0.6" resolved "https://registry.npmjs.org/@stdlib/math-base-special-gamma/-/math-base-special-gamma-0.0.6.tgz" @@ -1751,18 +1763,6 @@ "@stdlib/math-base-special-pow" "^0.0.x" "@stdlib/math-base-special-sin" "^0.0.x" -"@stdlib/math-base-special-gamma1pm1@^0.0.x": - version "0.0.6" - resolved "https://registry.npmjs.org/@stdlib/math-base-special-gamma1pm1/-/math-base-special-gamma1pm1-0.0.6.tgz" - integrity sha512-MAyGncYTJjdSAUCjezMq9ah+hEc4A3yiyTmBMtJ60xkFzRiMOgI+KZV8Yb3brtRWtMayGmRsarqbroXeAnzJKQ== - dependencies: - "@stdlib/constants-float64-eps" "^0.0.x" - "@stdlib/math-base-assert-is-nan" "^0.0.x" - "@stdlib/math-base-special-expm1" "^0.0.x" - "@stdlib/math-base-special-gamma" "^0.0.x" - "@stdlib/math-base-special-ln" "^0.0.x" - "@stdlib/math-base-special-log1p" "^0.0.x" - "@stdlib/math-base-special-gammainc@^0.0.6": version "0.0.6" resolved "https://registry.npmjs.org/@stdlib/math-base-special-gammainc/-/math-base-special-gammainc-0.0.6.tgz" @@ -2486,7 +2486,7 @@ resolved "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz" integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== -"@types/node@*", "@types/node@^20.10.1", "@types/node@>=12.12.47", "@types/node@>=13.7.0": +"@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0", "@types/node@^20.10.1": version "20.10.3" resolved "https://registry.npmjs.org/@types/node/-/node-20.10.3.tgz" integrity sha512-XJavIpZqiXID5Yxnxv3RUDKTN5b81ddNC3ecsA0SoFXz/QU8OGBwZGMomiq0zw+uuqbL/krztv/DINAQ/EV4gg== @@ -2545,7 +2545,7 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/parser@^5.0.0", "@typescript-eslint/parser@^5.45.0": +"@typescript-eslint/parser@^5.45.0": version "5.46.0" resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.46.0.tgz" integrity sha512-joNO6zMGUZg+C73vwrKXCd8usnsmOYmgW/w5ZW0pG0RGvqeznjtGDk61EqqTpNrFLUYBW2RSBFrxdAZMqA4OZA== @@ -2776,7 +2776,7 @@ acorn-walk@^8.1.1: resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== -"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8, acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.1, acorn@^8.8.0: +acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.1, acorn@^8.8.0: version "8.8.1" resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz" integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA== @@ -2791,7 +2791,7 @@ ajv-keywords@^3.5.2: resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5, ajv@^6.9.1: +ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -2883,7 +2883,7 @@ axios@^0.21.2: dependencies: follow-redirects "^1.14.0" -babel-jest@^29.0.0, babel-jest@^29.7.0: +babel-jest@^29.7.0: version "29.7.0" resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz" integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== @@ -3020,7 +3020,7 @@ browser-headers@^0.4.1: resolved "https://registry.npmjs.org/browser-headers/-/browser-headers-0.4.1.tgz" integrity sha512-CA9hsySZVo9371qEHjHZtYxV2cFtVj5Wj/ZHi8ooEsrtm4vOnl9Y9HmyYWk9q+05d7K3rdoAE0j3MVEFVvtQtg== -browserslist@^4.14.5, browserslist@^4.21.3, "browserslist@>= 4.21.0": +browserslist@^4.14.5, browserslist@^4.21.3: version "4.21.4" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz" integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw== @@ -3118,6 +3118,14 @@ case-anything@^2.1.10: resolved "https://registry.npmjs.org/case-anything/-/case-anything-2.1.10.tgz" integrity sha512-JczJwVrCP0jPKh05McyVsuOg6AYosrB9XWZKbQzXeDAm2ClE/PJE/BcrrQrVyGYH7Jg8V/LDupmyL4kFlVsVFQ== +chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chalk@^2.0.0: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" @@ -3127,14 +3135,6 @@ chalk@^2.0.0: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0, chalk@^4.1.2, chalk@4.1.2: - version "4.1.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - char-regex@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz" @@ -3213,27 +3213,22 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - color-name@1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + colorette@^2.0.14: version "2.0.19" resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz" integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== -commander@^2.20.0: - version "2.20.3" - resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -commander@^2.8.1: +commander@^2.20.0, commander@^2.8.1: version "2.20.3" resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -3565,12 +3560,7 @@ escalade@^3.1.1: resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== -escape-string-regexp@^1.0.2: - version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== @@ -3597,7 +3587,7 @@ eslint-plugin-prettier@^4.2.1: dependencies: prettier-linter-helpers "^1.0.0" -eslint-scope@^5.1.1, eslint-scope@5.1.1: +eslint-scope@5.1.1, eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== @@ -3630,7 +3620,7 @@ eslint-visitor-keys@^3.3.0: resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz" integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@*, "eslint@^6.0.0 || ^7.0.0 || ^8.0.0", eslint@^8.29.0, eslint@>=5, eslint@>=7.0.0, eslint@>=7.28.0: +eslint@^8.29.0: version "8.29.0" resolved "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz" integrity sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg== @@ -3795,7 +3785,7 @@ fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0, fast-json-stable-stringify@2.x: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -3936,6 +3926,11 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +fsevents@^2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + function-bind@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" @@ -3965,6 +3960,11 @@ get-package-type@^0.1.0: resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== +get-stream@3.0.0, get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz" + integrity sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ== + get-stream@^2.2.0: version "2.3.1" resolved "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz" @@ -3973,11 +3973,6 @@ get-stream@^2.2.0: object-assign "^4.0.1" pinkie-promise "^2.0.0" -get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz" - integrity sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ== - get-stream@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz" @@ -3990,11 +3985,6 @@ get-stream@^6.0.0: resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -get-stream@3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz" - integrity sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ== - glob-parent@^5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" @@ -4057,7 +4047,7 @@ globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" -google-protobuf@^3.14.0, google-protobuf@^3.15.5, google-protobuf@^3.21.2: +google-protobuf@^3.15.5, google-protobuf@^3.21.2: version "3.21.2" resolved "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz" integrity sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA== @@ -4268,7 +4258,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3, inherits@2: +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -4652,7 +4642,7 @@ jest-resolve-dependencies@^29.7.0: jest-regex-util "^29.6.3" jest-snapshot "^29.7.0" -jest-resolve@*, jest-resolve@^29.7.0: +jest-resolve@^29.7.0: version "29.7.0" resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz" integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== @@ -4805,7 +4795,7 @@ jest-worker@^29.7.0: merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^29.0.0, jest@^29.3.1: +jest@^29.3.1: version "29.7.0" resolved "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz" integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== @@ -4971,16 +4961,16 @@ long@^5.0.0, long@^5.2.1: resolved "https://registry.npmjs.org/long/-/long-5.2.1.tgz" integrity sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A== -lowercase-keys@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz" - integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== - lowercase-keys@1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz" integrity sha512-RPlX0+PHuvxVDZ7xX+EBVAp4RsVxP/TdDSN2mJYdiq1Lc4Hz7EUSjUI7RZrKKlmrIzVhf6Jo2stj7++gVarS0A== +lowercase-keys@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + lru-cache@^10.0.1: version "10.0.1" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz" @@ -5015,7 +5005,7 @@ make-dir@^4.0.0: dependencies: semver "^7.5.3" -make-error@^1.1.1, make-error@1.x: +make-error@1.x, make-error@^1.1.1: version "1.3.6" resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== @@ -5045,7 +5035,7 @@ micromatch@^4.0.4: braces "^3.0.2" picomatch "^2.3.1" -mime-db@^1.28.0, mime-db@1.52.0: +mime-db@1.52.0, mime-db@^1.28.0: version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== @@ -5101,11 +5091,6 @@ mkdirp@^0.5.6: dependencies: minimist "^1.2.6" -ms@^2.1.1: - version "2.1.3" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - ms@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" @@ -5116,6 +5101,11 @@ ms@2.1.2: resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + natural-compare-lite@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz" @@ -5392,7 +5382,7 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@^2.8.0, prettier@>=2.0.0: +prettier@^2.8.0: version "2.8.0" resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.0.tgz" integrity sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA== @@ -5419,26 +5409,7 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -protobufjs@^6.11.3: - version "6.11.3" - resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz" - integrity sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg== - dependencies: - "@protobufjs/aspromise" "^1.1.2" - "@protobufjs/base64" "^1.1.2" - "@protobufjs/codegen" "^2.0.4" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" - "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.0" - "@protobufjs/path" "^1.1.2" - "@protobufjs/pool" "^1.1.0" - "@protobufjs/utf8" "^1.1.0" - "@types/long" "^4.0.1" - "@types/node" ">=13.7.0" - long "^4.0.0" - -protobufjs@^6.8.8: +protobufjs@^6.11.3, protobufjs@^6.8.8, protobufjs@~6.11.2: version "6.11.3" resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz" integrity sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg== @@ -5494,25 +5465,6 @@ protobufjs@~6.10.2: "@types/node" "^13.7.0" long "^4.0.0" -protobufjs@~6.11.2: - version "6.11.3" - resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.3.tgz" - integrity sha512-xL96WDdCZYdU7Slin569tFX712BxsxslWwAfAhCYjQKGTq7dAU91Lomy6nLLhh/dyGhk/YH4TwTSRxTzhuHyZg== - dependencies: - "@protobufjs/aspromise" "^1.1.2" - "@protobufjs/base64" "^1.1.2" - "@protobufjs/codegen" "^2.0.4" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" - "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.0" - "@protobufjs/path" "^1.1.2" - "@protobufjs/pool" "^1.1.0" - "@protobufjs/utf8" "^1.1.0" - "@types/long" "^4.0.1" - "@types/node" ">=13.7.0" - long "^4.0.0" - protoc-gen-js@^3.21.2: version "3.21.2" resolved "https://registry.npmjs.org/protoc-gen-js/-/protoc-gen-js-3.21.2.tgz" @@ -5577,33 +5529,7 @@ react-is@^18.0.0: resolved "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== -readable-stream@^2.0.0: - version "2.3.8" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" - integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readable-stream@^2.3.0: - version "2.3.8" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" - integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readable-stream@^2.3.5: +readable-stream@^2.0.0, readable-stream@^2.3.0, readable-stream@^2.3.5: version "2.3.8" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -5724,20 +5650,15 @@ rxjs@^7.5.7: dependencies: tslib "^2.1.0" -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.2.0, safe-buffer@~5.2.0, safe-buffer@5.2.1: - version "5.2.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.2.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" @@ -5770,6 +5691,13 @@ seek-bzip@^1.0.5: dependencies: commander "^2.8.1" +semver@7.x, semver@^7.3.7, semver@^7.5.3, semver@^7.5.4: + version "7.5.4" + resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + semver@^5.6.0: version "5.7.2" resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" @@ -5780,13 +5708,6 @@ semver@^6.3.0: resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.3.7, semver@^7.5.3, semver@^7.5.4, semver@7.x: - version "7.5.4" - resolved "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz" - integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== - dependencies: - lru-cache "^6.0.0" - serialize-javascript@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz" @@ -5857,14 +5778,6 @@ sort-keys@^2.0.0: dependencies: is-plain-obj "^1.0.0" -source-map-support@~0.5.20: - version "0.5.21" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - source-map-support@0.5.13: version "0.5.13" resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz" @@ -5873,6 +5786,14 @@ source-map-support@0.5.13: buffer-from "^1.0.0" source-map "^0.6.0" +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map@^0.6.0, source-map@^0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" @@ -5895,20 +5816,6 @@ strict-uri-encode@^1.0.0: resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz" integrity sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ== -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - string-length@^4.0.1: version "4.0.2" resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz" @@ -5926,6 +5833,20 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" @@ -6099,7 +6020,7 @@ ts-jest@^29.0.3: semver "7.x" yargs-parser "^21.0.1" -ts-node@^10.9.1, ts-node@>=9.0.0: +ts-node@^10.9.1: version "10.9.1" resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz" integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== @@ -6192,7 +6113,7 @@ type-fest@^0.21.3: resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== -typescript@^4.8.4, typescript@>=2.7, "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta", typescript@>=4.3: +typescript@^4.8.4: version "4.8.4" resolved "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz" integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== @@ -6283,7 +6204,7 @@ watchpack@^2.4.0: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" -webpack-cli@^4.10.0, webpack-cli@4.x.x: +webpack-cli@^4.10.0: version "4.10.0" resolved "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz" integrity sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w== @@ -6314,7 +6235,7 @@ webpack-sources@^3.2.3: resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@^5.1.0, webpack@^5.74.0, "webpack@4.x.x || 5.x.x": +webpack@^5.74.0: version "5.74.0" resolved "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz" integrity sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA== @@ -6390,7 +6311,7 @@ write-file-atomic@^4.0.2: imurmurhash "^0.1.4" signal-exit "^3.0.7" -ws@*, ws@^7: +ws@^7: version "7.5.9" resolved "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz" integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== From 7afb3bf8488efce7e0ce3b9e54eacf2f68c10c16 Mon Sep 17 00:00:00 2001 From: Omer <100387053+omerlavanet@users.noreply.github.com> Date: Wed, 6 Dec 2023 17:01:06 +0200 Subject: [PATCH 39/85] PRT-resume-service-faster-if-verification-passes (#1027) * query disabled chains more often allowing providers to resume service faster * lint + rename * fix wrong time in the test * polling time test more robust to slow machines * improve success chance in slow machines * Removed unnecessary struct field from SpecValidtor --------- Co-authored-by: Elad Gildnur --- protocol/chaintracker/chain_tracker_test.go | 13 +++-- protocol/rpcprovider/rpcprovider.go | 3 +- .../rpcprovider/rpcprovider_server_test.go | 9 ++-- protocol/rpcprovider/spec_validator.go | 51 ++++++++++++++++--- protocol/rpcprovider/spec_validator_test.go | 2 +- 5 files changed, 62 insertions(+), 16 deletions(-) diff --git a/protocol/chaintracker/chain_tracker_test.go b/protocol/chaintracker/chain_tracker_test.go index fce9ee0dd5..520890ec91 100644 --- a/protocol/chaintracker/chain_tracker_test.go +++ b/protocol/chaintracker/chain_tracker_test.go @@ -469,12 +469,12 @@ func TestChainTrackerPollingTimeUpdate(t *testing.T) { t.Run(play.name, func(t *testing.T) { mockBlocks := int64(25) fetcherBlocks := 1 - called := 0 + called := false callback := func() { - called++ } updatedTime := 0 * time.Second updateCallback := func(arg time.Duration) { + called = true updatedTime = arg } mockTimeUpdater := MockTimeUpdater{callBack: updateCallback} @@ -492,11 +492,14 @@ func TestChainTrackerPollingTimeUpdate(t *testing.T) { time.Sleep(play.updateTime) } // give it more time to update in case it didn't trigger on slow machines - if updatedTime.Milliseconds() == 0 { - time.Sleep(10 * play.updateTime) + if !called { + for i := 0; i < iterations*2; i++ { + mockChainFetcher.AdvanceBlock() + time.Sleep(play.updateTime) + } } require.InDelta(t, play.updateTime, updatedTime, float64(play.updateTime)*0.2) - // if we wait more time we expect this to fine tune + // if we wait more time we expect this to stay correct for i := 0; i < iterations*4; i++ { mockChainFetcher.AdvanceBlock() time.Sleep(play.updateTime) diff --git a/protocol/rpcprovider/rpcprovider.go b/protocol/rpcprovider/rpcprovider.go index cb50d4db0b..93f9bdd4c5 100644 --- a/protocol/rpcprovider/rpcprovider.go +++ b/protocol/rpcprovider/rpcprovider.go @@ -596,7 +596,8 @@ rpcprovider 127.0.0.1:3333 COS3 tendermintrpc "wss://www.node-path.com:80,https: cmdRPCProvider.Flags().Uint(rewardserver.RewardsSnapshotTimeoutSecFlagName, rewardserver.DefaultRewardsSnapshotTimeoutSec, "the seconds to wait until making snapshot of the rewards memory") cmdRPCProvider.Flags().String(StickinessHeaderName, RPCProviderStickinessHeaderName, "the name of the header to be attacked to requests for stickiness by consumer, used for consistency") cmdRPCProvider.Flags().Uint64Var(&chaintracker.PollingMultiplier, chaintracker.PollingMultiplierFlagName, 1, "when set, forces the chain tracker to poll more often, improving the sync at the cost of more queries") - cmdRPCProvider.Flags().Uint64Var(&SpecValidationIntervalSec, SpecValidationIntervalSecFlagName, SpecValidationIntervalSec, "determines the interval of which to run validation on the spec for all connected chains") + cmdRPCProvider.Flags().DurationVar(&SpecValidationInterval, SpecValidationIntervalFlagName, SpecValidationInterval, "determines the interval of which to run validation on the spec for all connected chains") + cmdRPCProvider.Flags().DurationVar(&SpecValidationIntervalDisabledChains, SpecValidationIntervalDisabledChainsFlagName, SpecValidationIntervalDisabledChains, "determines the interval of which to run validation on the spec for all disabled chains, determines recovery time") common.AddRollingLogConfig(cmdRPCProvider) return cmdRPCProvider } diff --git a/protocol/rpcprovider/rpcprovider_server_test.go b/protocol/rpcprovider/rpcprovider_server_test.go index ddf03311f8..8efa93f7e4 100644 --- a/protocol/rpcprovider/rpcprovider_server_test.go +++ b/protocol/rpcprovider/rpcprovider_server_test.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/http" + "strconv" "testing" "time" @@ -194,7 +195,7 @@ func TestHandleConsistency(t *testing.T) { requestBlock: 10001, specId: "LAV1", err: nil, - timeout: 25 * time.Millisecond, // 150 is one way travel time + timeout: 50 * time.Millisecond, // 150 is one way travel time chainTrackerBlocks: []int64{100, 101}, changeTime: 100 * time.Second, sleep: true, @@ -205,7 +206,7 @@ func TestHandleConsistency(t *testing.T) { requestBlock: 101, specId: "LAV1", err: nil, - timeout: 25 * time.Millisecond, // 150 is one way travel time + timeout: 50 * time.Millisecond, // 150 is one way travel time chainTrackerBlocks: []int64{100, 101}, changeTime: 100 * time.Second, sleep: true, @@ -227,6 +228,7 @@ func TestHandleConsistency(t *testing.T) { } mockChainTracker := &MockChainTracker{} require.GreaterOrEqual(t, len(play.chainTrackerBlocks), 1) + calls := 1 // how many times we have setLatestBlock in the mock mockChainTracker.SetLatestBlock(play.chainTrackerBlocks[0], time.Now().Add(-1*play.changeTime)) // change time is only in the past require.NoError(t, err) reliabilityManager := reliabilitymanager.NewReliabilityManager(mockChainTracker, nil, ts.Providers[0].Addr.String(), chainProxy, chainParser) @@ -245,12 +247,13 @@ func TestHandleConsistency(t *testing.T) { nextBlock := play.chainTrackerBlocks[1] time.Sleep(6 * time.Millisecond) mockChainTracker.SetLatestBlock(nextBlock, time.Now()) + calls += 1 } }() ctx, cancel := context.WithTimeout(context.Background(), play.timeout) latestBlock, _, timeSlept, err := rpcproviderServer.handleConsistency(ctx, seenBlock, requestBlock, averageBlockTime, blockLagForQosSync, blocksInFinalizationData, blockDistanceToFinalization) cancel() - require.Equal(t, play.err == nil, err == nil, err) + require.Equal(t, play.err == nil, err == nil, err, strconv.Itoa(calls)) require.Less(t, timeSlept, play.timeout) if play.sleep { require.NotZero(t, timeSlept) diff --git a/protocol/rpcprovider/spec_validator.go b/protocol/rpcprovider/spec_validator.go index 9f779b6a7f..6d0628bee4 100644 --- a/protocol/rpcprovider/spec_validator.go +++ b/protocol/rpcprovider/spec_validator.go @@ -12,10 +12,14 @@ import ( ) const ( - SpecValidationIntervalSecFlagName = "spec-validation-interval-sec" + SpecValidationIntervalFlagName = "spec-validation-interval" + SpecValidationIntervalDisabledChainsFlagName = "spec-validation-interval-disabled-chains" ) -var SpecValidationIntervalSec = uint64(10800) // 3 Hours +var ( + SpecValidationInterval = 3 * time.Hour + SpecValidationIntervalDisabledChains = 10 * time.Minute +) type SpecValidator struct { lock sync.RWMutex @@ -41,18 +45,26 @@ func (sv *SpecValidator) Start(ctx context.Context) { } func (sv *SpecValidator) validateAllChainsLoop(ctx context.Context) { - timerInterval := time.Duration(SpecValidationIntervalSec) * time.Second - ticker := time.NewTicker(timerInterval) + validationTicker := time.NewTicker(SpecValidationInterval) + validationTickerForDisabled := time.NewTicker(SpecValidationIntervalDisabledChains) for { select { - case <-ticker.C: + case <-validationTicker.C: func() { sv.lock.Lock() defer sv.lock.Unlock() sv.validateAllChains(ctx) + // we just ran validate on all chains no reason to do disabled chains in the next interval + validationTickerForDisabled.Reset(SpecValidationIntervalDisabledChains) + }() + case <-validationTickerForDisabled.C: + func() { + sv.lock.Lock() + defer sv.lock.Unlock() + sv.validateAllDisabledChains(ctx) }() case <-ctx.Done(): - ticker.Stop() + validationTicker.Stop() return } } @@ -112,6 +124,33 @@ func (sv *SpecValidator) validateAllChains(ctx context.Context) { } } +func (sv *SpecValidator) validateAllDisabledChains(ctx context.Context) { + for chainId := range sv.getDisabledChains(ctx) { + sv.validateChain(ctx, chainId) + } +} + +func (sv *SpecValidator) getDisabledChains(ctx context.Context) map[string]struct{} { + disabledChains := map[string]struct{}{} + for _, chainFetchersList := range sv.chainFetchers { + for _, chainFetcher := range chainFetchersList { + rpcEndpoint := sv.getRpcProviderEndpointFromChainFetcher(chainFetcher) + providerListener, found := sv.providerListeners[rpcEndpoint.NetworkAddress] + if !found { + continue + } + relayReceiver, found := providerListener.relayServer.relayReceivers[rpcEndpoint.Key()] + if !found { + continue + } + if !relayReceiver.enabled { + disabledChains[rpcEndpoint.ChainID] = struct{}{} + } + } + } + return disabledChains +} + func (sv *SpecValidator) validateChain(ctx context.Context, chainId string) error { errors := []error{} for _, chainFetcher := range sv.chainFetchers[chainId] { diff --git a/protocol/rpcprovider/spec_validator_test.go b/protocol/rpcprovider/spec_validator_test.go index 0a0b0c2e5f..1bd109b68f 100644 --- a/protocol/rpcprovider/spec_validator_test.go +++ b/protocol/rpcprovider/spec_validator_test.go @@ -88,7 +88,7 @@ func TestStartCallsAllValidateFunctions(t *testing.T) { chainFetcher.EXPECT().Validate(gomock.Any()).Times(1).After(firstCall).Do(raiseCallCount) } - SpecValidationIntervalSec = 1 + SpecValidationInterval = 1 * time.Second ctx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() specValidator.Start(ctx) From 9057dba5884a93291d7ad7d1e303c294a5fa2f37 Mon Sep 17 00:00:00 2001 From: Elad Gildnur <6321801+shleikes@users.noreply.github.com> Date: Thu, 7 Dec 2023 03:16:38 -0500 Subject: [PATCH 40/85] Fix a bug that caused new specs not to be checked (#1032) --- protocol/rpcprovider/rpcprovider.go | 5 +- protocol/rpcprovider/spec_validator.go | 3 +- protocol/rpcprovider/spec_validator_test.go | 6 +-- .../statetracker/provider_state_tracker.go | 11 ++++ protocol/statetracker/spec_updater.go | 53 ++++++++++++++++++- 5 files changed, 71 insertions(+), 7 deletions(-) diff --git a/protocol/rpcprovider/rpcprovider.go b/protocol/rpcprovider/rpcprovider.go index 93f9bdd4c5..c4893e6eb2 100644 --- a/protocol/rpcprovider/rpcprovider.go +++ b/protocol/rpcprovider/rpcprovider.go @@ -54,6 +54,7 @@ var ( type ProviderStateTrackerInf interface { RegisterForVersionUpdates(ctx context.Context, version *protocoltypes.Version, versionValidator statetracker.VersionValidationInf) RegisterForSpecUpdates(ctx context.Context, specUpdatable statetracker.SpecUpdatable, endpoint lavasession.RPCEndpoint) error + RegisterForSpecVerifications(ctx context.Context, specVerifier statetracker.SpecVerifier, endpoint lavasession.RPCEndpoint) error RegisterReliabilityManagerForVoteUpdates(ctx context.Context, voteUpdatable statetracker.VoteUpdatable, endpointP *lavasession.RPCProviderEndpoint) RegisterForEpochUpdates(ctx context.Context, epochUpdatable statetracker.EpochUpdatable) RegisterForDowntimeParamsUpdates(ctx context.Context, downtimeParamsUpdatable statetracker.DowntimeParamsUpdatable) error @@ -339,7 +340,9 @@ func (rpcp *RPCProvider) SetupEndpoint(ctx context.Context, rpcProviderEndpoint // Any validation needs to be before we store chain tracker for given chain id rpcp.chainTrackers.SetTrackerForChain(rpcProviderEndpoint.ChainID, chainTracker) - err = rpcp.providerStateTracker.RegisterForSpecUpdates(ctx, specValidator, rpcEndpoint) + err = rpcp.providerStateTracker.RegisterForSpecVerifications(ctx, specValidator, rpcEndpoint) + utils.LavaFormatDebug("Registering for spec verifications for endpoint", + utils.LogAttr("rpcEndpoint", rpcEndpoint)) if err != nil { return utils.LavaFormatError("failed to RegisterForSpecUpdates, panic severity critical error, aborting support for chain api due to invalid chain parser, continuing with others", err, utils.Attribute{Key: "endpoint", Value: rpcProviderEndpoint.String()}) } diff --git a/protocol/rpcprovider/spec_validator.go b/protocol/rpcprovider/spec_validator.go index 6d0628bee4..37745fd983 100644 --- a/protocol/rpcprovider/spec_validator.go +++ b/protocol/rpcprovider/spec_validator.go @@ -92,7 +92,7 @@ func (sv *SpecValidator) AddRPCProviderListener(address string, providerListener sv.providerListeners[address] = providerListener } -func (sv *SpecValidator) SetSpec(spec spectypes.Spec) { +func (sv *SpecValidator) VerifySpec(spec spectypes.Spec) { sv.lock.Lock() defer sv.lock.Unlock() @@ -101,6 +101,7 @@ func (sv *SpecValidator) SetSpec(spec spectypes.Spec) { utils.LavaFormatError("Could not find chainFetchers with given chainId", nil, utils.Attribute{Key: "chainId", Value: chainId}) return } + utils.LavaFormatDebug("Running spec verification for chainId", utils.LogAttr("chainId", chainId)) sv.validateChain(context.Background(), chainId) } diff --git a/protocol/rpcprovider/spec_validator_test.go b/protocol/rpcprovider/spec_validator_test.go index 1bd109b68f..f7780ccaa6 100644 --- a/protocol/rpcprovider/spec_validator_test.go +++ b/protocol/rpcprovider/spec_validator_test.go @@ -17,7 +17,7 @@ func TestSetSpecWithoutChainFetchersNorProviderListenerNoErrors(t *testing.T) { spec := testcommon.CreateMockSpec() specValidator := NewSpecValidator() - require.NotPanics(t, func() { specValidator.SetSpec(spec) }) + require.NotPanics(t, func() { specValidator.VerifySpec(spec) }) } func TestSetSpecWithoutRelayReceiversNoErrors(t *testing.T) { @@ -28,7 +28,7 @@ func TestSetSpecWithoutRelayReceiversNoErrors(t *testing.T) { specValidator := NewSpecValidator() specValidator.AddRPCProviderListener("", providerListener) - require.NotPanics(t, func() { specValidator.SetSpec(spec) }) + require.NotPanics(t, func() { specValidator.VerifySpec(spec) }) } func TestAddChainFetcherAndSetSpecCallsValidate(t *testing.T) { @@ -52,7 +52,7 @@ func TestAddChainFetcherAndSetSpecCallsValidate(t *testing.T) { specValidator.AddChainFetcher(ctx, &chainFetcherIf, specName) chainFetcher.EXPECT().Validate(gomock.Any()).Times(1).After(firstCall) - specValidator.SetSpec(spec) + specValidator.VerifySpec(spec) } func TestStartCallsAllValidateFunctions(t *testing.T) { diff --git a/protocol/statetracker/provider_state_tracker.go b/protocol/statetracker/provider_state_tracker.go index 4b152aa196..8dd53aa0f4 100644 --- a/protocol/statetracker/provider_state_tracker.go +++ b/protocol/statetracker/provider_state_tracker.go @@ -66,6 +66,17 @@ func (pst *ProviderStateTracker) RegisterForSpecUpdates(ctx context.Context, spe return specUpdater.RegisterSpecUpdatable(ctx, &specUpdatable, endpoint) } +func (pst *ProviderStateTracker) RegisterForSpecVerifications(ctx context.Context, specVerifier SpecVerifier, endpoint lavasession.RPCEndpoint) error { + // register for spec verifications sets spec and verifies when a spec has been modified + specUpdater := NewSpecUpdater(endpoint.ChainID, pst.stateQuery, pst.EventTracker) + specUpdaterRaw := pst.StateTracker.RegisterForUpdates(ctx, specUpdater) + specUpdater, ok := specUpdaterRaw.(*SpecUpdater) + if !ok { + utils.LavaFormatFatal("invalid updater type returned from RegisterForSpecVerifications", nil, utils.Attribute{Key: "updater", Value: specUpdaterRaw}) + } + return specUpdater.RegisterSpecVerifier(ctx, &specVerifier, endpoint) +} + func (pst *ProviderStateTracker) RegisterForVersionUpdates(ctx context.Context, version *protocoltypes.Version, versionValidator VersionValidationInf) { versionUpdater := NewVersionUpdater(pst.stateQuery, pst.EventTracker, version, versionValidator) versionUpdaterRaw := pst.StateTracker.RegisterForUpdates(ctx, versionUpdater) diff --git a/protocol/statetracker/spec_updater.go b/protocol/statetracker/spec_updater.go index dd9908abf6..ae9321ad44 100644 --- a/protocol/statetracker/spec_updater.go +++ b/protocol/statetracker/spec_updater.go @@ -24,6 +24,11 @@ type SpecUpdatable interface { GetUniqueName() string } +type SpecVerifier interface { + VerifySpec(spectypes.Spec) + GetUniqueName() string +} + type SpecUpdater struct { lock sync.RWMutex eventTracker *EventTracker @@ -31,11 +36,12 @@ type SpecUpdater struct { specGetter SpecGetter blockLastUpdated uint64 specUpdatables map[string]*SpecUpdatable + specVerifiers map[string]*SpecVerifier spec *spectypes.Spec } func NewSpecUpdater(chainId string, specGetter SpecGetter, eventTracker *EventTracker) *SpecUpdater { - return &SpecUpdater{chainId: chainId, specGetter: specGetter, eventTracker: eventTracker, specUpdatables: map[string]*SpecUpdatable{}} + return &SpecUpdater{chainId: chainId, specGetter: specGetter, eventTracker: eventTracker, specUpdatables: map[string]*SpecUpdatable{}, specVerifiers: map[string]*SpecVerifier{}} } func (su *SpecUpdater) UpdaterKey() string { @@ -74,7 +80,41 @@ func (su *SpecUpdater) RegisterSpecUpdatable(ctx context.Context, specUpdatable } } (*specUpdatable).SetSpec(*spec) - su.specUpdatables[endpoint.Key()] = specUpdatable + su.specUpdatables[key] = specUpdatable + return nil +} + +func (su *SpecUpdater) RegisterSpecVerifier(ctx context.Context, specVerifier *SpecVerifier, endpoint lavasession.RPCEndpoint) error { + su.lock.Lock() + defer su.lock.Unlock() + + // validating + if su.chainId != endpoint.ChainID { + return utils.LavaFormatError("panic level error Trying to register spec for wrong chain id stored in spec_updater", nil, utils.Attribute{Key: "endpoint", Value: endpoint}, utils.Attribute{Key: "stored_spec", Value: su.chainId}) + } + + verifierUniqueName := (*specVerifier).GetUniqueName() + key := strings.Join([]string{verifierUniqueName, endpoint.Key()}, "_") + existingSpecVerifier, found := su.specVerifiers[key] + if found { + return utils.LavaFormatError("panic level error Trying to register to spec verifications on already registered verifier unique name + chain + API interface", nil, + utils.Attribute{Key: "verifierUniqueName", Value: verifierUniqueName}, + utils.Attribute{Key: "endpoint", Value: endpoint}, + utils.Attribute{Key: "specVerifier", Value: existingSpecVerifier}) + } + + var spec *spectypes.Spec + if su.spec != nil { + spec = su.spec + } else { // we don't have spec stored so we need to fetch it + var err error + spec, err = su.specGetter.GetSpec(ctx, su.chainId) + if err != nil { + return utils.LavaFormatError("panic level error could not get chain spec failed registering", err, utils.LogAttr("chainID", su.chainId)) + } + } + (*specVerifier).VerifySpec(*spec) + su.specVerifiers[key] = specVerifier return nil } @@ -92,7 +132,16 @@ func (su *SpecUpdater) Update(latestBlock int64) { su.blockLastUpdated = spec.BlockLastUpdated } for _, specUpdatable := range su.specUpdatables { + utils.LavaFormatDebug("SpecUpdater: updating spec for chainId", + utils.LogAttr("chainId", su.chainId), + utils.LogAttr("specUpdatable", (*specUpdatable).GetUniqueName())) (*specUpdatable).SetSpec(*spec) } + for _, specVerifier := range su.specVerifiers { + utils.LavaFormatDebug("SpecUpdater: updating spec for chainId", + utils.LogAttr("chainId", su.chainId), + utils.LogAttr("specVerifier", (*specVerifier).GetUniqueName())) + (*specVerifier).VerifySpec(*spec) + } } } From f25dcd6c62eef83566652eeb78d33ee5b6838138 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Thu, 7 Dec 2023 08:43:05 +0000 Subject: [PATCH 41/85] done --- x/dualstaking/keeper/delegator_reward.go | 36 +++++++++---------- .../keeper/grpc_query_effective_policy.go | 4 +-- x/pairing/keeper/pairing.go | 6 ++-- x/pairing/keeper/pairing_test.go | 6 ++-- x/pairing/keeper/query_sdk_pairing.go | 2 +- 5 files changed, 25 insertions(+), 29 deletions(-) diff --git a/x/dualstaking/keeper/delegator_reward.go b/x/dualstaking/keeper/delegator_reward.go index ea5fb5f994..e4da8e0abb 100644 --- a/x/dualstaking/keeper/delegator_reward.go +++ b/x/dualstaking/keeper/delegator_reward.go @@ -202,15 +202,7 @@ func (k Keeper) RewardProvidersAndDelegators(ctx sdk.Context, providerAddr sdk.A if !calcOnlyProvider { if fullProviderReward.GT(math.ZeroInt()) { - fullProviderRewardCoins := sdk.Coins{sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), fullProviderReward)} - err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, senderModule, providerAddr, fullProviderRewardCoins) - if err != nil { - // panic:ok: reward transfer should never fail - utils.LavaFormatPanic("critical: failed to send reward to provider", err, - utils.Attribute{Key: "provider", Value: providerAddr}, - utils.Attribute{Key: "reward", Value: fullProviderRewardCoins}, - ) - } + k.rewardDelegator(ctx, types.Delegation{Provider: providerAddr.String(), ChainID: chainID, Delegator: providerAddr.String()}, fullProviderReward) } } @@ -223,19 +215,9 @@ func (k Keeper) updateDelegatorsReward(ctx sdk.Context, totalDelegations math.In for _, delegation := range delegations { delegatorRewardAmount := k.CalcDelegatorReward(delegatorsReward, totalDelegations, delegation) - rewardMapKey := types.DelegationKey(delegation.Provider, delegation.Delegator, delegation.ChainID) - delegatorReward, found := k.GetDelegatorReward(ctx, rewardMapKey) if !calcOnly { - if !found { - delegatorReward.Provider = delegation.Provider - delegatorReward.Delegator = delegation.Delegator - delegatorReward.ChainId = delegation.ChainID - delegatorReward.Amount = sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), delegatorRewardAmount) - } else { - delegatorReward.Amount = delegatorReward.Amount.AddAmount(delegatorRewardAmount) - } - k.SetDelegatorReward(ctx, delegatorReward) + k.rewardDelegator(ctx, delegation, delegatorRewardAmount) } usedDelegatorRewards = usedDelegatorRewards.Add(delegatorRewardAmount) @@ -244,6 +226,20 @@ func (k Keeper) updateDelegatorsReward(ctx sdk.Context, totalDelegations math.In return delegatorsReward.Sub(usedDelegatorRewards) } +func (k Keeper) rewardDelegator(ctx sdk.Context, delegation types.Delegation, amount math.Int) { + rewardMapKey := types.DelegationKey(delegation.Provider, delegation.Delegator, delegation.ChainID) + delegatorReward, found := k.GetDelegatorReward(ctx, rewardMapKey) + if !found { + delegatorReward.Provider = delegation.Provider + delegatorReward.Delegator = delegation.Delegator + delegatorReward.ChainId = delegation.ChainID + delegatorReward.Amount = sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), amount) + } else { + delegatorReward.Amount = delegatorReward.Amount.AddAmount(amount) + } + k.SetDelegatorReward(ctx, delegatorReward) +} + func (k Keeper) PayContributors(ctx sdk.Context, senderModule string, contributorAddresses []sdk.AccAddress, contributorReward math.Int, specId string) error { if len(contributorAddresses) == 0 { // do not return this error since we don;t want to bail diff --git a/x/pairing/keeper/grpc_query_effective_policy.go b/x/pairing/keeper/grpc_query_effective_policy.go index ef172a9a90..c7228595e9 100644 --- a/x/pairing/keeper/grpc_query_effective_policy.go +++ b/x/pairing/keeper/grpc_query_effective_policy.go @@ -22,7 +22,7 @@ func (k Keeper) EffectivePolicy(goCtx context.Context, req *types.QueryEffective if err != nil { return nil, err } - strictestPolicy, _, err := k.GetProjectStrictestPolicy(ctx, project, req.SpecID) + strictestPolicy, _, err := k.GetProjectStrictestPolicy(ctx, project, req.SpecID, uint64(ctx.BlockHeight())) if err != nil { return nil, err } @@ -41,7 +41,7 @@ func (k Keeper) EffectivePolicy(goCtx context.Context, req *types.QueryEffective if pendingProject.Equal(project) { return &types.QueryEffectivePolicyResponse{Policy: strictestPolicy}, err } else { - pendingPolicy, _, err := k.GetProjectStrictestPolicy(ctx, pendingProject, req.SpecID) + pendingPolicy, _, err := k.GetProjectStrictestPolicy(ctx, pendingProject, req.SpecID, uint64(ctx.BlockHeight())) return &types.QueryEffectivePolicyResponse{Policy: strictestPolicy, PendingPolicy: pendingPolicy}, err } } diff --git a/x/pairing/keeper/pairing.go b/x/pairing/keeper/pairing.go index d890fb465d..2fb60eb846 100644 --- a/x/pairing/keeper/pairing.go +++ b/x/pairing/keeper/pairing.go @@ -129,7 +129,7 @@ func (k Keeper) getPairingForClient(ctx sdk.Context, chainID string, clientAddre return nil, 0, "", err } - strictestPolicy, cluster, err := k.GetProjectStrictestPolicy(ctx, project, chainID) + strictestPolicy, cluster, err := k.GetProjectStrictestPolicy(ctx, project, chainID, block) if err != nil { return nil, 0, "", fmt.Errorf("invalid user for pairing: %s", err.Error()) } @@ -174,8 +174,8 @@ func (k Keeper) getPairingForClient(ctx sdk.Context, chainID string, clientAddre return providers, strictestPolicy.EpochCuLimit, project.Index, err } -func (k Keeper) GetProjectStrictestPolicy(ctx sdk.Context, project projectstypes.Project, chainID string) (*planstypes.Policy, string, error) { - plan, err := k.subscriptionKeeper.GetPlanFromSubscription(ctx, project.GetSubscription(), uint64(ctx.BlockHeight())) +func (k Keeper) GetProjectStrictestPolicy(ctx sdk.Context, project projectstypes.Project, chainID string, block uint64) (*planstypes.Policy, string, error) { + plan, err := k.subscriptionKeeper.GetPlanFromSubscription(ctx, project.GetSubscription(), block) if err != nil { return nil, "", err } diff --git a/x/pairing/keeper/pairing_test.go b/x/pairing/keeper/pairing_test.go index 579902670b..34a7e9aada 100644 --- a/x/pairing/keeper/pairing_test.go +++ b/x/pairing/keeper/pairing_test.go @@ -552,7 +552,7 @@ func TestAddonPairing(t *testing.T) { project, err := ts.GetProjectForBlock(projectID, ts.BlockHeight()) require.NoError(t, err) - strictestPolicy, _, err := ts.Keepers.Pairing.GetProjectStrictestPolicy(ts.Ctx, project, specId) + strictestPolicy, _, err := ts.Keepers.Pairing.GetProjectStrictestPolicy(ts.Ctx, project, specId, ts.BlockHeight()) require.NoError(t, err) if len(tt.expectedStrictestPolicies) > 0 { require.NotEqual(t, 0, len(strictestPolicy.ChainPolicies)) @@ -1962,7 +1962,7 @@ func TestExtensionAndAddonPairing(t *testing.T) { project, err := ts.GetProjectForBlock(projectID, ts.BlockHeight()) require.NoError(t, err) - strictestPolicy, _, err := ts.Keepers.Pairing.GetProjectStrictestPolicy(ts.Ctx, project, specId) + strictestPolicy, _, err := ts.Keepers.Pairing.GetProjectStrictestPolicy(ts.Ctx, project, specId, ts.BlockHeight()) require.NoError(t, err) if len(tt.expectedStrictestPolicies) > 0 { require.NotEqual(t, 0, len(strictestPolicy.ChainPolicies)) @@ -2113,7 +2113,7 @@ func TestMixSelectedProvidersAndArchivePairing(t *testing.T) { project, err := ts.GetProjectForBlock(projectID, ts.BlockHeight()) require.NoError(t, err) - strictestPolicy, _, err := ts.Keepers.Pairing.GetProjectStrictestPolicy(ts.Ctx, project, specId) + strictestPolicy, _, err := ts.Keepers.Pairing.GetProjectStrictestPolicy(ts.Ctx, project, specId, ts.BlockHeight()) require.NoError(t, err) require.NotEqual(t, 0, len(strictestPolicy.ChainPolicies)) diff --git a/x/pairing/keeper/query_sdk_pairing.go b/x/pairing/keeper/query_sdk_pairing.go index 48695eed22..83df033676 100644 --- a/x/pairing/keeper/query_sdk_pairing.go +++ b/x/pairing/keeper/query_sdk_pairing.go @@ -32,7 +32,7 @@ func (k Keeper) SdkPairing(goCtx context.Context, req *types.QueryGetPairingRequ return nil, err } - strictestPolicy, _, err := k.GetProjectStrictestPolicy(ctx, project, req.ChainID) + strictestPolicy, _, err := k.GetProjectStrictestPolicy(ctx, project, req.ChainID, uint64(ctx.BlockHeight())) if err != nil { return nil, err } From 97a815e4ba13e08bd72245ffeeb746134525ac62 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Thu, 7 Dec 2023 08:58:26 +0000 Subject: [PATCH 42/85] fix test --- x/pairing/keeper/helpers_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/x/pairing/keeper/helpers_test.go b/x/pairing/keeper/helpers_test.go index 08d15d444e..8f6428a6b4 100644 --- a/x/pairing/keeper/helpers_test.go +++ b/x/pairing/keeper/helpers_test.go @@ -134,8 +134,6 @@ func (ts *tester) payAndVerifyBalance( validPayment bool, providerRewardPerc uint64, ) { - // get consumer's project and subscription before payment - balance := ts.GetBalance(providerAddr) proj, err := ts.QueryProjectDeveloper(clientAddr.String()) if !validConsumer { @@ -213,9 +211,11 @@ func (ts *tester) payAndVerifyBalance( if totalCuUsed != 0 { want = planPrice.MulRaw(int64(providerReward)).QuoRaw(int64(totalCuUsed)) } - expectedReward := balance + want.Int64() - actualReward := ts.GetBalance(providerAddr) - require.Equal(ts.T, expectedReward, actualReward) + want.Int64() + + reward, err := ts.QueryDualstakingDelegatorRewards(providerAddr.String(), providerAddr.String(), relayPayment.Relays[0].SpecId) + require.Nil(ts.T, err) + require.Equal(ts.T, want, reward.Rewards[0].Amount.Amount) } // verifyRelayPayments verifies relay payments saved on-chain after getting payment From a54bf109a31b52d8f7870114ebe096b062d6c56d Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Thu, 7 Dec 2023 09:06:14 +0000 Subject: [PATCH 43/85] lint --- x/pairing/keeper/helpers_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/x/pairing/keeper/helpers_test.go b/x/pairing/keeper/helpers_test.go index 8f6428a6b4..1e4dbabcc0 100644 --- a/x/pairing/keeper/helpers_test.go +++ b/x/pairing/keeper/helpers_test.go @@ -134,7 +134,6 @@ func (ts *tester) payAndVerifyBalance( validPayment bool, providerRewardPerc uint64, ) { - proj, err := ts.QueryProjectDeveloper(clientAddr.String()) if !validConsumer { require.NotNil(ts.T, err) From 401cbbdb147c28e3af2e25e44fd8ec708cce9cfa Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Thu, 7 Dec 2023 09:52:46 +0000 Subject: [PATCH 44/85] fix some tests --- x/pairing/keeper/cu_tracker_test.go | 39 ++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/x/pairing/keeper/cu_tracker_test.go b/x/pairing/keeper/cu_tracker_test.go index fa369c31ad..26e81de175 100644 --- a/x/pairing/keeper/cu_tracker_test.go +++ b/x/pairing/keeper/cu_tracker_test.go @@ -249,18 +249,21 @@ func TestTrackedCuWithQos(t *testing.T) { } ts.relayPaymentWithoutPay(relayPaymentMessage2, true) - balance1 := ts.GetBalance(provider1Acc.Addr) - balance2 := ts.GetBalance(provider2Acc.Addr) - // advance month + blocksToSave + 1 to trigger the provider monthly payment ts.AdvanceMonths(1) ts.AdvanceBlocks(ts.BlocksToSave() + 1) - newBalance1 := ts.GetBalance(provider1Acc.Addr) - newBalance2 := ts.GetBalance(provider2Acc.Addr) - - require.Equal(t, balance1+tt.p1ExpectedReward, newBalance1) - require.Equal(t, balance2+tt.p2ExpectedReward, newBalance2) + reward, err := ts.QueryDualstakingDelegatorRewards(provider1Acc.Addr.String(), provider1Acc.Addr.String(), ts.spec.Index) + require.Nil(ts.T, err) + require.Equal(ts.T, tt.p1ExpectedReward, reward.Rewards[0].Amount.Amount.Int64()) + _, err = ts.TxDualstakingClaimRewards(provider1Acc.Addr.String(), provider1Acc.Addr.String()) + require.Nil(ts.T, err) + + reward, err = ts.QueryDualstakingDelegatorRewards(provider2Acc.Addr.String(), provider2Acc.Addr.String(), ts.spec.Index) + require.Nil(ts.T, err) + require.Equal(ts.T, tt.p2ExpectedReward, reward.Rewards[0].Amount.Amount.Int64()) + _, err = ts.TxDualstakingClaimRewards(provider2Acc.Addr.String(), provider2Acc.Addr.String()) + require.Nil(ts.T, err) }) } } @@ -350,6 +353,12 @@ func TestTrackedCuPlanPriceChange(t *testing.T) { ts.AdvanceMonths(1) ts.AdvanceBlocks(ts.BlocksToSave() + 1) + reward, err := ts.QueryDualstakingDelegatorRewards(providerAcc.Addr.String(), providerAcc.Addr.String(), ts.spec.Index) + require.Nil(ts.T, err) + require.Equal(ts.T, originalPlanPrice, reward.Rewards[0].Amount.Amount.Int64()) + _, err = ts.TxDualstakingClaimRewards(providerAcc.Addr.String(), providerAcc.Addr.String()) + require.Nil(ts.T, err) + balance := ts.GetBalance(providerAcc.Addr) require.Equal(t, balanceBeforePay+originalPlanPrice, balance) } @@ -454,6 +463,9 @@ func TestProviderMonthlyPayoutQuery(t *testing.T) { ts.AdvanceMonths(1) ts.AdvanceBlocks(ts.BlocksToSave() + 1) + _, err = ts.TxDualstakingClaimRewards(providerAcct.Addr.String(), providerAcct.Addr.String()) + require.Nil(ts.T, err) + balance := ts.GetBalance(providerAcct.Addr) require.Equal(t, expectedTotalPayout, uint64(balance-oldBalance)) @@ -576,6 +588,9 @@ func TestProviderMonthlyPayoutQueryWithContributor(t *testing.T) { ts.AdvanceMonths(1) ts.AdvanceBlocks(ts.BlocksToSave() + 1) + _, err = ts.TxDualstakingClaimRewards(providerAcct.Addr.String(), providerAcct.Addr.String()) + require.Nil(ts.T, err) + balance := ts.GetBalance(providerAcct.Addr) require.Equal(t, expectedTotalPayout, uint64(balance-oldBalance)) @@ -613,8 +628,14 @@ func TestFrozenProviderGetReward(t *testing.T) { ts.AdvanceMonths(1) ts.AdvanceBlocks(ts.BlocksToSave() + 1) - balance := ts.GetBalance(providerAcc.Addr) planPrice := ts.plan.Price.Amount.Int64() + reward, err := ts.QueryDualstakingDelegatorRewards(providerAcc.Addr.String(), providerAcc.Addr.String(), ts.spec.Index) + require.Nil(ts.T, err) + require.Equal(ts.T, planPrice, reward.Rewards[0].Amount.Amount.Int64()) + _, err = ts.TxDualstakingClaimRewards(providerAcc.Addr.String(), providerAcc.Addr.String()) + require.Nil(ts.T, err) + + balance := ts.GetBalance(providerAcc.Addr) require.Equal(t, balanceBeforePay+planPrice, balance) } From cd4d822e5c15883eb213842b299d35f8150b7bd2 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Thu, 7 Dec 2023 09:54:51 +0000 Subject: [PATCH 45/85] now even more pass --- x/pairing/keeper/helpers_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x/pairing/keeper/helpers_test.go b/x/pairing/keeper/helpers_test.go index 1e4dbabcc0..7eb17b6b02 100644 --- a/x/pairing/keeper/helpers_test.go +++ b/x/pairing/keeper/helpers_test.go @@ -215,6 +215,8 @@ func (ts *tester) payAndVerifyBalance( reward, err := ts.QueryDualstakingDelegatorRewards(providerAddr.String(), providerAddr.String(), relayPayment.Relays[0].SpecId) require.Nil(ts.T, err) require.Equal(ts.T, want, reward.Rewards[0].Amount.Amount) + _, err = ts.TxDualstakingClaimRewards(providerAddr.String(), providerAddr.String()) + require.Nil(ts.T, err) } // verifyRelayPayments verifies relay payments saved on-chain after getting payment From 35fcb9714d199bfbcd753dacf87bc08477be821b Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Thu, 7 Dec 2023 10:24:50 +0000 Subject: [PATCH 46/85] even better --- x/pairing/keeper/helpers_test.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/x/pairing/keeper/helpers_test.go b/x/pairing/keeper/helpers_test.go index 7eb17b6b02..08b578534f 100644 --- a/x/pairing/keeper/helpers_test.go +++ b/x/pairing/keeper/helpers_test.go @@ -210,11 +210,13 @@ func (ts *tester) payAndVerifyBalance( if totalCuUsed != 0 { want = planPrice.MulRaw(int64(providerReward)).QuoRaw(int64(totalCuUsed)) } - want.Int64() - reward, err := ts.QueryDualstakingDelegatorRewards(providerAddr.String(), providerAddr.String(), relayPayment.Relays[0].SpecId) + reward, err := ts.QueryDualstakingDelegatorRewards(providerAddr.String(), providerAddr.String(), "") require.Nil(ts.T, err) - require.Equal(ts.T, want, reward.Rewards[0].Amount.Amount) + for _, reward := range reward.Rewards { + want = want.Sub(reward.Amount.Amount) + } + require.True(ts.T, want.IsZero()) _, err = ts.TxDualstakingClaimRewards(providerAddr.String(), providerAddr.String()) require.Nil(ts.T, err) } From 7cc405751fbfb97c0b3c0ae462b37331e4c7dd54 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Thu, 7 Dec 2023 10:33:07 +0000 Subject: [PATCH 47/85] another test fix --- x/pairing/keeper/msg_server_relay_payment_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/x/pairing/keeper/msg_server_relay_payment_test.go b/x/pairing/keeper/msg_server_relay_payment_test.go index 0c72011e3e..98fb06cac4 100644 --- a/x/pairing/keeper/msg_server_relay_payment_test.go +++ b/x/pairing/keeper/msg_server_relay_payment_test.go @@ -217,8 +217,12 @@ func TestRelayPaymentUnstakingProviderForUnresponsivenessWithBadDataInput(t *tes require.Nil(t, err) ts.AdvanceMonths(1) ts.AdvanceBlocks(ts.BlocksToSave() + 1) - balanceProviderAfterPayment := ts.GetBalance(provider1Acct.Addr) + // reward + before == after + _, err = ts.TxDualstakingClaimRewards(provider1Acct.Addr.String(), provider1Acct.Addr.String()) + require.Nil(ts.T, err) + + balanceProviderAfterPayment := ts.GetBalance(provider1Acct.Addr) require.Equal(t, balanceProviderAfterPayment, int64(reward)+balanceProviderBeforePayment) } From 23d18303ce9126ba058c600ee8ce3539e34102ef Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Thu, 7 Dec 2023 10:40:15 +0000 Subject: [PATCH 48/85] another test fix --- x/pairing/keeper/msg_server_relay_payment_gov_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/x/pairing/keeper/msg_server_relay_payment_gov_test.go b/x/pairing/keeper/msg_server_relay_payment_gov_test.go index 21f3688783..7e8a2b21a4 100644 --- a/x/pairing/keeper/msg_server_relay_payment_gov_test.go +++ b/x/pairing/keeper/msg_server_relay_payment_gov_test.go @@ -103,6 +103,9 @@ func TestRelayPaymentGovQosWeightChange(t *testing.T) { ts.AdvanceMonths(1) ts.AdvanceBlocks(ts.BlocksToSave() + 1) + _, err = ts.TxDualstakingClaimRewards(providerAcct.Addr.String(), providerAcct.Addr.String()) + require.Nil(t, err) + newBalance := ts.GetBalance(providerAcct.Addr) // check that the provider's balance is increased by planPrice * 60 / 160 (both relay with QosWeight=0.7) From e42276ef615ff15b0075f198818ea9b047ef21df Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Thu, 7 Dec 2023 11:45:02 +0000 Subject: [PATCH 49/85] now e2e uses rewards --- testutil/e2e/paymentE2E.go | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/testutil/e2e/paymentE2E.go b/testutil/e2e/paymentE2E.go index 14b36581b5..2a8bdd1860 100644 --- a/testutil/e2e/paymentE2E.go +++ b/testutil/e2e/paymentE2E.go @@ -11,10 +11,10 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" - bankTypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/lavanet/lava/cmd/lavad/cmd" commonconsts "github.com/lavanet/lava/testutil/common/consts" "github.com/lavanet/lava/utils" + dualstakingTypes "github.com/lavanet/lava/x/dualstaking/types" epochStorageTypes "github.com/lavanet/lava/x/epochstorage/types" pairingTypes "github.com/lavanet/lava/x/pairing/types" subscriptionTypes "github.com/lavanet/lava/x/subscription/types" @@ -98,27 +98,30 @@ func (lt *lavaTest) getProvidersAddresses() ([]string, error) { return addresses, nil } -// getBalances gets the current balances of the input addresses -func (lt *lavaTest) getBalances(addresses []string) ([]sdk.Coin, error) { - bankQueryClient := bankTypes.NewQueryClient(lt.grpcConn) +// getRewards gets the current balances of the input addresses +func (lt *lavaTest) getRewards(addresses []string) ([]sdk.Coin, error) { + dualstakingQueryClient := dualstakingTypes.NewQueryClient(lt.grpcConn) - var balances []sdk.Coin + var rewards []sdk.Coin for _, addr := range addresses { sdkAddr, err := sdk.AccAddressFromBech32(addr) if err != nil { return nil, fmt.Errorf("could not get balance of address %s. err: %s", addr, err.Error()) } - balanceRequest := bankTypes.NewQueryBalanceRequest(sdkAddr, lt.tokenDenom) - res, err := bankQueryClient.Balance(context.Background(), balanceRequest) + rewardsRequest := dualstakingTypes.QueryDelegatorRewardsRequest{Delegator: addr, Provider: addr, ChainId: ""} + res, err := dualstakingQueryClient.DelegatorRewards(context.Background(), &rewardsRequest) if err != nil { - return nil, fmt.Errorf("could not get balance of address %s. err: %s", sdkAddr.String(), err.Error()) + return nil, fmt.Errorf("could not get rewards of address %s. err: %s", sdkAddr.String(), err.Error()) } - - balances = append(balances, *res.Balance) + total := sdk.NewCoin(commonconsts.TestTokenDenom, sdk.ZeroInt()) + for _, r := range res.Rewards { + total.Add(r.Amount) + } + rewards = append(rewards, total) } - return balances, nil + return rewards, nil } // checkPayment checks that at least one providers' balance increased (can't be known @@ -146,7 +149,7 @@ func (lt *lavaTest) checkPayment(providers []string, startBalances []sdk.Coin) { } // get new balance and checks that at least one provider's balance was increased - newBalances, err := lt.getBalances(providers) + newBalances, err := lt.getRewards(providers) if err != nil { panic(err) } @@ -240,7 +243,7 @@ func runPaymentE2E(timeout time.Duration) { if err != nil { panic(err) } - startBalances, err := lt.getBalances(providers) + startBalances, err := lt.getRewards(providers) if err != nil { panic(err) } From 09cec95cd9bae8c1c8212e7d185195afca4a522b Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Thu, 7 Dec 2023 13:16:02 +0000 Subject: [PATCH 50/85] fixa --- testutil/e2e/paymentE2E.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testutil/e2e/paymentE2E.go b/testutil/e2e/paymentE2E.go index 2a8bdd1860..631b197fef 100644 --- a/testutil/e2e/paymentE2E.go +++ b/testutil/e2e/paymentE2E.go @@ -116,7 +116,7 @@ func (lt *lavaTest) getRewards(addresses []string) ([]sdk.Coin, error) { } total := sdk.NewCoin(commonconsts.TestTokenDenom, sdk.ZeroInt()) for _, r := range res.Rewards { - total.Add(r.Amount) + total = total.Add(r.Amount) } rewards = append(rewards, total) } From 93f4e480b59739359b6b3d24e006f908f2c83dad Mon Sep 17 00:00:00 2001 From: Omer <100387053+omerlavanet@users.noreply.github.com> Date: Thu, 7 Dec 2023 17:49:21 +0200 Subject: [PATCH 51/85] PRT-allow-setting-extensions-via-header (#1025) * allow setting extensions with a header * fix a bug --- protocol/chainlib/base_chain_parser.go | 15 ++++++++---- protocol/chainlib/chain_message.go | 24 +++++++++++++++++++ protocol/chainlib/chainlib.go | 3 +++ .../extensionslib/extension_parser.go | 11 +++++++++ protocol/common/endpoints.go | 1 + protocol/rpcconsumer/rpcconsumer_server.go | 13 ++++++++++ 6 files changed, 62 insertions(+), 5 deletions(-) diff --git a/protocol/chainlib/base_chain_parser.go b/protocol/chainlib/base_chain_parser.go index 35c55d999f..d15413c5a4 100644 --- a/protocol/chainlib/base_chain_parser.go +++ b/protocol/chainlib/base_chain_parser.go @@ -125,14 +125,15 @@ func (bcp *BaseChainParser) SeparateAddonsExtensions(supported []string) (addons if supportedToCheck == "" { continue } - if !bcp.isExtension(supportedToCheck) { - // neither is an error - return nil, nil, utils.LavaFormatError("invalid supported to check, is neither an addon or an extension", nil, utils.Attribute{Key: "spec", Value: bcp.spec.Index}, utils.Attribute{Key: "supported", Value: supportedToCheck}) + if bcp.isExtension(supportedToCheck) { + extensions = append(extensions, supportedToCheck) + continue } - extensions = append(extensions, supportedToCheck) + // neither is an error + err = utils.LavaFormatError("invalid supported to check, is neither an addon or an extension", err, utils.Attribute{Key: "spec", Value: bcp.spec.Index}, utils.Attribute{Key: "supported", Value: supportedToCheck}) } } - return addons, extensions, nil + return addons, extensions, err } // gets all verifications for an endpoint supporting multiple addons and extensions @@ -349,6 +350,10 @@ func getServiceApis(spec spectypes.Spec, rpcInterface string) (retServerApis map return serverApis, taggedApis, apiCollections, headers, verifications } +func (bcp *BaseChainParser) ExtensionsParser() *extensionslib.ExtensionParser { + return &bcp.extensionParser +} + // matchSpecApiByName returns service api which match given name func matchSpecApiByName(name, connectionType string, serverApis map[ApiKey]ApiContainer) (*ApiContainer, bool) { // TODO: make it faster and better by not doing a regex instead using a better algorithm diff --git a/protocol/chainlib/chain_message.go b/protocol/chainlib/chain_message.go index d9ac745f86..f6b73ef73c 100644 --- a/protocol/chainlib/chain_message.go +++ b/protocol/chainlib/chain_message.go @@ -5,6 +5,7 @@ import ( "time" "github.com/lavanet/lava/protocol/chainlib/chainproxy/rpcInterfaceMessages" + "github.com/lavanet/lava/protocol/chainlib/extensionslib" pairingtypes "github.com/lavanet/lava/x/pairing/types" spectypes "github.com/lavanet/lava/x/spec/types" ) @@ -77,6 +78,29 @@ func (pm *baseChainMessageContainer) GetExtensions() []*spectypes.Extension { return pm.extensions } +// adds the following extensions +func (pm *baseChainMessageContainer) OverrideExtensions(extensionNames []string, extensionParser *extensionslib.ExtensionParser) { + existingExtensions := map[string]struct{}{} + for _, extension := range pm.extensions { + existingExtensions[extension.Name] = struct{}{} + } + for _, extensionName := range extensionNames { + if _, ok := existingExtensions[extensionName]; !ok { + existingExtensions[extensionName] = struct{}{} + extensionKey := extensionslib.ExtensionKey{ + Extension: extensionName, + ConnectionType: pm.apiCollection.CollectionData.Type, + InternalPath: pm.apiCollection.CollectionData.InternalPath, + Addon: pm.apiCollection.CollectionData.AddOn, + } + extension := extensionParser.GetExtension(extensionKey) + if extension != nil { + pm.extensions = append(pm.extensions, extension) + } + } + } +} + func (pm *baseChainMessageContainer) SetExtension(extension *spectypes.Extension) { if len(pm.extensions) > 0 { for _, ext := range pm.extensions { diff --git a/protocol/chainlib/chainlib.go b/protocol/chainlib/chainlib.go index 19ca1464cd..f46cd0d721 100644 --- a/protocol/chainlib/chainlib.go +++ b/protocol/chainlib/chainlib.go @@ -7,6 +7,7 @@ import ( "github.com/lavanet/lava/protocol/chainlib/chainproxy/rpcInterfaceMessages" "github.com/lavanet/lava/protocol/chainlib/chainproxy/rpcclient" + "github.com/lavanet/lava/protocol/chainlib/extensionslib" "github.com/lavanet/lava/protocol/common" "github.com/lavanet/lava/protocol/lavasession" "github.com/lavanet/lava/protocol/metrics" @@ -63,6 +64,7 @@ type ChainParser interface { Activate() UpdateBlockTime(newBlockTime time.Duration) GetUniqueName() string + ExtensionsParser() *extensionslib.ExtensionParser } type ChainMessage interface { @@ -70,6 +72,7 @@ type ChainMessage interface { UpdateLatestBlockInMessage(latestBlock int64, modifyContent bool) (modified bool) AppendHeader(metadata []pairingtypes.Metadata) GetExtensions() []*spectypes.Extension + OverrideExtensions(extensionNames []string, extensionParser *extensionslib.ExtensionParser) DisableErrorHandling() TimeoutOverride(...time.Duration) time.Duration ChainMessageForSend diff --git a/protocol/chainlib/extensionslib/extension_parser.go b/protocol/chainlib/extensionslib/extension_parser.go index 3c745da739..71024252ce 100644 --- a/protocol/chainlib/extensionslib/extension_parser.go +++ b/protocol/chainlib/extensionslib/extension_parser.go @@ -25,6 +25,17 @@ type ExtensionParser struct { configuredExtensions map[ExtensionKey]*spectypes.Extension } +func (ep *ExtensionParser) GetExtension(extension ExtensionKey) *spectypes.Extension { + if extension.Extension == "" { + return nil + } + extensionRet, ok := ep.configuredExtensions[extension] + if ok { + return extensionRet + } + return nil +} + func (ep *ExtensionParser) AllowedExtension(extension string) bool { if extension == "" { return true diff --git a/protocol/common/endpoints.go b/protocol/common/endpoints.go index 91887d7154..6d011dae0c 100644 --- a/protocol/common/endpoints.go +++ b/protocol/common/endpoints.go @@ -23,6 +23,7 @@ const ( // these headers need to be lowercase BLOCK_PROVIDERS_ADDRESSES_HEADER_NAME = "lava-providers-block" RELAY_TIMEOUT_HEADER_NAME = "lava-relay-timeout" + EXTENSION_OVERRIDE_HEADER_NAME = "lava-extension" ) type NodeUrl struct { diff --git a/protocol/rpcconsumer/rpcconsumer_server.go b/protocol/rpcconsumer/rpcconsumer_server.go index 8e124cd5df..dc155f398e 100644 --- a/protocol/rpcconsumer/rpcconsumer_server.go +++ b/protocol/rpcconsumer/rpcconsumer_server.go @@ -722,6 +722,8 @@ func (rpccs *RPCConsumerServer) LavaDirectiveHeaders(metadata []pairingtypes.Met headerDirectives[name] = metaElement.Value case common.RELAY_TIMEOUT_HEADER_NAME: headerDirectives[name] = metaElement.Value + case common.EXTENSION_OVERRIDE_HEADER_NAME: + headerDirectives[name] = metaElement.Value default: metadataRet = append(metadataRet, metaElement) } @@ -750,4 +752,15 @@ func (rpccs *RPCConsumerServer) HandleDirectiveHeadersForMessage(chainMessage ch chainMessage.TimeoutOverride(timeout) } } + extensionsStr, ok := directiveHeaders[common.EXTENSION_OVERRIDE_HEADER_NAME] + if ok { + extensions := strings.Split(extensionsStr, ",") + _, extensions, _ = rpccs.chainParser.SeparateAddonsExtensions(extensions) + if len(extensions) == 1 && extensions[0] == "none" { + // none eliminates existing extensions + chainMessage.OverrideExtensions([]string{}, rpccs.chainParser.ExtensionsParser()) + } else if len(extensions) > 0 { + chainMessage.OverrideExtensions(extensions, rpccs.chainParser.ExtensionsParser()) + } + } } From 38055a5e5b1642d5c347440b5a9ee51d000b0472 Mon Sep 17 00:00:00 2001 From: Omer <100387053+omerlavanet@users.noreply.github.com> Date: Thu, 7 Dec 2023 17:58:43 +0200 Subject: [PATCH 52/85] PRT-verify-provider-finalization-data-consistency (#1028) * added a consistency verification for the provider response * added guid header to requests --- protocol/chainlib/grpc.go | 6 ---- protocol/chainlib/jsonRPC.go | 11 +++--- protocol/chainlib/rest.go | 6 ---- protocol/chainlib/tendermintRPC.go | 19 ++++------ protocol/common/endpoints.go | 2 ++ protocol/lavaprotocol/response_builder.go | 7 ++++ protocol/rpcconsumer/rpcconsumer_server.go | 41 ++++++++++++++++++++-- x/protocol/types/params.go | 4 +-- 8 files changed, 61 insertions(+), 35 deletions(-) diff --git a/protocol/chainlib/grpc.go b/protocol/chainlib/grpc.go index e8974addb0..cfbdcbf1a9 100644 --- a/protocol/chainlib/grpc.go +++ b/protocol/chainlib/grpc.go @@ -311,12 +311,6 @@ func (apil *GrpcChainListener) Serve(ctx context.Context) { nodeError := &GrpcNodeErrorResponse{} unMarshalingError := json.Unmarshal(relayReply.Data, nodeError) metadataToReply := relayReply.Metadata - if relayResult.GetProvider() != "" { - metadataToReply = append(metadataToReply, pairingtypes.Metadata{ - Name: common.PROVIDER_ADDRESS_HEADER_NAME, - Value: relayResult.GetProvider(), - }) - } if unMarshalingError == nil { return nil, convertRelayMetaDataToMDMetaData(metadataToReply), status.Error(codes.Code(nodeError.ErrorCode), nodeError.ErrorMessage) } diff --git a/protocol/chainlib/jsonRPC.go b/protocol/chainlib/jsonRPC.go index f752f580f0..22d9291457 100644 --- a/protocol/chainlib/jsonRPC.go +++ b/protocol/chainlib/jsonRPC.go @@ -412,9 +412,6 @@ func (apil *JsonRPCChainListener) Serve(ctx context.Context) { headers := convertToMetadataMap(metadataValues) relayResult, err := apil.relaySender.SendRelay(ctx, "", string(fiberCtx.Body()), http.MethodPost, dappID, consumerIp, metricsData, headers) reply := relayResult.GetReply() - if relayResult.GetProvider() != "" { - fiberCtx.Set(common.PROVIDER_ADDRESS_HEADER_NAME, relayResult.GetProvider()) - } go apil.logger.AddMetricForHttp(metricsData, err, fiberCtx.GetReqHeaders()) if err != nil { // Get unique GUID response @@ -432,17 +429,17 @@ func (apil *JsonRPCChainListener) Serve(ctx context.Context) { // Construct json response response := convertToJsonError(errMasking) - // Return error json response - return fiberCtx.SendString(response) + return addHeadersAndSendString(fiberCtx, reply.GetMetadata(), response) } + response := string(reply.Data) // Log request and response apil.logger.LogRequestAndResponse("jsonrpc http", false, "POST", fiberCtx.Request().URI().String(), string(fiberCtx.Body()), - string(reply.Data), + response, msgSeed, time.Since(startTime), nil, @@ -451,7 +448,7 @@ func (apil *JsonRPCChainListener) Serve(ctx context.Context) { fiberCtx.Status(relayResult.StatusCode) } // Return json response - return fiberCtx.SendString(string(reply.Data)) + return addHeadersAndSendString(fiberCtx, reply.GetMetadata(), response) }) // Go diff --git a/protocol/chainlib/rest.go b/protocol/chainlib/rest.go index 813219568c..d880e1e31f 100644 --- a/protocol/chainlib/rest.go +++ b/protocol/chainlib/rest.go @@ -291,9 +291,6 @@ func (apil *RestChainListener) Serve(ctx context.Context) { relayResult, err := apil.relaySender.SendRelay(ctx, path+query, requestBody, http.MethodPost, dappID, fiberCtx.Get(common.IP_FORWARDING_HEADER_NAME, fiberCtx.IP()), analytics, restHeaders) reply := relayResult.GetReply() go apil.logger.AddMetricForHttp(analytics, err, fiberCtx.GetReqHeaders()) - if relayResult.GetProvider() != "" { - fiberCtx.Set(common.PROVIDER_ADDRESS_HEADER_NAME, relayResult.GetProvider()) - } if err != nil { // Get unique GUID response errMasking := apil.logger.GetUniqueGuidResponseForError(err, msgSeed) @@ -350,9 +347,6 @@ func (apil *RestChainListener) Serve(ctx context.Context) { relayResult, err := apil.relaySender.SendRelay(ctx, path+query, "", fiberCtx.Method(), dappID, fiberCtx.Get(common.IP_FORWARDING_HEADER_NAME, fiberCtx.IP()), analytics, restHeaders) reply := relayResult.GetReply() go apil.logger.AddMetricForHttp(analytics, err, fiberCtx.GetReqHeaders()) - if relayResult.GetProvider() != "" { - fiberCtx.Set(common.PROVIDER_ADDRESS_HEADER_NAME, relayResult.GetProvider()) - } if err != nil { // Get unique GUID response errMasking := apil.logger.GetUniqueGuidResponseForError(err, msgSeed) diff --git a/protocol/chainlib/tendermintRPC.go b/protocol/chainlib/tendermintRPC.go index 017a791379..5c603c9914 100644 --- a/protocol/chainlib/tendermintRPC.go +++ b/protocol/chainlib/tendermintRPC.go @@ -434,9 +434,6 @@ func (apil *TendermintRpcChainListener) Serve(ctx context.Context) { headers := convertToMetadataMap(metadataValues) relayResult, err := apil.relaySender.SendRelay(ctx, "", string(fiberCtx.Body()), "", dappID, fiberCtx.Get(common.IP_FORWARDING_HEADER_NAME, fiberCtx.IP()), metricsData, headers) reply := relayResult.GetReply() - if relayResult.GetProvider() != "" { - fiberCtx.Set(common.PROVIDER_ADDRESS_HEADER_NAME, relayResult.GetProvider()) - } go apil.logger.AddMetricForHttp(metricsData, err, fiberCtx.GetReqHeaders()) if err != nil { @@ -455,17 +452,17 @@ func (apil *TendermintRpcChainListener) Serve(ctx context.Context) { // Construct json response response := rpcInterfaceMessages.ConvertToTendermintError(errMasking, fiberCtx.Body()) - // Return error json response - return fiberCtx.SendString(response) + return addHeadersAndSendString(fiberCtx, reply.GetMetadata(), response) } // Log request and response apil.logger.LogRequestAndResponse("tendermint http in/out", false, "POST", fiberCtx.Request().URI().String(), string(fiberCtx.Body()), string(reply.Data), msgSeed, time.Since(startTime), nil) if relayResult.GetStatusCode() != 0 { fiberCtx.Status(relayResult.StatusCode) } + response := string(reply.Data) // Return json response - return fiberCtx.SendString(string(reply.Data)) + return addHeadersAndSendString(fiberCtx, reply.GetMetadata(), response) }) app.Get("/*", func(fiberCtx *fiber.Ctx) error { @@ -490,9 +487,6 @@ func (apil *TendermintRpcChainListener) Serve(ctx context.Context) { msgSeed := strconv.FormatUint(guid, 10) reply := relayResult.GetReply() go apil.logger.AddMetricForHttp(metricsData, err, fiberCtx.GetReqHeaders()) - if relayResult.GetProvider() != "" { - fiberCtx.Set(common.PROVIDER_ADDRESS_HEADER_NAME, relayResult.GetProvider()) - } if err != nil { // Get unique GUID response errMasking := apil.logger.GetUniqueGuidResponseForError(err, msgSeed) @@ -515,15 +509,16 @@ func (apil *TendermintRpcChainListener) Serve(ctx context.Context) { response := convertToJsonError(errMasking) // Return error json response - return fiberCtx.SendString(response) + return addHeadersAndSendString(fiberCtx, reply.GetMetadata(), response) } + response := string(reply.Data) // Log request and response - apil.logger.LogRequestAndResponse("tendermint http in/out", false, "GET", fiberCtx.Request().URI().String(), "", string(reply.Data), msgSeed, time.Since(startTime), nil) + apil.logger.LogRequestAndResponse("tendermint http in/out", false, "GET", fiberCtx.Request().URI().String(), "", response, msgSeed, time.Since(startTime), nil) if relayResult.GetStatusCode() != 0 { fiberCtx.Status(relayResult.StatusCode) } // Return json response - return fiberCtx.SendString(string(reply.Data)) + return addHeadersAndSendString(fiberCtx, reply.GetMetadata(), response) }) // // Go diff --git a/protocol/common/endpoints.go b/protocol/common/endpoints.go index 6d011dae0c..eebb971dde 100644 --- a/protocol/common/endpoints.go +++ b/protocol/common/endpoints.go @@ -20,6 +20,8 @@ const ( URL_QUERY_PARAMETERS_SEPARATOR_OTHER_PARAMETERS = "&" IP_FORWARDING_HEADER_NAME = "X-Forwarded-For" PROVIDER_ADDRESS_HEADER_NAME = "Lava-Provider-Address" + RETRY_COUNT_HEADER_NAME = "Lava-Retries" + GUID_HEADER_NAME = "Lava-Guid" // these headers need to be lowercase BLOCK_PROVIDERS_ADDRESSES_HEADER_NAME = "lava-providers-block" RELAY_TIMEOUT_HEADER_NAME = "lava-relay-timeout" diff --git a/protocol/lavaprotocol/response_builder.go b/protocol/lavaprotocol/response_builder.go index 64102cb7a9..e14ff06a94 100644 --- a/protocol/lavaprotocol/response_builder.go +++ b/protocol/lavaprotocol/response_builder.go @@ -9,6 +9,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/utils" "github.com/lavanet/lava/utils/sigs" + "github.com/lavanet/lava/utils/slices" conflicttypes "github.com/lavanet/lava/x/conflict/types" pairingtypes "github.com/lavanet/lava/x/pairing/types" spectypes "github.com/lavanet/lava/x/spec/types" @@ -83,6 +84,12 @@ func VerifyFinalizationData(reply *pairingtypes.RelayReply, relayRequest *pairin if err != nil { return nil, finalizationConflict, err } + providerLatestBlock := reply.LatestBlock + seenBlock := relayRequest.RelayData.SeenBlock + requestBlock := relayRequest.RelayData.RequestBlock + if providerLatestBlock < slices.Min([]int64{seenBlock, requestBlock}) { + return nil, nil, utils.LavaFormatError("provider response does not meet consistency requirements", ProviderFinzalizationDataError, utils.LogAttr("providerLatestBlock", providerLatestBlock), utils.LogAttr("seenBlock", seenBlock), utils.LogAttr("requestBlock", requestBlock), utils.Attribute{Key: "provider address", Value: providerAddr}) + } return finalizedBlocks, finalizationConflict, errRet } diff --git a/protocol/rpcconsumer/rpcconsumer_server.go b/protocol/rpcconsumer/rpcconsumer_server.go index dc155f398e..9c1cdf77c1 100644 --- a/protocol/rpcconsumer/rpcconsumer_server.go +++ b/protocol/rpcconsumer/rpcconsumer_server.go @@ -224,7 +224,7 @@ func (rpccs *RPCConsumerServer) SendRelay( blockOnSyncLoss := map[string]struct{}{} modifiedOnLatestReq := false errorRelayResult := &common.RelayResult{} // returned on error - retries := 0 + retries := uint64(0) timeouts := 0 unwantedProviders := rpccs.GetInitialUnwantedProviders(directiveHeaders) for ; retries < MaxRelayRetries; retries++ { @@ -296,6 +296,7 @@ func (rpccs *RPCConsumerServer) SendRelay( // TODO: secure, go over relay results to find discrepancies and choose majority, or trigger a second wallet relay if len(relayResults) == 0 { + rpccs.appendHeadersToRelayResult(ctx, errorRelayResult, retries) return errorRelayResult, utils.LavaFormatError("Failed all retries", nil, utils.Attribute{Key: "GUID", Value: ctx}, utils.Attribute{Key: "errors", Value: relayErrors}) } else if len(relayErrors) > 0 { utils.LavaFormatDebug("relay succeeded but had some errors", utils.Attribute{Key: "GUID", Value: ctx}, utils.Attribute{Key: "errors", Value: relayErrors}) @@ -314,8 +315,8 @@ func (rpccs *RPCConsumerServer) SendRelay( if retries > 0 { utils.LavaFormatDebug("relay succeeded after retries", utils.Attribute{Key: "GUID", Value: ctx}, utils.Attribute{Key: "retries", Value: retries}) } + rpccs.appendHeadersToRelayResult(ctx, returnedResult, retries) return returnedResult, nil - // return returnedResult.Reply, returnedResult.ReplyServer, nil } func (rpccs *RPCConsumerServer) sendRelayToProvider( @@ -764,3 +765,39 @@ func (rpccs *RPCConsumerServer) HandleDirectiveHeadersForMessage(chainMessage ch } } } + +func (rpccs *RPCConsumerServer) appendHeadersToRelayResult(ctx context.Context, relayResult *common.RelayResult, retries uint64) { + if relayResult == nil { + return + } + metadataReply := []pairingtypes.Metadata{} + // add the provider that responded + if relayResult.GetProvider() != "" { + metadataReply = append(metadataReply, + pairingtypes.Metadata{ + Name: common.PROVIDER_ADDRESS_HEADER_NAME, + Value: relayResult.GetProvider(), + }) + } + // add the relay retried count + if retries > 0 { + metadataReply = append(metadataReply, + pairingtypes.Metadata{ + Name: common.RETRY_COUNT_HEADER_NAME, + Value: strconv.FormatUint(retries, 10), + }) + } + guid, found := utils.GetUniqueIdentifier(ctx) + if found && guid != 0 { + guidStr := strconv.FormatUint(guid, 10) + metadataReply = append(metadataReply, + pairingtypes.Metadata{ + Name: common.GUID_HEADER_NAME, + Value: guidStr, + }) + } + if relayResult.Reply == nil { + relayResult.Reply = &pairingtypes.RelayReply{} + } + relayResult.Reply.Metadata = append(relayResult.Reply.Metadata, metadataReply...) +} diff --git a/x/protocol/types/params.go b/x/protocol/types/params.go index 58f968de99..0c001bf121 100644 --- a/x/protocol/types/params.go +++ b/x/protocol/types/params.go @@ -12,8 +12,8 @@ import ( var _ paramtypes.ParamSet = (*Params)(nil) const ( - TARGET_VERSION = "0.30.3" - MIN_VERSION = "0.27.1" + TARGET_VERSION = "0.30.4" + MIN_VERSION = "0.30.1" ) var ( From f9a0ef2b983f29a21b56927d9a033e6709d9e888 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Sun, 10 Dec 2023 09:05:44 +0000 Subject: [PATCH 53/85] pr changes --- testutil/e2e/paymentE2E.go | 16 ++++++++-------- x/pairing/keeper/cu_tracker_test.go | 9 +++++++++ x/pairing/keeper/helpers_test.go | 4 ++++ 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/testutil/e2e/paymentE2E.go b/testutil/e2e/paymentE2E.go index 631b197fef..a15060c936 100644 --- a/testutil/e2e/paymentE2E.go +++ b/testutil/e2e/paymentE2E.go @@ -127,7 +127,7 @@ func (lt *lavaTest) getRewards(addresses []string) ([]sdk.Coin, error) { // checkPayment checks that at least one providers' balance increased (can't be known // in test time since pairing is pseudo-random) // with the monthly payment mechanism, we just wait and the providers get the rewards automatically -func (lt *lavaTest) checkPayment(providers []string, startBalances []sdk.Coin) { +func (lt *lavaTest) checkPayment(providers []string, startRewards []sdk.Coin) { pairingQueryClient := pairingTypes.NewQueryClient(lt.grpcConn) // wait for month+blocksToSave pass (debug_month = 2min, debug_epochsToSave = 5) and query for expected payout @@ -149,22 +149,22 @@ func (lt *lavaTest) checkPayment(providers []string, startBalances []sdk.Coin) { } // get new balance and checks that at least one provider's balance was increased - newBalances, err := lt.getRewards(providers) + newRewards, err := lt.getRewards(providers) if err != nil { panic(err) } - for i := range newBalances { - newAmount := newBalances[i].Amount - startAmount := startBalances[i].Amount + for i := range newRewards { + newAmount := newRewards[i].Amount + startAmount := startRewards[i].Amount payout := newAmount.Sub(startAmount) if payout.IsNegative() || !withinRange(payout.Uint64(), expectedPayoutArr[i], 80) { panic(utils.LavaFormatError("payment check failed", fmt.Errorf("provider did not get expected payment"), utils.Attribute{Key: "provider", Value: providers[i]}, - utils.Attribute{Key: "start_balance", Value: startBalances[i].String()}, + utils.Attribute{Key: "start_balance", Value: startRewards[i].String()}, utils.Attribute{Key: "expected_payout", Value: expectedPayoutArr[i]}, - utils.Attribute{Key: "start_balance+expected_payout", Value: startBalances[i].AddAmount(sdk.NewIntFromUint64(expectedPayoutArr[i])).String()}, - utils.Attribute{Key: "actual_balance", Value: newBalances[i]}, + utils.Attribute{Key: "start_balance+expected_payout", Value: startRewards[i].AddAmount(sdk.NewIntFromUint64(expectedPayoutArr[i])).String()}, + utils.Attribute{Key: "actual_balance", Value: newRewards[i]}, )) } } diff --git a/x/pairing/keeper/cu_tracker_test.go b/x/pairing/keeper/cu_tracker_test.go index 26e81de175..c6f71a12b9 100644 --- a/x/pairing/keeper/cu_tracker_test.go +++ b/x/pairing/keeper/cu_tracker_test.go @@ -253,6 +253,9 @@ func TestTrackedCuWithQos(t *testing.T) { ts.AdvanceMonths(1) ts.AdvanceBlocks(ts.BlocksToSave() + 1) + balance1 := ts.GetBalance(provider1Acc.Addr) + balance2 := ts.GetBalance(provider2Acc.Addr) + reward, err := ts.QueryDualstakingDelegatorRewards(provider1Acc.Addr.String(), provider1Acc.Addr.String(), ts.spec.Index) require.Nil(ts.T, err) require.Equal(ts.T, tt.p1ExpectedReward, reward.Rewards[0].Amount.Amount.Int64()) @@ -264,6 +267,12 @@ func TestTrackedCuWithQos(t *testing.T) { require.Equal(ts.T, tt.p2ExpectedReward, reward.Rewards[0].Amount.Amount.Int64()) _, err = ts.TxDualstakingClaimRewards(provider2Acc.Addr.String(), provider2Acc.Addr.String()) require.Nil(ts.T, err) + + newBalance1 := ts.GetBalance(provider1Acc.Addr) + newBalance2 := ts.GetBalance(provider2Acc.Addr) + + require.Equal(t, balance1+tt.p1ExpectedReward, newBalance1) + require.Equal(t, balance2+tt.p2ExpectedReward, newBalance2) }) } } diff --git a/x/pairing/keeper/helpers_test.go b/x/pairing/keeper/helpers_test.go index 08b578534f..6c00bb34d0 100644 --- a/x/pairing/keeper/helpers_test.go +++ b/x/pairing/keeper/helpers_test.go @@ -211,6 +211,7 @@ func (ts *tester) payAndVerifyBalance( want = planPrice.MulRaw(int64(providerReward)).QuoRaw(int64(totalCuUsed)) } + balanceWant := ts.GetBalance(providerAddr) + want.Int64() reward, err := ts.QueryDualstakingDelegatorRewards(providerAddr.String(), providerAddr.String(), "") require.Nil(ts.T, err) for _, reward := range reward.Rewards { @@ -219,6 +220,9 @@ func (ts *tester) payAndVerifyBalance( require.True(ts.T, want.IsZero()) _, err = ts.TxDualstakingClaimRewards(providerAddr.String(), providerAddr.String()) require.Nil(ts.T, err) + + balance := ts.GetBalance(providerAddr) + want.Int64() + require.Equal(ts.T, balanceWant, balance) } // verifyRelayPayments verifies relay payments saved on-chain after getting payment From 6d566ff2d0f8415f641340f0f0e675b2a8f74626 Mon Sep 17 00:00:00 2001 From: Ran Mishael <106548467+ranlavanet@users.noreply.github.com> Date: Sun, 10 Dec 2023 11:38:10 +0100 Subject: [PATCH 54/85] adding keyring-os lavavisor bootstrap (#1034) * adding keyring-os lavavisor bootstrap * adjustments for start process * changing scanf usage to use term.readpassword --- ecosystem/lavavisor/README.md | 9 +++ ecosystem/lavavisor/cmd/pod.go | 8 ++- ecosystem/lavavisor/cmd/wrap.go | 30 +++++++++- .../lavavisor/pkg/process/version_monitor.go | 60 +++++++++++++++++-- protocol/common/cobra_common.go | 4 ++ protocol/rpcconsumer/rpcconsumer.go | 11 ++-- protocol/rpcprovider/rpcprovider.go | 9 +-- 7 files changed, 111 insertions(+), 20 deletions(-) diff --git a/ecosystem/lavavisor/README.md b/ecosystem/lavavisor/README.md index 4f1136f552..877f5c2fa4 100644 --- a/ecosystem/lavavisor/README.md +++ b/ecosystem/lavavisor/README.md @@ -58,6 +58,15 @@ lavavisor pod --cmd 'lavap rpcconsumer ./config/consumer_examples/lava_consumer. ### running multiple wrap commands on the same VM if you would like to run multiple wrappers on the same machine, you can set up one --auto-download process while the others are running with --auto-download disabled (default behavior) this will result with one process managing downloading and building while others just wait for the task to be completed. +### Using keyring-backend os +If you are using keyring-backend os you will need to provide the lavavisor (wrap/pod commands only) with a keyring-backend password so it can use it to start the lavap process and read from the keyring os. + +In order to do that add the "--enter-keyring-password" flag to the lavavisor command line. when the lavavisor bootstrap it will request the password from the user with the following prompt: + +``` +INF [Lavavisor] Please enter the keyring password: +``` + ___ 2- **`lavavisor create-service`**: Creates system files according to given consumer / provider config file and configuration flags. diff --git a/ecosystem/lavavisor/cmd/pod.go b/ecosystem/lavavisor/cmd/pod.go index 3cfa1eb664..fd721e182c 100644 --- a/ecosystem/lavavisor/cmd/pod.go +++ b/ecosystem/lavavisor/cmd/pod.go @@ -36,6 +36,7 @@ provider example: flags.AddQueryFlagsToCmd(cmdLavavisorPod) cmdLavavisorPod.Flags().String("directory", os.ExpandEnv("~/"), "Protocol Flags Directory") // cmdLavavisorPod.Flags().Bool("auto-download", false, "Automatically download missing binaries") + cmdLavavisorPod.Flags().Bool(KeyRingPasswordFlag, false, "If you are using keyring OS you will need to enter the keyring password for it.") cmdLavavisorPod.Flags().String(flags.FlagChainID, app.Name, "network chain id") cmdLavavisorPod.Flags().String("cmd", "", "the command to execute") cmdLavavisorPod.MarkFlagRequired("cmd") @@ -43,6 +44,7 @@ provider example: } func LavavisorPod(cmd *cobra.Command) error { + keyRingPassword := getKeyringPassword(cmd) dir, err := cmd.Flags().GetString("directory") if err != nil { return err @@ -65,11 +67,11 @@ func LavavisorPod(cmd *cobra.Command) error { } lavavisor := LavaVisor{} - err = lavavisor.PodStart(ctx, txFactory, clientCtx, runCommand, dir) + err = lavavisor.PodStart(ctx, txFactory, clientCtx, runCommand, dir, keyRingPassword) return err } -func (lv *LavaVisor) PodStart(ctx context.Context, txFactory tx.Factory, clientCtx client.Context, runCommand string, lavavisorDir string) (err error) { +func (lv *LavaVisor) PodStart(ctx context.Context, txFactory tx.Factory, clientCtx client.Context, runCommand string, lavavisorDir string, keyRingPassword *processmanager.KeyRingPassword) (err error) { ctx, cancel := context.WithCancel(ctx) signalChan := make(chan os.Signal, 1) signal.Notify(signalChan, os.Interrupt) @@ -119,7 +121,7 @@ func (lv *LavaVisor) PodStart(ctx context.Context, txFactory tx.Factory, clientC } }() - versionMonitor.StartProcess() + versionMonitor.StartProcess(keyRingPassword) // tear down select { diff --git a/ecosystem/lavavisor/cmd/wrap.go b/ecosystem/lavavisor/cmd/wrap.go index 9fd1a00da0..516801e2e4 100644 --- a/ecosystem/lavavisor/cmd/wrap.go +++ b/ecosystem/lavavisor/cmd/wrap.go @@ -15,8 +15,11 @@ import ( "github.com/lavanet/lava/utils" "github.com/lavanet/lava/utils/rand" "github.com/spf13/cobra" + "golang.org/x/term" ) +const KeyRingPasswordFlag = "enter-keyring-password" + func CreateLavaVisorWrapCobraCommand() *cobra.Command { cmdLavavisorWrap := &cobra.Command{ Use: "wrap", @@ -37,13 +40,34 @@ provider example: flags.AddQueryFlagsToCmd(cmdLavavisorWrap) cmdLavavisorWrap.Flags().String("directory", os.ExpandEnv("~/"), "Protocol Flags Directory") cmdLavavisorWrap.Flags().Bool("auto-download", false, "Automatically download missing binaries") + cmdLavavisorWrap.Flags().Bool(KeyRingPasswordFlag, false, "If you are using keyring OS you will need to enter the keyring password for it.") cmdLavavisorWrap.Flags().String(flags.FlagChainID, app.Name, "network chain id") cmdLavavisorWrap.Flags().String("cmd", "", "the command to execute") cmdLavavisorWrap.MarkFlagRequired("cmd") return cmdLavavisorWrap } +func getKeyringPassword(cmd *cobra.Command) *processmanager.KeyRingPassword { + password, err := cmd.Flags().GetBool(KeyRingPasswordFlag) + if err != nil { + utils.LavaFormatFatal("failed fetching flag", err) + } + var passphrase string + if password { + utils.LavaFormatInfo("[Lavavisor] Please enter the keyring password:") + passwordBytes, err := term.ReadPassword(int(os.Stdin.Fd())) + if err != nil { + utils.LavaFormatFatal("failed reading password from user", err) + } + passphrase = string(passwordBytes) + utils.LavaFormatInfo("[Lavavisor] Password received") + } + return &processmanager.KeyRingPassword{Password: password, Passphrase: passphrase} +} + func LavavisorWrap(cmd *cobra.Command) error { + keyRingPassword := getKeyringPassword(cmd) + dir, err := cmd.Flags().GetString("directory") if err != nil { return err @@ -80,11 +104,11 @@ func LavavisorWrap(cmd *cobra.Command) error { } lavavisor := LavaVisor{} - err = lavavisor.Wrap(ctx, txFactory, clientCtx, lavavisorPath, autoDownload, runCommand) + err = lavavisor.Wrap(ctx, txFactory, clientCtx, lavavisorPath, autoDownload, runCommand, keyRingPassword) return err } -func (lv *LavaVisor) Wrap(ctx context.Context, txFactory tx.Factory, clientCtx client.Context, lavavisorPath string, autoDownload bool, runCommand string) (err error) { +func (lv *LavaVisor) Wrap(ctx context.Context, txFactory tx.Factory, clientCtx client.Context, lavavisorPath string, autoDownload bool, runCommand string, keyringPassword *processmanager.KeyRingPassword) (err error) { ctx, cancel := context.WithCancel(ctx) signalChan := make(chan os.Signal, 1) signal.Notify(signalChan, os.Interrupt) @@ -127,7 +151,7 @@ func (lv *LavaVisor) Wrap(ctx context.Context, txFactory tx.Factory, clientCtx c } }() - versionMonitor.StartProcess() + versionMonitor.StartProcess(keyringPassword) // tear down select { diff --git a/ecosystem/lavavisor/pkg/process/version_monitor.go b/ecosystem/lavavisor/pkg/process/version_monitor.go index 0f160baeea..0fa26ad244 100644 --- a/ecosystem/lavavisor/pkg/process/version_monitor.go +++ b/ecosystem/lavavisor/pkg/process/version_monitor.go @@ -1,6 +1,8 @@ package processmanager import ( + "bufio" + "fmt" "os" "os/exec" "os/signal" @@ -8,7 +10,9 @@ import ( "strings" "sync" "syscall" + "time" + "github.com/lavanet/lava/protocol/common" "github.com/lavanet/lava/protocol/statetracker" "github.com/lavanet/lava/utils" protocoltypes "github.com/lavanet/lava/x/protocol/types" @@ -19,6 +23,11 @@ type ProtocolBinaryFetcherInf interface { FetchProtocolBinary(protocolConsensusVersion *protocoltypes.Version) (selectedBinaryPath string, err error) } +type KeyRingPassword struct { + Password bool // whether the password is required + Passphrase string // the password +} + type VersionMonitor struct { BinaryPath string LavavisorPath string @@ -218,13 +227,13 @@ func (vm *VersionMonitor) ValidateProtocolVersion(incoming *statetracker.Protoco return nil } -func (vm *VersionMonitor) StartProcess() { +func (vm *VersionMonitor) StartProcess(keyringPassword *KeyRingPassword) { // Create a channel to capture OS signals (e.g., Ctrl+C) sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM) // Start subprocess in a Goroutine - go vm.startSubprocess() + go vm.startSubprocess(keyringPassword) // Main loop for monitoring the subprocess for { @@ -232,7 +241,7 @@ func (vm *VersionMonitor) StartProcess() { case <-vm.restart: utils.LavaFormatInfo("[Lavavisor] Received restart signal, restarting subprocess...") vm.StopSubprocess() - go vm.startSubprocess() + go vm.startSubprocess(keyringPassword) case sig := <-sigCh: utils.LavaFormatInfo("[Lavavisor] Received signal:", utils.Attribute{Key: "signal", Value: sig}) vm.StopSubprocess() @@ -250,7 +259,7 @@ func (vm *VersionMonitor) StopSubprocess() { } } -func (vm *VersionMonitor) startSubprocess() { +func (vm *VersionMonitor) startSubprocess(keyringPassword *KeyRingPassword) { // make sure the subprocess wont continue running if we run into a panic. defer func() { if r := recover(); r != nil { @@ -264,12 +273,53 @@ func (vm *VersionMonitor) startSubprocess() { // Set up output redirection so you can see the subprocess's output vm.onGoingCmd.Stdout = os.Stdout - vm.onGoingCmd.Stderr = os.Stderr + // vm.onGoingCmd.Stderr = os.Stderr + + foundPasswordTrigger := make(chan struct{}) + processStart := common.ProcessStartLogText + stderrPipe, err := vm.onGoingCmd.StderrPipe() + if err != nil { + utils.LavaFormatError("[Lavavisor] Error obtaining stderr pipe:", err) + return + } + + // Interaction with the command's Stdin + stdin, err := vm.onGoingCmd.StdinPipe() + if err != nil { + fmt.Println("Error obtaining stdin:", err) + return + } + + go func() { + scanner := bufio.NewScanner(stderrPipe) + for scanner.Scan() { + line := scanner.Text() + fmt.Println(line) + if strings.Contains(line, processStart) { + foundPasswordTrigger <- struct{}{} + } + } + }() if err := vm.onGoingCmd.Start(); err != nil { utils.LavaFormatError("[Lavavisor] Error starting subprocess:", err) } + <-foundPasswordTrigger + // wait to make sure process is waiting for password + time.Sleep(time.Second * 3) + + if keyringPassword != nil && keyringPassword.Password { + // Send input to the command + _, err = stdin.Write([]byte(keyringPassword.Passphrase + "\n")) + if err != nil { + fmt.Println("Error writing to stdin:", err) + return + } + utils.LavaFormatInfo("[Lavavisor] entered keyring-os password.") + } + stdin.Close() // Flush the input stream (this sends the input to the process) + if err := vm.onGoingCmd.Wait(); err != nil { if strings.Contains(err.Error(), "signal: killed") { utils.LavaFormatInfo("[Lavavisor] Subprocess stopped due to sig killed.") diff --git a/protocol/common/cobra_common.go b/protocol/common/cobra_common.go index 28411ce800..8b50592927 100644 --- a/protocol/common/cobra_common.go +++ b/protocol/common/cobra_common.go @@ -15,6 +15,10 @@ const ( RollingLogFormat = "rolling-log-format" ) +const ( + ProcessStartLogText = "Process Started" +) + const ( defaultRollingLogState = "off" // off defaultRollingLogMaxSize = "100" // 100MB diff --git a/protocol/rpcconsumer/rpcconsumer.go b/protocol/rpcconsumer/rpcconsumer.go index 8cc8f515e9..b66fc8802b 100644 --- a/protocol/rpcconsumer/rpcconsumer.go +++ b/protocol/rpcconsumer/rpcconsumer.go @@ -307,6 +307,11 @@ rpcconsumer consumer_examples/full_consumer_example.yml --cache-be "127.0.0.1:77 return nil }, RunE: func(cmd *cobra.Command, args []string) error { + utils.LavaFormatInfo(common.ProcessStartLogText) + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } // set viper config_name := DefaultRPCConsumerFileName if len(args) == 1 { @@ -325,11 +330,7 @@ rpcconsumer consumer_examples/full_consumer_example.yml --cache-be "127.0.0.1:77 closeLoggerOnFinish := common.SetupRollingLogger() defer closeLoggerOnFinish() - utils.LavaFormatInfo("RPCConsumer started", utils.Attribute{Key: "args", Value: strings.Join(args, ",")}) - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } + utils.LavaFormatInfo("RPCConsumer started:", utils.Attribute{Key: "args", Value: strings.Join(args, ",")}) // setting the insecure option on provider dial, this should be used in development only! lavasession.AllowInsecureConnectionToProviders = viper.GetBool(lavasession.AllowInsecureConnectionToProvidersFlag) diff --git a/protocol/rpcprovider/rpcprovider.go b/protocol/rpcprovider/rpcprovider.go index c4893e6eb2..6ae82d3eb3 100644 --- a/protocol/rpcprovider/rpcprovider.go +++ b/protocol/rpcprovider/rpcprovider.go @@ -434,6 +434,11 @@ rpcprovider 127.0.0.1:3333 COS3 tendermintrpc "wss://www.node-path.com:80,https: return nil }, RunE: func(cmd *cobra.Command, args []string) error { + utils.LavaFormatInfo(common.ProcessStartLogText) + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } config_name := DefaultRPCProviderFileName if len(args) == 1 { config_name = args[0] // name of config file (without extension) @@ -451,10 +456,6 @@ rpcprovider 127.0.0.1:3333 COS3 tendermintrpc "wss://www.node-path.com:80,https: defer closeLoggerOnFinish() utils.LavaFormatInfo("RPCProvider started") - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } var rpcProviderEndpoints []*lavasession.RPCProviderEndpoint var endpoints_strings []string var viper_endpoints *viper.Viper From 6fbcc4d8b5c24d7c1017b3e4c2eff2f58a6f14e4 Mon Sep 17 00:00:00 2001 From: Yaroms <103432884+Yaroms@users.noreply.github.com> Date: Sun, 10 Dec 2023 13:44:48 +0200 Subject: [PATCH 55/85] CNS-754-let-modify-plan-speficy-the-block-number-of-the-fixation (#1035) * let modify plan specify the fixation block * fix unitests * fix unitest --------- Co-authored-by: Yarom Swisa --- testutil/common/tester.go | 2 +- x/plans/keeper/plan.go | 38 +++++++++++++++++++++++-------------- x/plans/keeper/plan_test.go | 8 ++++---- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/testutil/common/tester.go b/testutil/common/tester.go index 510895011f..b456898c9d 100644 --- a/testutil/common/tester.go +++ b/testutil/common/tester.go @@ -218,7 +218,7 @@ func (ts *Tester) AddPlan(name string, plan planstypes.Plan) *Tester { } func (ts *Tester) ModifyPlan(name string, plan planstypes.Plan) *Tester { - err := ts.Keepers.Plans.AddPlan(ts.Ctx, plan, true) + err := ts.Keepers.Plans.AddPlan(ts.Ctx, plan, false) if err != nil { panic("tester: falied to add plan: '" + plan.Index + "'") } diff --git a/x/plans/keeper/plan.go b/x/plans/keeper/plan.go index 5fa7641815..39aeeb101e 100644 --- a/x/plans/keeper/plan.go +++ b/x/plans/keeper/plan.go @@ -16,12 +16,9 @@ func (k Keeper) AddPlan(ctx sdk.Context, planToAdd types.Plan, modify bool) erro return err } - // overwrite the planToAdd's block field with the current block height - planToAdd.Block = uint64(ctx.BlockHeight()) - if modify { var planFromStore types.Plan - block, _, _, found := k.plansFS.FindEntryDetailed(ctx, planToAdd.GetIndex(), uint64(ctx.BlockHeight()), &planFromStore) + block, _, _, found := k.plansFS.FindEntryDetailed(ctx, planToAdd.GetIndex(), planToAdd.Block, &planFromStore) if found { if planFromStore.Price.Amount.LT(planToAdd.Price.Amount) { return utils.LavaFormatError("failed modifying plan in planFS", fmt.Errorf("plan price cannot be increased"), @@ -29,17 +26,30 @@ func (k Keeper) AddPlan(ctx sdk.Context, planToAdd types.Plan, modify bool) erro utils.Attribute{Key: "originalPlan", Value: planFromStore}, ) } - - planToAdd.Block = block + if planToAdd.Block != block { + return utils.LavaFormatError("failed modifying plan in planFS", fmt.Errorf("plan to modify does not exist"), + utils.Attribute{Key: "planToAdd", Value: planToAdd}, + utils.Attribute{Key: "originalPlan", Value: planFromStore}, + utils.Attribute{Key: "requestedBlock", Value: planToAdd.Block}, + ) + } + k.plansFS.ModifyEntry(ctx, planToAdd.GetIndex(), planToAdd.Block, &planToAdd) + } else { + return utils.LavaFormatError("failed modifying plan in planFS", fmt.Errorf("plan to modify does not exist"), + utils.Attribute{Key: "planToAdd", Value: planToAdd}, + utils.Attribute{Key: "originalPlan", Value: planFromStore}, + utils.Attribute{Key: "requestedBlock", Value: planToAdd.Block}, + ) + } + } else { + planToAdd.Block = uint64(ctx.BlockHeight()) + // TODO: verify the CU per epoch field + err = k.plansFS.AppendEntry(ctx, planToAdd.GetIndex(), planToAdd.Block, &planToAdd) + if err != nil { + return utils.LavaFormatError("failed adding plan to planFS", err, + utils.Attribute{Key: "planToAdd", Value: planToAdd}, + ) } - } - - // TODO: verify the CU per epoch field - err = k.plansFS.AppendEntry(ctx, planToAdd.GetIndex(), planToAdd.Block, &planToAdd) - if err != nil { - return utils.LavaFormatError("failed adding plan to planFS", err, - utils.Attribute{Key: "planToAdd", Value: planToAdd}, - ) } return nil diff --git a/x/plans/keeper/plan_test.go b/x/plans/keeper/plan_test.go index 14beb9de2e..3c69e7dd2e 100644 --- a/x/plans/keeper/plan_test.go +++ b/x/plans/keeper/plan_test.go @@ -355,8 +355,8 @@ func TestModifyPlan(t *testing.T) { ts.AdvanceEpoch() // modify the plan (block should stay the same, change should happen) - plans[0].AnnualDiscountPercentage = 42 - err = testkeeper.SimulatePlansAddProposal(ts.Ctx, ts.Keepers.Plans, []types.Plan{plans[0]}, true) + originalPlan.AnnualDiscountPercentage = 42 + err = testkeeper.SimulatePlansAddProposal(ts.Ctx, ts.Keepers.Plans, []types.Plan{originalPlan}, true) require.Nil(t, err) indices = ts.Keepers.Plans.GetAllPlanIndices(ts.Ctx) require.Equal(t, 1, len(indices)) @@ -366,7 +366,7 @@ func TestModifyPlan(t *testing.T) { require.Equal(t, uint64(42), modifiedPlan.AnnualDiscountPercentage) // modify the plan by increasing its price. proposal should fail - plans[0].Price = plans[0].Price.AddAmount(math.NewIntFromUint64(1)) - err = testkeeper.SimulatePlansAddProposal(ts.Ctx, ts.Keepers.Plans, []types.Plan{plans[0]}, true) + originalPlan.Price = originalPlan.Price.AddAmount(math.NewIntFromUint64(1)) + err = testkeeper.SimulatePlansAddProposal(ts.Ctx, ts.Keepers.Plans, []types.Plan{originalPlan}, true) require.NotNil(t, err) } From 298ed8789beebdefb4d3ee769cd08f60bd374261 Mon Sep 17 00:00:00 2001 From: Elad Gildnur Date: Sun, 10 Dec 2023 07:15:23 -0500 Subject: [PATCH 56/85] CR Fix: Another lint fix --- ecosystem/lava-sdk/src/util/apiCollection.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ecosystem/lava-sdk/src/util/apiCollection.ts b/ecosystem/lava-sdk/src/util/apiCollection.ts index 12a79da350..047fb7759a 100644 --- a/ecosystem/lava-sdk/src/util/apiCollection.ts +++ b/ecosystem/lava-sdk/src/util/apiCollection.ts @@ -1,6 +1,4 @@ -import { - SpecCategory, -} from "../grpc_web_services/lavanet/lava/spec/api_collection_pb"; +import { SpecCategory } from "../grpc_web_services/lavanet/lava/spec/api_collection_pb"; export function CombineSpecCategories( first: SpecCategory, From c7ae2daaeb4703b0c736bfe95639e28adce7d4f4 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Sun, 10 Dec 2023 12:29:16 +0000 Subject: [PATCH 57/85] added handler --- app/app.go | 1 + app/upgrades/empty_upgrades.go | 6 ++++++ x/protocol/module.go | 7 ++++++- x/protocol/types/params.go | 2 +- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/app/app.go b/app/app.go index 3c9bd06edc..8c53a1881e 100644 --- a/app/app.go +++ b/app/app.go @@ -161,6 +161,7 @@ var Upgrades = []upgrades.Upgrade{ upgrades.Upgrade_0_30_0, upgrades.Upgrade_0_30_1, upgrades.Upgrade_0_30_2, + upgrades.Upgrade_0_31_0, } // this line is used by starport scaffolding # stargate/wasm/app/enabledProposals diff --git a/app/upgrades/empty_upgrades.go b/app/upgrades/empty_upgrades.go index 18899496e5..b2cea62038 100644 --- a/app/upgrades/empty_upgrades.go +++ b/app/upgrades/empty_upgrades.go @@ -158,3 +158,9 @@ var Upgrade_0_30_2 = Upgrade{ CreateUpgradeHandler: defaultUpgradeHandler, StoreUpgrades: store.StoreUpgrades{}, } + +var Upgrade_0_31_0 = Upgrade{ + UpgradeName: "v0.31.0", + CreateUpgradeHandler: defaultUpgradeHandler, + StoreUpgrades: store.StoreUpgrades{}, +} diff --git a/x/protocol/module.go b/x/protocol/module.go index 4f58cc7f79..f0cd7584f2 100644 --- a/x/protocol/module.go +++ b/x/protocol/module.go @@ -187,10 +187,15 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // panic:ok: at start up, migration cannot proceed anyhow panic(fmt.Errorf("%s: failed to register migration to v13: %w", types.ModuleName, err)) } + + if err := cfg.RegisterMigration(types.ModuleName, 13, migrator.MigrateVersion); err != nil { + // panic:ok: at start up, migration cannot proceed anyhow + panic(fmt.Errorf("%s: failed to register migration to v14: %w", types.ModuleName, err)) + } } // ConsensusVersion implements ConsensusVersion. -func (AppModule) ConsensusVersion() uint64 { return 13 } +func (AppModule) ConsensusVersion() uint64 { return 14 } // RegisterInvariants registers the capability module's invariants. func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} diff --git a/x/protocol/types/params.go b/x/protocol/types/params.go index 0c001bf121..8d56bb76bc 100644 --- a/x/protocol/types/params.go +++ b/x/protocol/types/params.go @@ -12,7 +12,7 @@ import ( var _ paramtypes.ParamSet = (*Params)(nil) const ( - TARGET_VERSION = "0.30.4" + TARGET_VERSION = "0.31.0" MIN_VERSION = "0.30.1" ) From f2cc4fc7e1868f94a46846daa3c900070e6b3c83 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Sun, 10 Dec 2023 15:43:58 +0000 Subject: [PATCH 58/85] done --- .../lava/dualstaking/delegation_que.proto | 11 - x/dualstaking/ante/ante_handler.go | 38 +- x/dualstaking/keeper/delegate_que.go | 49 --- x/dualstaking/keeper/hooks.go | 4 +- x/dualstaking/keeper/keeper.go | 2 + x/dualstaking/types/delegation_que.go | 18 - x/dualstaking/types/delegation_que.pb.go | 364 ------------------ 7 files changed, 20 insertions(+), 466 deletions(-) delete mode 100644 proto/lavanet/lava/dualstaking/delegation_que.proto delete mode 100644 x/dualstaking/keeper/delegate_que.go delete mode 100644 x/dualstaking/types/delegation_que.go delete mode 100644 x/dualstaking/types/delegation_que.pb.go diff --git a/proto/lavanet/lava/dualstaking/delegation_que.proto b/proto/lavanet/lava/dualstaking/delegation_que.proto deleted file mode 100644 index 0426845f7b..0000000000 --- a/proto/lavanet/lava/dualstaking/delegation_que.proto +++ /dev/null @@ -1,11 +0,0 @@ -syntax = "proto3"; -package lavanet.lava.dualstaking; - -option go_package = "github.com/lavanet/lava/x/dualstaking/types"; - -import "gogoproto/gogo.proto"; -import "cosmos/base/v1beta1/coin.proto"; - -message DelegationQue { - repeated bool Que = 1; -} \ No newline at end of file diff --git a/x/dualstaking/ante/ante_handler.go b/x/dualstaking/ante/ante_handler.go index e6842cdc37..ee9edb7b13 100644 --- a/x/dualstaking/ante/ante_handler.go +++ b/x/dualstaking/ante/ante_handler.go @@ -1,11 +1,12 @@ package ante import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/lavanet/lava/x/dualstaking/keeper" - "github.com/lavanet/lava/x/dualstaking/types" ) // RedelegationFlager sets the GasMeter in the Context and wraps the next AnteHandler with a defer clause @@ -22,28 +23,21 @@ func NewRedelegationFlager(dualstaking keeper.Keeper) RedelegationFlager { } func (rf RedelegationFlager) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { - que := types.DelegationQue{} - msgs := tx.GetMsgs() - for _, msg := range msgs { - switch msg.(type) { - case *stakingtypes.MsgBeginRedelegate: - que.Redelegate() - case *stakingtypes.MsgCreateValidator: - que.DelegateUnbond() - case *stakingtypes.MsgDelegate: - que.DelegateUnbond() - case *stakingtypes.MsgUndelegate: - que.DelegateUnbond() - case *stakingtypes.MsgCancelUnbondingDelegation: - que.DelegateUnbond() - case *types.MsgDelegate: - que.DelegateUnbond() - case *types.MsgUnbond: - que.DelegateUnbond() - - default: + redelegations := false + others := false + for _, msg := range tx.GetMsgs() { + if _, ok := msg.(*stakingtypes.MsgBeginRedelegate); ok { + redelegations = true + } else { + others = true } } - rf.SetDelegationQue(ctx, que) + + if redelegations && others { + return ctx, fmt.Errorf("cannot send batch requests with redelegation messages") + } + + keeper.RedelegationFlag = redelegations + return next(ctx, tx, simulate) } diff --git a/x/dualstaking/keeper/delegate_que.go b/x/dualstaking/keeper/delegate_que.go deleted file mode 100644 index 5ff946de53..0000000000 --- a/x/dualstaking/keeper/delegate_que.go +++ /dev/null @@ -1,49 +0,0 @@ -package keeper - -// Delegation allows securing funds for a specific provider to effectively increase -// its stake so it will be paired with consumers more often. The delegators do not -// transfer the funds to the provider but only bestow the funds with it. In return -// to locking the funds there, delegators get some of the provider’s profit (after -// commission deduction). -// -// The delegated funds are stored in the module's BondedPoolName account. On request -// to terminate the delegation, they are then moved to the modules NotBondedPoolName -// account, and remain locked there for staking.UnbondingTime() witholding period -// before finally released back to the delegator. The timers for bonded funds are -// tracked are indexed by the delegator, provider, and chainID. -// -// The delegation state is stores with fixation using two maps: one for delegations -// indexed by the combination , used to track delegations -// and find/access delegations by provider (and chainID); and another for delegators -// tracking the list of providers for a delegator, indexed by the delegator. - -import ( - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/lavanet/lava/x/dualstaking/types" -) - -func (k Keeper) SetDelegationQue(ctx sdk.Context, que types.DelegationQue) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.DelegationQueKeyPrefix)) - b := k.cdc.MustMarshal(&que) - store.Set([]byte{0}, b) -} - -func (k Keeper) GetDelegationQue(ctx sdk.Context) (val types.DelegationQue, found bool) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.DelegationQueKeyPrefix)) - - b := store.Get([]byte{0}) - if b == nil { - return val, false - } - - k.cdc.MustUnmarshal(b, &val) - return val, true -} - -func (k Keeper) DelegationQuePop(ctx sdk.Context) bool { - que, _ := k.GetDelegationQue(ctx) - item := que.DeQue() - k.SetDelegationQue(ctx, que) - return item -} diff --git a/x/dualstaking/keeper/hooks.go b/x/dualstaking/keeper/hooks.go index 551bc040ff..c3e48480ea 100644 --- a/x/dualstaking/keeper/hooks.go +++ b/x/dualstaking/keeper/hooks.go @@ -46,7 +46,7 @@ func (h Hooks) BeforeDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAd // create new delegation period record // add description func (h Hooks) AfterDelegationModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error { - if !h.k.DelegationQuePop(ctx) { + if RedelegationFlag { return nil } @@ -142,7 +142,7 @@ func (h Hooks) AfterValidatorBeginUnbonding(_ sdk.Context, _ sdk.ConsAddress, _ } func (h Hooks) BeforeDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error { - if !h.k.DelegationQuePop(ctx) { + if RedelegationFlag { return nil } diff --git a/x/dualstaking/keeper/keeper.go b/x/dualstaking/keeper/keeper.go index a6fabb47c8..29000897f1 100644 --- a/x/dualstaking/keeper/keeper.go +++ b/x/dualstaking/keeper/keeper.go @@ -14,6 +14,8 @@ import ( "github.com/lavanet/lava/x/dualstaking/types" ) +var RedelegationFlag bool + type ( Keeper struct { cdc codec.BinaryCodec diff --git a/x/dualstaking/types/delegation_que.go b/x/dualstaking/types/delegation_que.go deleted file mode 100644 index 32bbcb148d..0000000000 --- a/x/dualstaking/types/delegation_que.go +++ /dev/null @@ -1,18 +0,0 @@ -package types - -// mark the next to be a regular delegation/unbond, as stand alone we want to take action -func (dq *DelegationQue) DelegateUnbond() { - dq.Que = append(dq.Que, true) -} - -// redelegates does unbond and than redelegate, we dont want to take action in dual staking, mark them as false -func (dq *DelegationQue) Redelegate() { - dq.Que = append(dq.Que, false) - dq.Que = append(dq.Que, false) -} - -func (dq *DelegationQue) DeQue() bool { - item := dq.Que[0] - dq.Que = dq.Que[1:] - return item -} diff --git a/x/dualstaking/types/delegation_que.pb.go b/x/dualstaking/types/delegation_que.pb.go deleted file mode 100644 index 823d3dc825..0000000000 --- a/x/dualstaking/types/delegation_que.pb.go +++ /dev/null @@ -1,364 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: lavanet/lava/dualstaking/delegation_que.proto - -package types - -import ( - fmt "fmt" - _ "github.com/cosmos/cosmos-sdk/types" - _ "github.com/cosmos/gogoproto/gogoproto" - proto "github.com/cosmos/gogoproto/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// 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 - -type DelegationQue struct { - Que []bool `protobuf:"varint,1,rep,packed,name=Que,proto3" json:"Que,omitempty"` -} - -func (m *DelegationQue) Reset() { *m = DelegationQue{} } -func (m *DelegationQue) String() string { return proto.CompactTextString(m) } -func (*DelegationQue) ProtoMessage() {} -func (*DelegationQue) Descriptor() ([]byte, []int) { - return fileDescriptor_a56a227bbc9f22a1, []int{0} -} -func (m *DelegationQue) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *DelegationQue) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_DelegationQue.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 *DelegationQue) XXX_Merge(src proto.Message) { - xxx_messageInfo_DelegationQue.Merge(m, src) -} -func (m *DelegationQue) XXX_Size() int { - return m.Size() -} -func (m *DelegationQue) XXX_DiscardUnknown() { - xxx_messageInfo_DelegationQue.DiscardUnknown(m) -} - -var xxx_messageInfo_DelegationQue proto.InternalMessageInfo - -func (m *DelegationQue) GetQue() []bool { - if m != nil { - return m.Que - } - return nil -} - -func init() { - proto.RegisterType((*DelegationQue)(nil), "lavanet.lava.dualstaking.DelegationQue") -} - -func init() { - proto.RegisterFile("lavanet/lava/dualstaking/delegation_que.proto", fileDescriptor_a56a227bbc9f22a1) -} - -var fileDescriptor_a56a227bbc9f22a1 = []byte{ - // 201 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0xcd, 0x49, 0x2c, 0x4b, - 0xcc, 0x4b, 0x2d, 0xd1, 0x07, 0xd1, 0xfa, 0x29, 0xa5, 0x89, 0x39, 0xc5, 0x25, 0x89, 0xd9, 0x99, - 0x79, 0xe9, 0xfa, 0x29, 0xa9, 0x39, 0xa9, 0xe9, 0x89, 0x25, 0x99, 0xf9, 0x79, 0xf1, 0x85, 0xa5, - 0xa9, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0x12, 0x50, 0xe5, 0x7a, 0x20, 0x5a, 0x0f, 0x49, - 0xb9, 0x94, 0x48, 0x7a, 0x7e, 0x7a, 0x3e, 0x58, 0x91, 0x3e, 0x88, 0x05, 0x51, 0x2f, 0x25, 0x97, - 0x9c, 0x5f, 0x9c, 0x9b, 0x5f, 0xac, 0x9f, 0x94, 0x58, 0x9c, 0xaa, 0x5f, 0x66, 0x98, 0x94, 0x5a, - 0x92, 0x68, 0xa8, 0x9f, 0x9c, 0x9f, 0x99, 0x07, 0x91, 0x57, 0x52, 0xe4, 0xe2, 0x75, 0x81, 0xdb, - 0x13, 0x58, 0x9a, 0x2a, 0x24, 0xc0, 0xc5, 0x1c, 0x58, 0x9a, 0x2a, 0xc1, 0xa8, 0xc0, 0xac, 0xc1, - 0x11, 0x04, 0x62, 0x3a, 0xb9, 0x9e, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, - 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, - 0x76, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x3e, 0x8a, 0x37, 0x2a, 0x50, - 0x3c, 0x52, 0x52, 0x59, 0x90, 0x5a, 0x9c, 0xc4, 0x06, 0xb6, 0xd0, 0x18, 0x10, 0x00, 0x00, 0xff, - 0xff, 0xb6, 0xfd, 0xfd, 0xf9, 0xf1, 0x00, 0x00, 0x00, -} - -func (m *DelegationQue) 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 *DelegationQue) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *DelegationQue) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Que) > 0 { - for iNdEx := len(m.Que) - 1; iNdEx >= 0; iNdEx-- { - i-- - if m.Que[iNdEx] { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - } - i = encodeVarintDelegationQue(dAtA, i, uint64(len(m.Que))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func encodeVarintDelegationQue(dAtA []byte, offset int, v uint64) int { - offset -= sovDelegationQue(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *DelegationQue) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.Que) > 0 { - n += 1 + sovDelegationQue(uint64(len(m.Que))) + len(m.Que)*1 - } - return n -} - -func sovDelegationQue(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozDelegationQue(x uint64) (n int) { - return sovDelegationQue(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *DelegationQue) 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 ErrIntOverflowDelegationQue - } - 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: DelegationQue: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: DelegationQue: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType == 0 { - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowDelegationQue - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Que = append(m.Que, bool(v != 0)) - } else if wireType == 2 { - var packedLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowDelegationQue - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - packedLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if packedLen < 0 { - return ErrInvalidLengthDelegationQue - } - postIndex := iNdEx + packedLen - if postIndex < 0 { - return ErrInvalidLengthDelegationQue - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - var elementCount int - elementCount = packedLen - if elementCount != 0 && len(m.Que) == 0 { - m.Que = make([]bool, 0, elementCount) - } - for iNdEx < postIndex { - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowDelegationQue - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Que = append(m.Que, bool(v != 0)) - } - } else { - return fmt.Errorf("proto: wrong wireType = %d for field Que", wireType) - } - default: - iNdEx = preIndex - skippy, err := skipDelegationQue(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthDelegationQue - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipDelegationQue(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, ErrIntOverflowDelegationQue - } - 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, ErrIntOverflowDelegationQue - } - 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, ErrIntOverflowDelegationQue - } - 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, ErrInvalidLengthDelegationQue - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupDelegationQue - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthDelegationQue - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthDelegationQue = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowDelegationQue = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupDelegationQue = fmt.Errorf("proto: unexpected end of group") -) From 44e60f970265358e1108b17506d349cf5ba01369 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Sun, 10 Dec 2023 15:45:03 +0000 Subject: [PATCH 59/85] add script --- scripts/add_validator.sh | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 scripts/add_validator.sh diff --git a/scripts/add_validator.sh b/scripts/add_validator.sh new file mode 100644 index 0000000000..6cddb67345 --- /dev/null +++ b/scripts/add_validator.sh @@ -0,0 +1,20 @@ +clear +rm -rf ~/.lava_test +lavad init validator2 --chain-id lava --home ~/.lava_test +lavad config broadcast-mode sync --home ~/.lava_test +lavad config keyring-backend test --home ~/.lava_test +lavad keys add validator2 --home ~/.lava_test + +GASPRICE="0.000000001ulava" +lavad tx bank send $(lavad keys show alice -a) $(lavad keys show validator2 -a --home ~/.lava_test) 500000ulava -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE + +lavad tx staking create-validator -y --from validator2 --amount="50000ulava" --pubkey=$(lavad tendermint show-validator --home ~/.lava_test) --commission-rate="0.10" \ + --commission-max-rate="0.20" \ + --commission-max-change-rate="0.01" \ + --min-self-delegation="1000" \ + --gas-adjustment "1.5" \ + --gas "auto" \ + --gas-prices $GASPRICE \ + --home ~/.lava_test + +lavad tx staking redelegate lava@valoper1yhzkfrcdwf2hwpc4cre8er5tamp6wdm4stx2ec lava@valoper1z025w20ms6cpdht585nhsw682jph4yc7hx0gqc 500000000000ulava -y --from user1 --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE From a28a4a46d5a36ead7581611d2763f378958cd206 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Sun, 10 Dec 2023 15:47:02 +0000 Subject: [PATCH 60/85] add some stuff --- scripts/add_validator.sh | 1 + x/dualstaking/types/types.go | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/scripts/add_validator.sh b/scripts/add_validator.sh index 6cddb67345..a53986307f 100644 --- a/scripts/add_validator.sh +++ b/scripts/add_validator.sh @@ -1,3 +1,4 @@ +# this script is adding another validator to the chain (without a running node) (this validator will be soon jailed due to inactivity) clear rm -rf ~/.lava_test lavad init validator2 --chain-id lava --home ~/.lava_test diff --git a/x/dualstaking/types/types.go b/x/dualstaking/types/types.go index 57fb29b5a0..ca141ed0de 100644 --- a/x/dualstaking/types/types.go +++ b/x/dualstaking/types/types.go @@ -14,7 +14,3 @@ const ( NotBondedPoolName = "not_bonded_dualstaking_pool" BondedPoolName = "bonded_dualstaking_pool" ) - -const ( - DelegationQueKeyPrefix = "DelegationQue/value/" -) From 0f7eae8b17764ab612ec57c56aaf3ca4627cc23c Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Sun, 10 Dec 2023 16:03:24 +0000 Subject: [PATCH 61/85] pr changes --- x/dualstaking/ante/ante_handler.go | 9 +++------ x/dualstaking/keeper/hooks.go | 4 ++-- x/dualstaking/keeper/keeper.go | 5 ++++- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/x/dualstaking/ante/ante_handler.go b/x/dualstaking/ante/ante_handler.go index ee9edb7b13..9ff59686c4 100644 --- a/x/dualstaking/ante/ante_handler.go +++ b/x/dualstaking/ante/ante_handler.go @@ -9,11 +9,8 @@ import ( "github.com/lavanet/lava/x/dualstaking/keeper" ) -// RedelegationFlager sets the GasMeter in the Context and wraps the next AnteHandler with a defer clause -// to recover from any downstream OutOfGas panics in the AnteHandler chain to return an error with information -// on gas provided and gas used. -// CONTRACT: Must be first decorator in the chain -// CONTRACT: Tx must implement GasTx interface +// RedelegationFlager sets the dualstaking redelegation flag when needed. +// when the user sends redelegation tx we dont want the hooks to do anything type RedelegationFlager struct { keeper.Keeper } @@ -37,7 +34,7 @@ func (rf RedelegationFlager) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate boo return ctx, fmt.Errorf("cannot send batch requests with redelegation messages") } - keeper.RedelegationFlag = redelegations + keeper.DisableDualstakingHook = redelegations return next(ctx, tx, simulate) } diff --git a/x/dualstaking/keeper/hooks.go b/x/dualstaking/keeper/hooks.go index c3e48480ea..72b77c6a9c 100644 --- a/x/dualstaking/keeper/hooks.go +++ b/x/dualstaking/keeper/hooks.go @@ -46,7 +46,7 @@ func (h Hooks) BeforeDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAd // create new delegation period record // add description func (h Hooks) AfterDelegationModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error { - if RedelegationFlag { + if DisableDualstakingHook { return nil } @@ -142,7 +142,7 @@ func (h Hooks) AfterValidatorBeginUnbonding(_ sdk.Context, _ sdk.ConsAddress, _ } func (h Hooks) BeforeDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error { - if RedelegationFlag { + if DisableDualstakingHook { return nil } diff --git a/x/dualstaking/keeper/keeper.go b/x/dualstaking/keeper/keeper.go index 29000897f1..ab9a1303d9 100644 --- a/x/dualstaking/keeper/keeper.go +++ b/x/dualstaking/keeper/keeper.go @@ -14,7 +14,10 @@ import ( "github.com/lavanet/lava/x/dualstaking/types" ) -var RedelegationFlag bool +// dualstaking uses hookd to catch delegations/unbonding tx's to do the same action on the providers delegations. +// in the case of redelegation, since the user doesnt put/takes tokens back we dont want to take action in the providers delegations. +// this flag is a local flag used to mark the next hooks to do nothing since this was cause by redelegation tx (redelegation = delegation + unbond) +var DisableDualstakingHook bool type ( Keeper struct { From 2cd1c2fcac298eb66a703ed06a9f609541e480a4 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Sun, 10 Dec 2023 16:04:06 +0000 Subject: [PATCH 62/85] linter --- x/dualstaking/keeper/keeper.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/dualstaking/keeper/keeper.go b/x/dualstaking/keeper/keeper.go index ab9a1303d9..a899e436b7 100644 --- a/x/dualstaking/keeper/keeper.go +++ b/x/dualstaking/keeper/keeper.go @@ -14,7 +14,7 @@ import ( "github.com/lavanet/lava/x/dualstaking/types" ) -// dualstaking uses hookd to catch delegations/unbonding tx's to do the same action on the providers delegations. +// DisableDualstakingHook: dualstaking uses hookd to catch delegations/unbonding tx's to do the same action on the providers delegations. // in the case of redelegation, since the user doesnt put/takes tokens back we dont want to take action in the providers delegations. // this flag is a local flag used to mark the next hooks to do nothing since this was cause by redelegation tx (redelegation = delegation + unbond) var DisableDualstakingHook bool From 30ad6c1d61bd397399c3f84cd197506489faf82d Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Sun, 10 Dec 2023 16:04:27 +0000 Subject: [PATCH 63/85] bahh --- x/dualstaking/keeper/keeper.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/dualstaking/keeper/keeper.go b/x/dualstaking/keeper/keeper.go index a899e436b7..5c32a98a93 100644 --- a/x/dualstaking/keeper/keeper.go +++ b/x/dualstaking/keeper/keeper.go @@ -14,7 +14,7 @@ import ( "github.com/lavanet/lava/x/dualstaking/types" ) -// DisableDualstakingHook: dualstaking uses hookd to catch delegations/unbonding tx's to do the same action on the providers delegations. +// DisableDualstakingHook : dualstaking uses hookd to catch delegations/unbonding tx's to do the same action on the providers delegations. // in the case of redelegation, since the user doesnt put/takes tokens back we dont want to take action in the providers delegations. // this flag is a local flag used to mark the next hooks to do nothing since this was cause by redelegation tx (redelegation = delegation + unbond) var DisableDualstakingHook bool From 99fa374342a2c6690bf1ca151b1fa127a3b8bda7 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Sun, 10 Dec 2023 16:07:48 +0000 Subject: [PATCH 64/85] upgrade handler --- app/app.go | 1 + app/upgrades/empty_upgrades.go | 6 ++++++ x/protocol/module.go | 7 ++++++- x/protocol/types/params.go | 2 +- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/app/app.go b/app/app.go index 4ab68aa18a..10c0649170 100644 --- a/app/app.go +++ b/app/app.go @@ -162,6 +162,7 @@ var Upgrades = []upgrades.Upgrade{ upgrades.Upgrade_0_30_1, upgrades.Upgrade_0_30_2, upgrades.Upgrade_0_31_0, + upgrades.Upgrade_0_31_1, } // this line is used by starport scaffolding # stargate/wasm/app/enabledProposals diff --git a/app/upgrades/empty_upgrades.go b/app/upgrades/empty_upgrades.go index b2cea62038..da2d702f8c 100644 --- a/app/upgrades/empty_upgrades.go +++ b/app/upgrades/empty_upgrades.go @@ -164,3 +164,9 @@ var Upgrade_0_31_0 = Upgrade{ CreateUpgradeHandler: defaultUpgradeHandler, StoreUpgrades: store.StoreUpgrades{}, } + +var Upgrade_0_31_1 = Upgrade{ + UpgradeName: "v0.31.1", + CreateUpgradeHandler: defaultUpgradeHandler, + StoreUpgrades: store.StoreUpgrades{}, +} diff --git a/x/protocol/module.go b/x/protocol/module.go index f0cd7584f2..5dbd3fcd4e 100644 --- a/x/protocol/module.go +++ b/x/protocol/module.go @@ -192,10 +192,15 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // panic:ok: at start up, migration cannot proceed anyhow panic(fmt.Errorf("%s: failed to register migration to v14: %w", types.ModuleName, err)) } + + if err := cfg.RegisterMigration(types.ModuleName, 14, migrator.MigrateVersion); err != nil { + // panic:ok: at start up, migration cannot proceed anyhow + panic(fmt.Errorf("%s: failed to register migration to v15: %w", types.ModuleName, err)) + } } // ConsensusVersion implements ConsensusVersion. -func (AppModule) ConsensusVersion() uint64 { return 14 } +func (AppModule) ConsensusVersion() uint64 { return 15 } // RegisterInvariants registers the capability module's invariants. func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} diff --git a/x/protocol/types/params.go b/x/protocol/types/params.go index 8d56bb76bc..cf99c326c8 100644 --- a/x/protocol/types/params.go +++ b/x/protocol/types/params.go @@ -12,7 +12,7 @@ import ( var _ paramtypes.ParamSet = (*Params)(nil) const ( - TARGET_VERSION = "0.31.0" + TARGET_VERSION = "0.31.1" MIN_VERSION = "0.30.1" ) From 53a44f9193f0955c1d4f2a0e34d0f342788070dc Mon Sep 17 00:00:00 2001 From: OneEuroQuestion <134633990+oneeuroquestion@users.noreply.github.com> Date: Sun, 10 Dec 2023 18:10:57 +0100 Subject: [PATCH 65/85] GROW-1144 makefile fixes for macos (#1001) * GROW-1144 makefile fixes for macos * fixing file --------- Co-authored-by: Michael Cotic Co-authored-by: Ran Mishael --- Readme.md | 21 ++++++++++++++------- scripts/init_install.sh | 37 +++++++++++++++++++++---------------- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/Readme.md b/Readme.md index d0d2125455..07a96d1a34 100644 --- a/Readme.md +++ b/Readme.md @@ -3,7 +3,6 @@ parent: order: false --> -

Logo Lava Network

@@ -11,6 +10,7 @@ parent: ![image](https://user-images.githubusercontent.com/2770565/203528359-dced4d06-f020-4b6a-bb5f-319124924689.png) ### What is Lava? + The Lava Protocol aims to provide decentralized and scalable access to blockchain data through the use of a network of providers and consumers. It utilizes a proof-of-stake consensus mechanism and incentivizes participants through the use of its native LAVA token. The protocol includes features such as a stake-weighted pseudorandom pairing function, backfilling, and a lazy settlement process to improve scalability and efficiency. The roadmap for the Lava Protocol includes further development of governance, conflict resolution, privacy, and quality of service, as well as support for additional API specifications. It is designed to be a public good that enables decentralized access to the Web3 ecosystem. Read more about Lava in the [litepaper](https://litepaper.lavanet.xyz?utm_source=github.com&utm_medium=github&utm_campaign=readme) and visit the [Docs](https://docs.lavanet.xyz?utm_source=github.com&utm_medium=github&utm_campaign=readme) @@ -22,31 +22,38 @@ Lava is built using the [Cosmos SDK](https://github.com/cosmos/cosmos-sdk/) whic **Note**: Requires [Go 1.20.5](https://golang.org/dl/) ### Installing development dependencies + before running the scripts make sure you have go installed and added to $PATH, you can validate by running `which go` init_install will install all necessary dependencies to develop on lava. + ```bash ./scripts/init_install.sh ``` ## Building the binaries -install-all will build all lava binaries (lavad, lavap, lavavisor) and place them in the go bin path on your environment. + +LAVA_BINARY=all will build all lava binaries (lavad, lavap, lavavisor) and place them in the go bin path on your environment. + ```bash -make install-all +LAVA_BINARY=all make install ``` ### Building the binaries locally -You can also build the binaries locally (path will be ./build/...) by running + +You can also build the binaries locally (path will be ./build/...) by running + ```bash -make build-all +LAVA_BINARY=all make build ``` ### Building only a specific binary -it is possible to also build only one binary, for example lavad only. + +it is possible to build only one binary: lavad/lavap/lavavisor + ```bash LAVA_BINARY=lavad make install ``` - Or check out the latest [release](https://github.com/lavanet/lava/releases). ### Add `lavad` autocomplete diff --git a/scripts/init_install.sh b/scripts/init_install.sh index 4701782611..f533d019e4 100755 --- a/scripts/init_install.sh +++ b/scripts/init_install.sh @@ -42,26 +42,31 @@ fi ############################# BUF INSTALLATION ###################################### if ! command_exists buf; then - # Define the version of buf to install - BUF_VERSION="1.25.0" # Update this to the latest version if needed + if [[ "$OSTYPE" == "darwin"* ]]; then + # If the operating system is MacOS, use brew to install buf + brew install buf + else + # Define the version of buf to install + BUF_VERSION="1.25.0" # Update this to the latest version if needed - # Define the installation directory - INSTALL_DIR="/usr/local/bin" # You might need to adjust this based on your preferences + # Define the installation directory + INSTALL_DIR="/usr/local/bin" # You might need to adjust this based on your preferences - # Download and install buf - echo "Downloading buf version $BUF_VERSION..." - curl -sSL "https://github.com/bufbuild/buf/releases/download/v${BUF_VERSION}/buf-$(uname -s)-$(uname -m)" -o "${INSTALL_DIR}/buf" + # Download and install buf + echo "Downloading buf version $BUF_VERSION..." + curl -sSL "https://github.com/bufbuild/buf/releases/download/v${BUF_VERSION}/buf-$(uname -s)-$(uname -m)" -o "${INSTALL_DIR}/buf" - # Add execute permissions to the buf binary - chmod +x "${INSTALL_DIR}/buf" + # Add execute permissions to the buf binary + chmod +x "${INSTALL_DIR}/buf" - # Check if the installation was successful - if [ $? -eq 0 ]; then - echo "buf version $BUF_VERSION has been installed to $INSTALL_DIR." - exit 0 - else - echo "An error occurred during the buf installation process. Please install buf manually." - exit 1 + # Check if the installation was successful + if [ $? -eq 0 ]; then + echo "buf version $BUF_VERSION has been installed to $INSTALL_DIR." + exit 0 + else + echo "An error occurred during the buf installation process. Please install buf manually." + exit 1 + fi fi else echo "buf is already installed" From ba1aac71de905d1b91602bb56ae30e620b7c375d Mon Sep 17 00:00:00 2001 From: Ran Mishael <106548467+ranlavanet@users.noreply.github.com> Date: Mon, 11 Dec 2023 14:44:58 +0100 Subject: [PATCH 66/85] PRT-976 Sdk init specific api interface (#1038) * WIP * adding the functionality to skip api interfaces! * fixing bug in init * adding log information when specifying wrong api interfaces * v0.30.4 * fix warning --- .../param_changes/param_change_downtime.json | 12 ++ ecosystem/lava-sdk/package.json | 2 +- .../lava-sdk/scripts/setup_sdk_with_local.sh | 2 +- .../src/chainlib/base_chain_parser.ts | 6 + .../src/rpcconsumer/rpcconsumer_server.ts | 3 - ecosystem/lava-sdk/src/sdk/sdk.ts | 114 +++++++++++++++--- .../lava-sdk/src/stateTracker/types/types.ts | 19 +++ 7 files changed, 134 insertions(+), 24 deletions(-) create mode 100644 cookbook/param_changes/param_change_downtime.json create mode 100644 ecosystem/lava-sdk/src/stateTracker/types/types.ts diff --git a/cookbook/param_changes/param_change_downtime.json b/cookbook/param_changes/param_change_downtime.json new file mode 100644 index 0000000000..71d5218f4b --- /dev/null +++ b/cookbook/param_changes/param_change_downtime.json @@ -0,0 +1,12 @@ +{ + "title": "Emergency Mode - Epoch Duration Update", + "description": "Change the Emergency Mode Epoch Duration", + "changes": [ + { + "subspace": "downtime", + "key": "EpochDuration", + "value": "900000000000" + } + ], + "deposit": "10000000ulava" +} \ No newline at end of file diff --git a/ecosystem/lava-sdk/package.json b/ecosystem/lava-sdk/package.json index 96f9d33b14..01b723e865 100644 --- a/ecosystem/lava-sdk/package.json +++ b/ecosystem/lava-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@lavanet/lava-sdk", - "version": "0.30.3", + "version": "0.30.4", "description": "An SDK for interacting with Lava provider", "main": "./bin/src/sdk/sdk.js", "author": "Lava Protocol Inc", diff --git a/ecosystem/lava-sdk/scripts/setup_sdk_with_local.sh b/ecosystem/lava-sdk/scripts/setup_sdk_with_local.sh index 418b00f6de..6322721e47 100755 --- a/ecosystem/lava-sdk/scripts/setup_sdk_with_local.sh +++ b/ecosystem/lava-sdk/scripts/setup_sdk_with_local.sh @@ -70,7 +70,7 @@ json_content+=' ] echo "$json_content" > pairingList.json -GEOLOCATION=2 +GEOLOCATION=1 cp examples/jsonRPC.ts examples/jsonRPC_test.ts cp examples/restAPI.ts examples/restAPI_test.ts diff --git a/ecosystem/lava-sdk/src/chainlib/base_chain_parser.ts b/ecosystem/lava-sdk/src/chainlib/base_chain_parser.ts index b9fc55162d..d64f4552fb 100644 --- a/ecosystem/lava-sdk/src/chainlib/base_chain_parser.ts +++ b/ecosystem/lava-sdk/src/chainlib/base_chain_parser.ts @@ -16,6 +16,12 @@ export const APIInterfaceJsonRPC = "jsonrpc"; export const APIInterfaceTendermintRPC = "tendermintrpc"; export const APIInterfaceRest = "rest"; export const APIInterfaceGrpc = "grpc"; +export const AllApiInterfaces = [ + APIInterfaceJsonRPC, + APIInterfaceTendermintRPC, + APIInterfaceRest, + APIInterfaceGrpc, +]; export const HeadersPassSend = Header.HeaderType.PASS_SEND; /** diff --git a/ecosystem/lava-sdk/src/rpcconsumer/rpcconsumer_server.ts b/ecosystem/lava-sdk/src/rpcconsumer/rpcconsumer_server.ts index 35aa5104d8..74bc8b5a0c 100644 --- a/ecosystem/lava-sdk/src/rpcconsumer/rpcconsumer_server.ts +++ b/ecosystem/lava-sdk/src/rpcconsumer/rpcconsumer_server.ts @@ -403,10 +403,7 @@ export class RPCConsumerServer { return relayResponse; } const chainBlockStats = this.chainParser.chainBlockStats(); - Logger.debug("Updating requested Block", singleConsumerSession.sessionId); UpdateRequestedBlock(relayData, reply); - Logger.debug("after Updating", relayData.getRequestBlock()); - Logger.debug("did errored", relayResponse.err); const finalized = IsFinalizedBlock( relayData.getRequestBlock(), reply.getLatestBlock(), diff --git a/ecosystem/lava-sdk/src/sdk/sdk.ts b/ecosystem/lava-sdk/src/sdk/sdk.ts index a856572697..58015304a8 100644 --- a/ecosystem/lava-sdk/src/sdk/sdk.ts +++ b/ecosystem/lava-sdk/src/sdk/sdk.ts @@ -21,6 +21,7 @@ import { SendRelayOptions, SendRelaysBatchOptions, SendRestRelayOptions, + AllApiInterfaces, } from "../chainlib/base_chain_parser"; import { JsonRpcChainParser } from "../chainlib/jsonrpc"; import { RestChainParser } from "../chainlib/rest"; @@ -34,27 +35,42 @@ import { import { AverageWorldLatency } from "../common/timeout"; import { ConsumerConsistency } from "../rpcconsumer/consumerConsistency"; import { GeolocationFromString } from "../lavasession/geolocation"; - -export type ChainIDsToInit = string | string[]; // chainId or an array of chain ids to initialize sdk for. +import { + ChainIDsToInit, + ChainIdSpecification, +} from "../stateTracker/types/types"; type RelayReceiver = string; // chainId + ApiInterface /** * Options for initializing the LavaSDK. + * @param privateKey // Required: The private key of the staked Lava client for the specified chainID + * @param badge // Required: Public URL of badge server and ID of the project you want to connect. Remove privateKey if badge is enabled. + * @param chainIds // Required: The ID of the chain you want to query or an array of chain ids example "ETH1" | ["ETH1", "LAV1"] + * @param pairingListConfig // Optional: The Lava pairing list config used for communicating with the Lava network + * @param network // Optional: The network from pairingListConfig to be used ["mainnet", "testnet"] + * @param geolocation // Optional: The geolocation to be used ["1" or "USC" for US central, "2" or "EU" for Europe, 4: "USE", 8: "USW", 16: "AF", 32: "AS", 64: "AU"] + * @param lavaChainId // Optional: The Lava chain ID (default value for Lava Testnet) + * @param secure // Optional: communicates through https, this is a temporary flag that will be disabled once the chain will use https by default + * @param allowInsecureTransport // Optional: indicates to use a insecure transport when connecting the provider, this is used for testing purposes only and allows self-signed certificates to be used + * @param logLevel // Optional for log level settings, "debug" | "info" | "warn" | "error" | "success" | "NoPrints" + * @param transport // Optional for transport settings if you would like to change the default transport settings. see utils/browser.ts for the current settings + * @param providerOptimizerStrategy // Optional: the strategy to use to pick providers (default: balanced) + * @param maxConcurrentProviders // Optional: the maximum number of providers to use concurrently (default: 3)} */ export interface LavaSDKOptions { - privateKey?: string; // Required: The private key of the staked Lava client for the specified chainID - badge?: BadgeOptions; // Required: Public URL of badge server and ID of the project you want to connect. Remove privateKey if badge is enabled. - chainIds: ChainIDsToInit; // Required: The ID of the chain you want to query or an array of chain ids example "ETH1" | ["ETH1", "LAV1"] - pairingListConfig?: string; // Optional: The Lava pairing list config used for communicating with the Lava network - network?: string; // Optional: The network from pairingListConfig to be used ["mainnet", "testnet"] - geolocation?: string; // Optional: The geolocation to be used ["1" or "USC" for US central, "2" or "EU" for Europe, 4: "USE", 8: "USW", 16: "AF", 32: "AS", 64: "AU"] - lavaChainId?: string; // Optional: The Lava chain ID (default value for Lava Testnet) - secure?: boolean; // Optional: communicates through https, this is a temporary flag that will be disabled once the chain will use https by default - allowInsecureTransport?: boolean; // Optional: indicates to use a insecure transport when connecting the provider, this is used for testing purposes only and allows self-signed certificates to be used - logLevel?: string | LogLevel; // Optional for log level settings, "debug" | "info" | "warn" | "error" | "success" | "NoPrints" - transport?: any; // Optional for transport settings if you would like to change the default transport settings. see utils/browser.ts for the current settings - providerOptimizerStrategy?: ProviderOptimizerStrategy; // Optional: the strategy to use to pick providers (default: balanced) - maxConcurrentProviders?: number; // Optional: the maximum number of providers to use concurrently (default: 3)} + privateKey?: string; + badge?: BadgeOptions; + chainIds: ChainIDsToInit; + pairingListConfig?: string; + network?: string; + geolocation?: string; + lavaChainId?: string; + secure?: boolean; + allowInsecureTransport?: boolean; + logLevel?: string | LogLevel; + transport?: any; + providerOptimizerStrategy?: ProviderOptimizerStrategy; + maxConcurrentProviders?: number; } export class LavaSDK { @@ -68,7 +84,7 @@ export class LavaSDK { private account: AccountData | Error; private secure: boolean; private allowInsecureTransport: boolean; - private chainIDRpcInterface: string[]; + private chainIDRpcInterface: ChainIdSpecification; private transport: any; private rpcConsumerServerRouter: Map; // routing the right chainID and apiInterface to rpc server private relayer?: Relayer; // we setup the relayer in the init function as we require extra information @@ -228,12 +244,21 @@ export class LavaSDK { consumerConsistency ); } + const chainIds: string[] = []; + this.chainIDRpcInterface.forEach((specification) => { + if (typeof specification == "string") { + chainIds.push(specification); + } else { + // If it's ChainIdWithSpecificAPIInterfaces, extract chainId and append it to chainIDs + chainIds.push(specification.chainId); + } + }); // Init state tracker const tracker = new StateTracker( this.pairingListConfig, this.relayer, - this.chainIDRpcInterface, + chainIds, { geolocation: this.geolocation, network: this.network, @@ -267,7 +292,25 @@ export class LavaSDK { await tracker.initialize(); // init rpcconsumer servers - for (const chainId of this.chainIDRpcInterface) { + for (const specification of this.chainIDRpcInterface) { + let chainId: string; + let apiInterfaceSpecification: string[] = []; + if (typeof specification == "string") { + chainId = specification; + } else { + chainId = specification.chainId; + apiInterfaceSpecification = specification.apiInterfaces; + apiInterfaceSpecification.forEach((apiInterface) => { + if (!AllApiInterfaces.includes(apiInterface)) { + Logger.error( + "Api interface does not exist, allowed list:", + AllApiInterfaces, + "provided:", + apiInterface + ); + } + }); + } const pairingResponse = tracker.getPairingResponse(chainId); if (pairingResponse == undefined) { @@ -296,6 +339,17 @@ export class LavaSDK { Logger.debug("Skipping grpc for: ", chainId); continue; } + // check if we have a specification for api interfaces if we do we need to check the api interface fits the specification + if ( + apiInterfaceSpecification.length > 0 && + !apiInterfaceSpecification.includes(apiInterface) + ) { + Logger.debug( + "Skipping API Interface as its not mentioned in apiSpecification: ", + apiInterface + ); + continue; + } // in case we have rest - POST + rest - GET collections this will prevent us from adding the same chainId and apiInterface twice if ( @@ -381,6 +435,26 @@ export class LavaSDK { rpcConsumerServer ); } + + if (this.rpcConsumerServerRouter.size < 1) { + const skippedApiInterfaces: Array = []; + apiCollectionList.forEach((collection) => { + skippedApiInterfaces.push( + collection.getCollectionData()?.getApiInterface() + ); + }); + + Logger.warn( + "unexpected behavior rpcConsumerServerRouter size is smaller than 1 while finished initializing", + chainId, + "skipped initializing the following Api interfaces", + skippedApiInterfaces, + ",map:", + JSON.stringify(this.rpcConsumerServerRouter.values()), + "VS your api specification", + apiInterfaceSpecification + ); + } } await tracker.startTracking(); } @@ -512,7 +586,9 @@ export class LavaSDK { rpcConsumerServer.message, "Check you initialized the chains properly", "Chain Requested", - options?.chainId ?? JSON.stringify(this.rpcConsumerServerRouter.keys()) + options?.chainId, + "Chains stored:", + JSON.stringify(this.rpcConsumerServerRouter.keys()) ); } diff --git a/ecosystem/lava-sdk/src/stateTracker/types/types.ts b/ecosystem/lava-sdk/src/stateTracker/types/types.ts new file mode 100644 index 0000000000..dadf2cfc60 --- /dev/null +++ b/ecosystem/lava-sdk/src/stateTracker/types/types.ts @@ -0,0 +1,19 @@ +export type ChainIDsToInit = string | ChainIdSpecification; + +/** + * @param ChainIdWithSpecificAPIInterfaces Use ChainIdWithSpecificAPIInterfaces if you want to initialize only a specific api interface + for example, some chains are initializing 2-3 api interfaces (tendermint, rest, jsonrpc) + use this functionality to initialize specific api interfaces for less traffic if you are not using them. (the sdk will not probe these interfaces) + */ +export type ChainIdSpecification = + | string[] + | ChainIdWithSpecificAPIInterfaces[]; // chainId or an array of chain ids to initialize sdk for. + +/** + * @param chainId chain id to initialize + * @param apiInterfaces list of api interfaces to initialize + */ +export interface ChainIdWithSpecificAPIInterfaces { + chainId: string; + apiInterfaces: string[]; +} From bb9918989d6ad5c82fe0fc432a95be99c17c4ece Mon Sep 17 00:00:00 2001 From: oren-lava Date: Wed, 13 Dec 2023 14:35:14 +0200 Subject: [PATCH 67/85] CNS-773: disable payment e2e --- .github/workflows/e2e.yml | 68 +++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 2ef5fe025f..59538ffbc2 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -203,38 +203,38 @@ jobs: go-version: 1.20.5 ###################################################### - ### Run Lava Protocol Payment E2E Tests + ### Run Lava Protocol Payment E2E Tests - temporarily disabled ###################################################### - - name: Run Lava Payment E2E Tests -timeout 1200s - run: go test ./testutil/e2e/ -run ^TestLavaProtocolPayment$ -v -timeout 1200s # 20mins - - - name: tail -n 300 Lavad Logs - if: always() - run: tail -n 300 testutil/e2e/protocolLogs/00_StartLava.log - - - name: Stake Lava All Logs - if: always() - run: cat testutil/e2e/protocolLogs/01_stakeLavaForPayment.log - - - name: Stake Lava Error Only Logs - if: always() - continue-on-error: true - run: cat testutil/e2e/protocolLogs/01_stakeLava_errors.log - - - name: Lava Provider All Logs - if: always() - run: grep "" testutil/e2e/protocolLogs/05_LavaProvider* --exclude="*errors*" - - - name: Lava Provider Error Only Logs - if: always() - continue-on-error: true - run: grep "" testutil/e2e/protocolLogs/05_LavaProvider* --include="*errors*" - - - name: RPCConsumer Consumer All Logs - if: always() - run: grep "" testutil/e2e/protocolLogs/06_RPCConsumer* --exclude="*errors*" - - - name: RPCConsumer Consumer Error Only Logs - if: always() - continue-on-error: true - run: grep "" testutil/e2e/protocolLogs/06_RPCConsumer* --include="*errors*" + # - name: Run Lava Payment E2E Tests -timeout 1200s + # run: go test ./testutil/e2e/ -run ^TestLavaProtocolPayment$ -v -timeout 1200s # 20mins + + # - name: tail -n 300 Lavad Logs + # if: always() + # run: tail -n 300 testutil/e2e/protocolLogs/00_StartLava.log + + # - name: Stake Lava All Logs + # if: always() + # run: cat testutil/e2e/protocolLogs/01_stakeLavaForPayment.log + + # - name: Stake Lava Error Only Logs + # if: always() + # continue-on-error: true + # run: cat testutil/e2e/protocolLogs/01_stakeLava_errors.log + + # - name: Lava Provider All Logs + # if: always() + # run: grep "" testutil/e2e/protocolLogs/05_LavaProvider* --exclude="*errors*" + + # - name: Lava Provider Error Only Logs + # if: always() + # continue-on-error: true + # run: grep "" testutil/e2e/protocolLogs/05_LavaProvider* --include="*errors*" + + # - name: RPCConsumer Consumer All Logs + # if: always() + # run: grep "" testutil/e2e/protocolLogs/06_RPCConsumer* --exclude="*errors*" + + # - name: RPCConsumer Consumer Error Only Logs + # if: always() + # continue-on-error: true + # run: grep "" testutil/e2e/protocolLogs/06_RPCConsumer* --include="*errors*" From 981471ba26c3afca58f8711b4860baccb6d5d88b Mon Sep 17 00:00:00 2001 From: oren-lava Date: Wed, 13 Dec 2023 14:37:08 +0200 Subject: [PATCH 68/85] CNS-773: completely disable --- .github/workflows/e2e.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 59538ffbc2..b6b228dda3 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -192,15 +192,15 @@ jobs: if: always() continue-on-error: true run: grep "" testutil/e2e/sdkLogs/01_sdkTest* --include="*errors*" - test-payment-e2e: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: "0" - - uses: actions/setup-go@v3 - with: - go-version: 1.20.5 + # test-payment-e2e: + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v3 + # with: + # fetch-depth: "0" + # - uses: actions/setup-go@v3 + # with: + # go-version: 1.20.5 ###################################################### ### Run Lava Protocol Payment E2E Tests - temporarily disabled From f95de739f858bdc297073cc9ebba1c19627f52d0 Mon Sep 17 00:00:00 2001 From: Yaroms <103432884+Yaroms@users.noreply.github.com> Date: Wed, 13 Dec 2023 18:31:27 +0200 Subject: [PATCH 69/85] sepsep (#1042) Co-authored-by: Yarom Swisa --- cookbook/specs/spec_add_arbitrum.json | 43 +++++++++++++++++++++ cookbook/specs/spec_add_optimism.json | 43 +++++++++++++++++++++ cookbook/specs/spec_add_starknet.json | 55 +++++++++++++++++++++++++++ 3 files changed, 141 insertions(+) diff --git a/cookbook/specs/spec_add_arbitrum.json b/cookbook/specs/spec_add_arbitrum.json index e977dd51d7..6d7cb3e1ea 100644 --- a/cookbook/specs/spec_add_arbitrum.json +++ b/cookbook/specs/spec_add_arbitrum.json @@ -88,6 +88,49 @@ ] } ] + }, + { + "index": "ARBS", + "name": "arbitrum sepolia testnet", + "enabled": true, + "imports": [ + "ARB1" + ], + "reliability_threshold": 268435455, + "data_reliability_enabled": true, + "block_distance_for_finalized_data": 1, + "blocks_in_finalization_proof": 3, + "average_block_time": 500, + "allowed_block_lag_for_qos_sync": 20, + "min_stake_provider": { + "denom": "ulava", + "amount": "50000000000" + }, + "api_collections": [ + { + "enabled": true, + "collection_data": { + "api_interface": "jsonrpc", + "internal_path": "", + "type": "POST", + "add_on": "" + }, + "apis": [], + "headers": [], + "inheritance_apis": [], + "parse_directives": [], + "verifications": [ + { + "name": "chain-id", + "values": [ + { + "expected_value": "0x66eee" + } + ] + } + ] + } + ] } ] }, diff --git a/cookbook/specs/spec_add_optimism.json b/cookbook/specs/spec_add_optimism.json index 834c8902c5..2cd36902c4 100644 --- a/cookbook/specs/spec_add_optimism.json +++ b/cookbook/specs/spec_add_optimism.json @@ -179,6 +179,49 @@ ] } ] + }, + { + "index": "OPTMS", + "name": "optimism sepolia testnet", + "enabled": true, + "imports": [ + "OPTM" + ], + "reliability_threshold": 268435455, + "data_reliability_enabled": true, + "block_distance_for_finalized_data": 1, + "blocks_in_finalization_proof": 1, + "average_block_time": 5000, + "allowed_block_lag_for_qos_sync": 200, + "min_stake_provider": { + "denom": "ulava", + "amount": "50000000000" + }, + "api_collections": [ + { + "enabled": true, + "collection_data": { + "api_interface": "jsonrpc", + "internal_path": "", + "type": "POST", + "add_on": "" + }, + "apis": [], + "headers": [], + "inheritance_apis": [], + "parse_directives": [], + "verifications": [ + { + "name": "chain-id", + "values": [ + { + "expected_value": "0xaa37dc" + } + ] + } + ] + } + ] } ] }, diff --git a/cookbook/specs/spec_add_starknet.json b/cookbook/specs/spec_add_starknet.json index 38779a5807..20b00f3107 100644 --- a/cookbook/specs/spec_add_starknet.json +++ b/cookbook/specs/spec_add_starknet.json @@ -620,6 +620,61 @@ ] } ] + }, + { + "index": "STRKS", + "name": "starknet sepolia testnet", + "enabled": true, + "imports": [ + "STRK" + ], + "reliability_threshold": 268435455, + "data_reliability_enabled": true, + "block_distance_for_finalized_data": 1, + "blocks_in_finalization_proof": 3, + "average_block_time": 1800000, + "allowed_block_lag_for_qos_sync": 1, + "min_stake_provider": { + "denom": "ulava", + "amount": "50000000000" + }, + "api_collections": [ + { + "enabled": true, + "collection_data": { + "api_interface": "jsonrpc", + "internal_path": "", + "type": "POST", + "add_on": "" + }, + "apis": [], + "headers": [], + "inheritance_apis": [], + "parse_directives": [], + "verifications": [ + { + "name": "chain-id", + "parse_directive": { + "function_template": "{\"jsonrpc\":\"2.0\",\"method\":\"starknet_chainId\",\"params\":[],\"id\":1}", + "function_tag": "VERIFICATION", + "result_parsing": { + "parser_arg": [ + "0" + ], + "parser_func": "PARSE_BY_ARG", + "encoding": "hex" + }, + "api_name": "starknet_chainId" + }, + "values": [ + { + "expected_value": "0x534e5f5345504f4c4941" + } + ] + } + ] + } + ] } ] }, From 4d71b87f0e0c3f335c4f91a2f7703e56f4f20a2e Mon Sep 17 00:00:00 2001 From: Ran Mishael <106548467+ranlavanet@users.noreply.github.com> Date: Wed, 13 Dec 2023 19:15:37 +0100 Subject: [PATCH 70/85] PRT-1041 Stability, sequence number failures fix, spamming errors fix (#1043) * fixed a spamming error for websocket close on other cases (normal, going away etc..) * changing log level for failing to connect, this is not an error as we cant control it. * adding more info for api requests * adding a better error handling for currently disabled subscription * PRT-1035 - Identified the issue in payment failing, Simulating the tx could also fail on sequence number. added a retry and protection. * PRT-1045 api not supported is not an error. its a user mistake mostly. reducing to info level * PRT-1045 reducing error to info level on get supported api. * fixing log * adding evmos script for debugging * Update protocol/chainlib/base_chain_parser.go * fixing missing error handling * increase size to 32mb --- protocol/chainlib/base_chain_parser.go | 5 +- protocol/chainlib/jsonRPC.go | 2 +- protocol/chainlib/tendermintRPC.go | 2 +- protocol/lavasession/consumer_types.go | 4 +- protocol/metrics/rpcconsumerlogs.go | 7 +- protocol/rpcconsumer/rpcconsumer_server.go | 8 +- protocol/rpcprovider/provider_listener.go | 3 +- .../rpcprovider/rewardserver/reward_server.go | 2 +- protocol/statetracker/tx_sender.go | 89 ++++++++++++------- .../pre_setups/init_evmos_only_with_node.sh | 60 +++++++++++++ 10 files changed, 138 insertions(+), 44 deletions(-) create mode 100755 scripts/pre_setups/init_evmos_only_with_node.sh diff --git a/protocol/chainlib/base_chain_parser.go b/protocol/chainlib/base_chain_parser.go index d15413c5a4..f2be77602d 100644 --- a/protocol/chainlib/base_chain_parser.go +++ b/protocol/chainlib/base_chain_parser.go @@ -218,12 +218,12 @@ func (apip *BaseChainParser) getSupportedApi(name, connectionType string) (*ApiC // Return an error if spec does not exist if !ok { - return nil, utils.LavaFormatError("api not supported", nil, utils.Attribute{Key: "name", Value: name}, utils.Attribute{Key: "connectionType", Value: connectionType}) + return nil, utils.LavaFormatInfo("api not supported", utils.Attribute{Key: "name", Value: name}, utils.Attribute{Key: "connectionType", Value: connectionType}) } // Return an error if api is disabled if !apiCont.api.Enabled { - return nil, utils.LavaFormatError("api is disabled", nil, utils.Attribute{Key: "name", Value: name}, utils.Attribute{Key: "connectionType", Value: connectionType}) + return nil, utils.LavaFormatInfo("api is disabled", utils.Attribute{Key: "name", Value: name}, utils.Attribute{Key: "connectionType", Value: connectionType}) } return &apiCont, nil @@ -376,6 +376,7 @@ func matchSpecApiByName(name, connectionType string, serverApis map[ApiKey]ApiCo utils.LavaFormatWarning("API was found on a different connection type", nil, utils.Attribute{Key: "connection_type_found", Value: foundNameOnDifferentConnectionType}, utils.Attribute{Key: "connection_type_requested", Value: connectionType}, + utils.LogAttr("requested_api", name), ) } return nil, false diff --git a/protocol/chainlib/jsonRPC.go b/protocol/chainlib/jsonRPC.go index 22d9291457..86c7dd5ec7 100644 --- a/protocol/chainlib/jsonRPC.go +++ b/protocol/chainlib/jsonRPC.go @@ -106,7 +106,7 @@ func (apip *JsonRPCChainParser) ParseMsg(url string, data []byte, connectionType // Check api is supported and save it in nodeMsg apiCont, err := apip.getSupportedApi(msg.Method, connectionType) if err != nil { - return nil, utils.LavaFormatError("getSupportedApi jsonrpc failed", err, utils.Attribute{Key: "method", Value: msg.Method}) + return nil, utils.LavaFormatInfo("getSupportedApi jsonrpc failed", utils.LogAttr("reason", err), utils.Attribute{Key: "method", Value: msg.Method}) } apiCollectionForMessage, err := apip.getApiCollection(connectionType, apiCont.collectionKey.InternalPath, apiCont.collectionKey.Addon) diff --git a/protocol/chainlib/tendermintRPC.go b/protocol/chainlib/tendermintRPC.go index 5c603c9914..005a21581d 100644 --- a/protocol/chainlib/tendermintRPC.go +++ b/protocol/chainlib/tendermintRPC.go @@ -137,7 +137,7 @@ func (apip *TendermintChainParser) ParseMsg(urlPath string, data []byte, connect // Check api is supported and save it in nodeMsg apiCont, err := apip.getSupportedApi(msg.Method, connectionType) if err != nil { - return nil, utils.LavaFormatError("getSupportedApi jsonrpc failed", err, utils.Attribute{Key: "method", Value: msg.Method}) + return nil, utils.LavaFormatInfo("getSupportedApi jsonrpc failed", utils.LogAttr("reason", err), utils.Attribute{Key: "method", Value: msg.Method}) } apiCollectionForMessage, err := apip.getApiCollection(connectionType, apiCont.collectionKey.InternalPath, apiCont.collectionKey.Addon) diff --git a/protocol/lavasession/consumer_types.go b/protocol/lavasession/consumer_types.go index 484650244e..8a9c66ba7a 100644 --- a/protocol/lavasession/consumer_types.go +++ b/protocol/lavasession/consumer_types.go @@ -371,7 +371,7 @@ func (cswp *ConsumerSessionsWithProvider) fetchEndpointConnectionFromConsumerSes client, conn, err := cswp.ConnectRawClientWithTimeout(ctx, endpoint.NetworkAddress) if err != nil { endpoint.ConnectionRefusals++ - utils.LavaFormatError("error connecting to provider", err, utils.Attribute{Key: "provider endpoint", Value: endpoint.NetworkAddress}, utils.Attribute{Key: "provider address", Value: cswp.PublicLavaAddress}, utils.Attribute{Key: "endpoint", Value: endpoint}, utils.Attribute{Key: "refusals", Value: endpoint.ConnectionRefusals}) + utils.LavaFormatInfo("error connecting to provider", utils.LogAttr("err", err), utils.Attribute{Key: "provider endpoint", Value: endpoint.NetworkAddress}, utils.Attribute{Key: "provider address", Value: cswp.PublicLavaAddress}, utils.Attribute{Key: "endpoint", Value: endpoint}, utils.Attribute{Key: "refusals", Value: endpoint.ConnectionRefusals}) if endpoint.ConnectionRefusals >= MaxConsecutiveConnectionAttempts { endpoint.Enabled = false utils.LavaFormatWarning("disabling provider endpoint for the duration of current epoch.", nil, utils.Attribute{Key: "Endpoint", Value: endpoint.NetworkAddress}, utils.Attribute{Key: "address", Value: cswp.PublicLavaAddress}) @@ -426,7 +426,7 @@ func (cswp *ConsumerSessionsWithProvider) fetchEndpointConnectionFromConsumerSes var allDisabled bool connected, endpointPtr, allDisabled = getConnectionFromConsumerSessionsWithProvider(ctx) if allDisabled { - utils.LavaFormatError("purging provider after all endpoints are disabled", nil, utils.Attribute{Key: "provider endpoints", Value: cswp.Endpoints}, utils.Attribute{Key: "provider address", Value: cswp.PublicLavaAddress}) + utils.LavaFormatInfo("purging provider after all endpoints are disabled", utils.Attribute{Key: "provider endpoints", Value: cswp.Endpoints}, utils.Attribute{Key: "provider address", Value: cswp.PublicLavaAddress}) // report provider. return connected, endpointPtr, cswp.PublicLavaAddress, AllProviderEndpointsDisabledError } diff --git a/protocol/metrics/rpcconsumerlogs.go b/protocol/metrics/rpcconsumerlogs.go index 88f50d9e90..b007df009c 100644 --- a/protocol/metrics/rpcconsumerlogs.go +++ b/protocol/metrics/rpcconsumerlogs.go @@ -21,7 +21,7 @@ import ( var ReturnMaskedErrors = "false" const ( - webSocketCloseMessage = "websocket: close 1005 (no status)" + webSocketCloseMessage = "websocket: close " RefererHeaderKey = "Referer" OriginHeaderKey = "Origin" UserAgentHeaderKey = "User-Agent" @@ -114,8 +114,9 @@ func (rpccl *RPCConsumerLogs) GetUniqueGuidResponseForError(responseError error, // We dont want to alert error monitoring for that purpses. func (rpccl *RPCConsumerLogs) AnalyzeWebSocketErrorAndWriteMessage(c *websocket.Conn, mt int, err error, msgSeed string, msg []byte, rpcType string, timeTaken time.Duration) { if err != nil { - if err.Error() == webSocketCloseMessage { - utils.LavaFormatInfo("Websocket connection closed by the user, " + err.Error()) + errMessage := err.Error() + if strings.Contains(errMessage, webSocketCloseMessage) { + utils.LavaFormatInfo("Websocket connection closed by the user, " + errMessage) return } rpccl.LogRequestAndResponse(rpcType+" ws msg", true, "ws", c.LocalAddr().String(), string(msg), "", msgSeed, timeTaken, err) diff --git a/protocol/rpcconsumer/rpcconsumer_server.go b/protocol/rpcconsumer/rpcconsumer_server.go index 9c1cdf77c1..4c2e122375 100644 --- a/protocol/rpcconsumer/rpcconsumer_server.go +++ b/protocol/rpcconsumer/rpcconsumer_server.go @@ -205,6 +205,12 @@ func (rpccs *RPCConsumerServer) SendRelay( if err != nil { return nil, err } + // temporarily disable subscriptions + isSubscription := chainlib.IsSubscription(chainMessage) + if isSubscription { + return &common.RelayResult{ProviderAddress: ""}, utils.LavaFormatError("Subscriptions are not supported at the moment", nil) + } + rpccs.HandleDirectiveHeadersForMessage(chainMessage, directiveHeaders) if _, ok := rpccs.consumerServices[chainlib.GetAddon(chainMessage)]; !ok { utils.LavaFormatError("unsupported addon usage, consumer policy does not allow", nil, @@ -344,7 +350,7 @@ func (rpccs *RPCConsumerServer) sendRelayToProvider( if isSubscription { // temporarily disable subscriptions // TODO: fix subscription and disable this case. - return &common.RelayResult{ProviderAddress: ""}, utils.LavaFormatError("Subscriptions are not supported currently", nil) + return &common.RelayResult{ProviderAddress: ""}, utils.LavaFormatError("Subscriptions are disabled currently", nil) } privKey := rpccs.privKey diff --git a/protocol/rpcprovider/provider_listener.go b/protocol/rpcprovider/provider_listener.go index 416b609f94..f9d5768d46 100644 --- a/protocol/rpcprovider/provider_listener.go +++ b/protocol/rpcprovider/provider_listener.go @@ -53,7 +53,8 @@ func NewProviderListener(ctx context.Context, networkAddress lavasession.Network // GRPC lis := chainlib.GetListenerWithRetryGrpc("tcp", networkAddress.Address) - grpcServer := grpc.NewServer() + serverReceiveMaxMessageSize := grpc.MaxRecvMsgSize(1024 * 1024 * 32) // setting receive size to 32mb instead of 4mb default + grpcServer := grpc.NewServer(serverReceiveMaxMessageSize) wrappedServer := grpcweb.WrapServer(grpcServer) handler := func(resp http.ResponseWriter, req *http.Request) { diff --git a/protocol/rpcprovider/rewardserver/reward_server.go b/protocol/rpcprovider/rewardserver/reward_server.go index 132f28a42d..4c2536023f 100644 --- a/protocol/rpcprovider/rewardserver/reward_server.go +++ b/protocol/rpcprovider/rewardserver/reward_server.go @@ -214,7 +214,7 @@ func (rws *RewardServer) sendRewardsClaim(ctx context.Context, epoch uint64) err } rws.updatePaymentRequestAttempt(rewardsToClaim, true) - utils.LavaFormatDebug("sent rewards claim", utils.Attribute{Key: "number_of_relay_sessions_sent", Value: len(rewardsToClaim)}) + utils.LavaFormatDebug("Sent rewards claim", utils.Attribute{Key: "number_of_relay_sessions_sent", Value: len(rewardsToClaim)}) } else { utils.LavaFormatDebug("no rewards to claim") } diff --git a/protocol/statetracker/tx_sender.go b/protocol/statetracker/tx_sender.go index c6154d9fb9..3d8f51631f 100644 --- a/protocol/statetracker/tx_sender.go +++ b/protocol/statetracker/tx_sender.go @@ -88,62 +88,38 @@ func (ts *TxSender) SimulateAndBroadCastTxWithRetryOnSeqMismatch(msg sdk.Msg, ch return err } - retryWithNewSequenceNumber := false success := false idx := -1 sequenceNumberParsed := 0 latestResult := common.TxResultData{} + var gasUsed uint64 for ; idx < RETRY_INCORRECT_SEQUENCE && !success; idx++ { - if retryWithNewSequenceNumber { // a retry - // if sequence number error happened it means that we already sent a tx this block. - // we need to wait a block for the tx to be approved, - // only then we can ask for a new sequence number continue and try again. - var seq uint64 - if sequenceNumberParsed != 0 { - utils.LavaFormatInfo("Sequence Number extracted from transaction error, retrying", utils.Attribute{Key: "sequence", Value: strconv.Itoa(sequenceNumberParsed)}) - seq = uint64(sequenceNumberParsed) - } else { - var err error - _, seq, err = clientCtx.AccountRetriever.GetAccountNumberSequence(clientCtx, clientCtx.GetFromAddress()) - if err != nil { - utils.LavaFormatError("failed to get correct sequence number for account, give up", err) - break // give up - } - } - txfactory = txfactory.WithSequence(seq) - utils.LavaFormatInfo("Retrying with sequence number:", utils.Attribute{Key: "SeqNum", Value: seq}) - // reset the state - sequenceNumberParsed = 0 - } - - _, gasUsed, err := tx.CalculateGas(clientCtx, txfactory, msg) + utils.LavaFormatDebug("Attempting to send relay payment transaction", utils.LogAttr("index", idx)) + txfactory, gasUsed, err = ts.simulateTxWithRetry(clientCtx, txfactory, msg) if err != nil { - return err + return utils.LavaFormatError("Failed Simulating transaction", err) } - txfactory = txfactory.WithGas(gasUsed) - // incase we got an error the tx result is basically the error - latestResult, err = ts.SendTxAndVerifyCommit(txfactory, msg) transactionResult := latestResult.RawLog if err == nil { // if we get some other code which isn't 0 then keep retrying success = true break } else if strings.Contains(transactionResult, "account sequence") { - retryWithNewSequenceNumber = true - sequenceNumberParsed, err = common.FindSequenceNumber(transactionResult) + txfactory, err = ts.getNewFactoryFromASequenceNumberError(transactionResult, txfactory, clientCtx) if err != nil { - utils.LavaFormatWarning("Failed findSequenceNumber", err, utils.Attribute{Key: "sequence", Value: transactionResult}) + return utils.LavaFormatError("Failed getting a new factory", err) } + // we got a new factory with an adjusted sequence number we should be good to try again } else if strings.Contains(transactionResult, "out of gas") { utils.LavaFormatInfo("Transaction got out of gas error, retrying next block.") - retryWithNewSequenceNumber = true // retry with out of gas issue } else if strings.Contains(transactionResult, "insufficient fees; got:") { // err := parseInsufficientFeesError(transactionResult, gasUsed) if err == nil { return utils.LavaFormatError("Failed sending transaction", nil, utils.Attribute{Key: "result", Value: latestResult}) } } + utils.LavaFormatDebug("Failed sending transaction, will retry", utils.LogAttr("Index", idx), utils.LogAttr("reason:", err), utils.LogAttr("rawLog", transactionResult)) } if !success { return utils.LavaFormatError("Failed sending transaction with all retries and giving up", nil, utils.Attribute{Key: "result", Value: latestResult}, utils.Attribute{Key: "Number Of Retries executed", Value: idx}, utils.Attribute{Key: "Parsed Sequence", Value: sequenceNumberParsed}) @@ -152,6 +128,54 @@ func (ts *TxSender) SimulateAndBroadCastTxWithRetryOnSeqMismatch(msg sdk.Msg, ch return nil } +func (ts *TxSender) getSequenceNumberFromErrorOrClient(clientCtx client.Context, errString string) (uint64, error) { + sequenceNumberParsed, err := common.FindSequenceNumber(errString) + if err != nil { + utils.LavaFormatWarning("getSequenceNumberFromErrorOrClient: Failed to findSequenceNumber, fetching from client", err) + _, seq, err := clientCtx.AccountRetriever.GetAccountNumberSequence(clientCtx, clientCtx.GetFromAddress()) + if err != nil { + return 0, utils.LavaFormatError("failed to get correct sequence number for account, give up", err) + } + return seq, nil + } + return uint64(sequenceNumberParsed), nil +} + +// this method will attempt to create a new tx factory from a sequence number error provided the expected sequence number is inside the error string +// the new factory should succeed in executing the tx +func (ts *TxSender) getNewFactoryFromASequenceNumberError(errString string, txfactory tx.Factory, clientCtx client.Context) (tx.Factory, error) { + sequence, errSequence := ts.getSequenceNumberFromErrorOrClient(clientCtx, errString) + if errSequence != nil { + return txfactory, errSequence + } + utils.LavaFormatDebug("Retrying with new sequence factory", utils.LogAttr("sequence", sequence)) + return txfactory.WithSequence(sequence), nil +} + +func (ts *TxSender) simulateTxWithRetry(clientCtx client.Context, txfactory tx.Factory, msg sdk.Msg) (tx.Factory, uint64, error) { + for retrySimulation := 0; retrySimulation < RETRY_INCORRECT_SEQUENCE; retrySimulation++ { + utils.LavaFormatDebug("Running Simulation", utils.LogAttr("idx", retrySimulation)) + _, gasUsed, err := tx.CalculateGas(clientCtx, txfactory, msg) + if err != nil { + utils.LavaFormatInfo("Simulation failed", utils.LogAttr("reason:", err)) + errString := err.Error() + if strings.Contains(errString, "account sequence") { + utils.LavaFormatInfo("Identified account sequence reason, attempting to run a new simulation with the correct sequence number") + txfactory, err = ts.getNewFactoryFromASequenceNumberError(errString, txfactory, clientCtx) + if err != nil { + return txfactory, 0, err + } + continue // if we got a new factory successfully continue to next attempt in simulation + } else { + return txfactory, 0, err + } + } + txfactory = txfactory.WithGas(gasUsed) + return txfactory, gasUsed, nil + } + return txfactory, 0, utils.LavaFormatError("Failed Calculating gas for reward transaction", nil) +} + func (ts *TxSender) SendTxAndVerifyCommit(txfactory tx.Factory, msg sdk.Msg) (parsedResult common.TxResultData, err error) { myWriter := bytes.Buffer{} clientCtx := ts.clientCtx @@ -286,6 +310,7 @@ func NewProviderTxSender(ctx context.Context, clientCtx client.Context, txFactor func (pts *ProviderTxSender) TxRelayPayment(ctx context.Context, relayRequests []*pairingtypes.RelaySession, description string, latestBlocks []*pairingtypes.LatestBlockReport) error { msg := pairingtypes.NewMsgRelayPayment(pts.clientCtx.FromAddress.String(), relayRequests, description, latestBlocks) + utils.LavaFormatDebug("Sending reward TX", utils.LogAttr("Number_of_relay_sessions_for_payment", len(relayRequests))) err := pts.SimulateAndBroadCastTxWithRetryOnSeqMismatch(msg, true) if err != nil { return utils.LavaFormatError("relay_payment - sending Tx Failed", err) diff --git a/scripts/pre_setups/init_evmos_only_with_node.sh b/scripts/pre_setups/init_evmos_only_with_node.sh new file mode 100755 index 0000000000..7731619fb5 --- /dev/null +++ b/scripts/pre_setups/init_evmos_only_with_node.sh @@ -0,0 +1,60 @@ +#!/bin/bash +__dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +source "$__dir"/../useful_commands.sh +. "${__dir}"/../vars/variables.sh + +LOGS_DIR=${__dir}/../../testutil/debugging/logs +mkdir -p $LOGS_DIR +rm $LOGS_DIR/*.log + +killall screen +screen -wipe + +echo "[Test Setup] installing all binaries" +make install-all + +echo "[Test Setup] setting up a new lava node" +screen -d -m -S node bash -c "./scripts/start_env_dev.sh" +screen -ls +echo "[Test Setup] sleeping 20 seconds for node to finish setup (if its not enough increase timeout)" +sleep 20 + +GASPRICE="0.000000001ulava" +lavad tx gov submit-legacy-proposal spec-add ./cookbook/specs/spec_add_ibc.json,./cookbook/specs/spec_add_cosmoswasm.json,./cookbook/specs/spec_add_cosmossdk.json,./cookbook/specs/spec_add_cosmossdk_45.json,./cookbook/specs/spec_add_cosmossdk_full.json,./cookbook/specs/spec_add_ethereum.json,./cookbook/specs/spec_add_cosmoshub.json,./cookbook/specs/spec_add_lava.json,./cookbook/specs/spec_add_osmosis.json,./cookbook/specs/spec_add_fantom.json,./cookbook/specs/spec_add_celo.json,./cookbook/specs/spec_add_optimism.json,./cookbook/specs/spec_add_arbitrum.json,./cookbook/specs/spec_add_starknet.json,./cookbook/specs/spec_add_aptos.json,./cookbook/specs/spec_add_juno.json,./cookbook/specs/spec_add_polygon.json,./cookbook/specs/spec_add_evmos.json,./cookbook/specs/spec_add_base.json,./cookbook/specs/spec_add_canto.json,./cookbook/specs/spec_add_sui.json,./cookbook/specs/spec_add_solana.json,./cookbook/specs/spec_add_bsc.json,./cookbook/specs/spec_add_axelar.json,./cookbook/specs/spec_add_avalanche.json,./cookbook/specs/spec_add_fvm.json -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE & +wait_next_block +wait_next_block +lavad tx gov vote 1 yes -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE +sleep 4 + +# Plans proposal +lavad tx gov submit-legacy-proposal plans-add ./cookbook/plans/default.json,./cookbook/plans/temporary-add.json -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE +wait_next_block +wait_next_block +lavad tx gov vote 2 yes -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE + +sleep 4 + +CLIENTSTAKE="500000000000ulava" +PROVIDERSTAKE="500000000000ulava" + +PROVIDER1_LISTENER="127.0.0.1:2220" + +lavad tx subscription buy DefaultPlan $(lavad keys show user1 -a) -y --from user1 --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE +wait_next_block +lavad tx pairing stake-provider "EVMOS" $PROVIDERSTAKE "$PROVIDER1_LISTENER,1" 1 -y --from servicer1 --provider-moniker "dummyMoniker" --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE + +sleep_until_next_epoch + +screen -d -m -S provider1 bash -c "source ~/.bashrc; lavap rpcprovider \ +$PROVIDER1_LISTENER EVMOS rest '$EVMOS_REST' \ +$PROVIDER1_LISTENER EVMOS tendermintrpc '$EVMOS_RPC,$EVMOS_RPC' \ +$PROVIDER1_LISTENER EVMOS grpc '$EVMOS_GRPC' \ +$PROVIDER1_LISTENER EVMOS jsonrpc '$EVMOS_JRPC' \ +$EXTRA_PROVIDER_FLAGS --geolocation 1 --log_level debug --from servicer1 --chain-id lava --metrics-listen-address ":7776" 2>&1 | tee $LOGS_DIR/PROVIDER1.log" && sleep 0.25 + +screen -d -m -S consumers bash -c "source ~/.bashrc; lavap rpcconsumer \ +127.0.0.1:3360 EVMOS rest 127.0.0.1:3361 EVMOS tendermintrpc 127.0.0.1:3362 EVMOS grpc 127.0.0.1:3363 EVMOS jsonrpc \ +$EXTRA_PORTAL_FLAGS --geolocation 1 --log_level debug --from user1 --chain-id lava --allow-insecure-provider-dialing --metrics-listen-address ":7779" 2>&1 | tee $LOGS_DIR/CONSUMERS.log" && sleep 0.25 + +echo "--- setting up screens done ---" +screen -ls \ No newline at end of file From f6c9d5fb9752d271e44c1fa32bcedc9012131188 Mon Sep 17 00:00:00 2001 From: Omer <100387053+omerlavanet@users.noreply.github.com> Date: Thu, 14 Dec 2023 12:03:38 +0200 Subject: [PATCH 71/85] PRT-add-health-checker (#1036) * WIP health command * finished health data gathering * added alerts to health * revert upgrading go version * revert * adapt to go 1.20 * added suppression system * lint * WIP alert attributes for monitoring and suppression * added suppression support, WIP testing and configurability * fix spec raw call to spec expanded * added suppression count configuration * added health example * added latest block metric on all checks * added unhealthy as 0 * fix missing logs issues * fix panic in state tracker when the node is unavailable * added fixes and apiInterface data * added the autogenerating file to ignore * prettify errors, improve suppression by attribute * verified working alert mechanism * more sleep to health test * better error handling * fix resource exhaustion on context done in grpc connector * lint --- .gitignore | 2 +- cmd/lavap/main.go | 2 + config/health_examples/health_example.yml | 31 ++ config/health_examples/health_template.yml | 29 ++ protocol/chainlib/chainproxy/connector.go | 16 +- protocol/chainlib/grpc.go | 6 + protocol/lavaprotocol/errors.go | 2 + protocol/metrics/health_metrics.go | 107 ++++ protocol/monitoring/alerting.go | 483 +++++++++++++++++ protocol/monitoring/health.go | 573 +++++++++++++++++++++ protocol/monitoring/health_cmd.go | 226 ++++++++ protocol/monitoring/health_results.go | 171 ++++++ protocol/rpcprovider/cors_test.go | 8 +- protocol/rpcprovider/provider_listener.go | 9 +- protocol/rpcprovider/rpcprovider.go | 2 +- protocol/rpcprovider/testing.go | 4 +- protocol/statetracker/state_tracker.go | 14 +- scripts/init_chain_commands.sh | 5 + scripts/init_install.sh | 4 +- scripts/useful_commands.sh | 41 +- utils/lavalog.go | 112 ++-- 21 files changed, 1775 insertions(+), 72 deletions(-) create mode 100644 config/health_examples/health_example.yml create mode 100644 config/health_examples/health_template.yml create mode 100644 protocol/metrics/health_metrics.go create mode 100644 protocol/monitoring/alerting.go create mode 100644 protocol/monitoring/health.go create mode 100644 protocol/monitoring/health_cmd.go create mode 100644 protocol/monitoring/health_results.go diff --git a/.gitignore b/.gitignore index eab6fcc08e..2719be8dfd 100644 --- a/.gitignore +++ b/.gitignore @@ -88,6 +88,6 @@ ecosystem/lavajs/proto/tendermint testutil/e2e/sdk/tests/package-lock.json testutil/e2e/sdk/tests/node_modules.json - +config/health_examples/health_template_gen.yml # Yarn .yarn/ diff --git a/cmd/lavap/main.go b/cmd/lavap/main.go index da8238e3f1..f7ef58d863 100644 --- a/cmd/lavap/main.go +++ b/cmd/lavap/main.go @@ -11,6 +11,7 @@ import ( "github.com/lavanet/lava/cmd/lavad/cmd" "github.com/lavanet/lava/ecosystem/cache" "github.com/lavanet/lava/protocol/badgegenerator" + "github.com/lavanet/lava/protocol/monitoring" "github.com/lavanet/lava/protocol/rpcconsumer" "github.com/lavanet/lava/protocol/rpcprovider" "github.com/lavanet/lava/protocol/statetracker" @@ -52,6 +53,7 @@ func main() { testCmd.AddCommand(rpcconsumer.CreateTestRPCConsumerCobraCommand()) testCmd.AddCommand(rpcprovider.CreateTestRPCProviderCobraCommand()) testCmd.AddCommand(statetracker.CreateEventsCobraCommand()) + testCmd.AddCommand(monitoring.CreateHealthCobraCommand()) rootCmd.AddCommand(cache.CreateCacheCobraCommand()) if err := svrcmd.Execute(rootCmd, "", app.DefaultNodeHome); err != nil { switch e := err.(type) { diff --git a/config/health_examples/health_example.yml b/config/health_examples/health_example.yml new file mode 100644 index 0000000000..0a8be9ad67 --- /dev/null +++ b/config/health_examples/health_example.yml @@ -0,0 +1,31 @@ +max-provider-latency: 150ms +subscription-days-left-alert: 10 +interval: 5m +allowed_time_lag: 30s +query-retries: 5 +alert-webhook-url: +identifier: health_example +cu-percent-threshold: 0.2 +alert-suppression-interval: 6h +disable-alert-suppression: false +suppression-alert-count-threshold: 3 +metrics-listen-address: ":7776" +disable-alert-logging: false +subscription_addresses: + - lava@... + - lava@... +provider_addresses: + - lava@... + - lava@... + - lava@... +consumer_endpoints: + - chain-id: ETH1 + api-interface: jsonrpc + network-address: 127.0.0.1:3333 +reference_endpoints: + - chain-id: ETH1 + api-interface: jsonrpc + network-address: public-rpc-1 + - chain-id: ETH1 + api-interface: jsonrpc + network-address: public-rpc-2 \ No newline at end of file diff --git a/config/health_examples/health_template.yml b/config/health_examples/health_template.yml new file mode 100644 index 0000000000..7c5e12ba03 --- /dev/null +++ b/config/health_examples/health_template.yml @@ -0,0 +1,29 @@ +max-provider-latency: 150ms +subscription-days-left-alert: 10 +interval: 5s +allowed_time_lag: 30s +query-retries: 5 +identifier: health_example +cu-percent-threshold: 0.2 +alert-suppression-interval: 60s +disable-alert-suppression: false +suppression-alert-count-threshold: 2 +metrics-listen-address: ":7776" +disable-alert-logging: false +allow-insecure-provider-dialing: true +consumer_endpoints: + - chain-id: ETH1 + api-interface: jsonrpc + network-address: http://127.0.0.1:3333 + - chain-id: LAV1 + api-interface: rest + network-address: http://127.0.0.1:3360 + - chain-id: LAV1 + api-interface: tendermintrpc + network-address: http://127.0.0.1:3361 + - chain-id: LAV1 + api-interface: grpc + network-address: 127.0.0.1:3362 +#REPLACED +subscription_addresses: +provider_addresses: diff --git a/protocol/chainlib/chainproxy/connector.go b/protocol/chainlib/chainproxy/connector.go index baa08e5bd9..92ff96111b 100644 --- a/protocol/chainlib/chainproxy/connector.go +++ b/protocol/chainlib/chainproxy/connector.go @@ -132,16 +132,17 @@ func (connector *Connector) connectorLoop(ctx context.Context) { } func (connector *Connector) Close() { - for { + for i := 0; ; i++ { connector.lock.Lock() - log.Println("Connector closing", len(connector.freeClients)) for i := 0; i < len(connector.freeClients); i++ { connector.freeClients[i].Close() } connector.freeClients = []*rpcclient.Client{} if connector.usedClients > 0 { - log.Println("Connector closing, waiting for in use clients", connector.usedClients) + if i > 10 { + utils.LavaFormatError("stuck while closing connector", nil, utils.LogAttr("freeClients", connector.freeClients), utils.LogAttr("usedClients", connector.usedClients)) + } connector.lock.Unlock() time.Sleep(100 * time.Millisecond) } else { @@ -335,8 +336,8 @@ func (connector *GRPCConnector) GetRpc(ctx context.Context, block bool) (*grpc.C } ret := connector.freeClients[0] - connector.freeClients = connector.freeClients[1:] connector.usedClients++ + connector.freeClients = connector.freeClients[1:] return ret, nil } @@ -360,16 +361,17 @@ func (connector *GRPCConnector) connectorLoop(ctx context.Context) { } func (connector *GRPCConnector) Close() { - for { + for i := 0; ; i++ { connector.lock.Lock() - log.Println("Connector closing", len(connector.freeClients)) for i := 0; i < len(connector.freeClients); i++ { connector.freeClients[i].Close() } connector.freeClients = []*grpc.ClientConn{} if connector.usedClients > 0 { - log.Println("Connector closing, waiting for in use clients", connector.usedClients) + if i > 10 { + utils.LavaFormatError("stuck while closing grpc connector", nil, utils.LogAttr("freeClients", connector.freeClients), utils.LogAttr("usedClients", connector.usedClients)) + } connector.lock.Unlock() time.Sleep(100 * time.Millisecond) } else { diff --git a/protocol/chainlib/grpc.go b/protocol/chainlib/grpc.go index cfbdcbf1a9..766fb1f6d4 100644 --- a/protocol/chainlib/grpc.go +++ b/protocol/chainlib/grpc.go @@ -371,6 +371,12 @@ func newGrpcChainProxy(ctx context.Context, nodeUrl string, averageBlockTime tim if err != nil { return nil, utils.LavaFormatError("reflectionConnection Error", err) } + // this connection is kept open so it needs to be closed on teardown + go func() { + <-ctx.Done() + utils.LavaFormatInfo("tearing down reflection connection, context done") + conn.ReturnRpc(reflectionConnection) + }() err = parser.(*GrpcChainParser).setupForProvider(reflectionConnection) if err != nil { diff --git a/protocol/lavaprotocol/errors.go b/protocol/lavaprotocol/errors.go index 517e31bad6..aedb32ec0e 100644 --- a/protocol/lavaprotocol/errors.go +++ b/protocol/lavaprotocol/errors.go @@ -9,4 +9,6 @@ var ( ProviderFinzalizationDataAccountabilityError = sdkerrors.New("ProviderFinzalizationDataAccountability Error", 3366, "provider returned invalid finalization data, with accountability") HashesConsunsusError = sdkerrors.New("HashesConsunsus Error", 3367, "identified finalized responses with conflicting hashes, from two providers") ConsistencyError = sdkerrors.New("Consistency Error", 3368, "does not meet consistency requirements") + UnhandledRelayReceiverError = sdkerrors.New("UnhandledRelayReceiver Error", 3369, "provider does not handle requested api interface and spec") + DisabledRelayReceiverError = sdkerrors.New("DisabledRelayReceiverError Error", 3370, "provider does not pass verification and disabled this interface and spec") ) diff --git a/protocol/metrics/health_metrics.go b/protocol/metrics/health_metrics.go new file mode 100644 index 0000000000..159eef9f88 --- /dev/null +++ b/protocol/metrics/health_metrics.go @@ -0,0 +1,107 @@ +package metrics + +import ( + "net/http" + + "github.com/lavanet/lava/utils" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promhttp" +) + +type HealthMetrics struct { + failedRuns *prometheus.CounterVec + successfulRuns *prometheus.CounterVec + failureAlerts *prometheus.GaugeVec + healthyChecks *prometheus.GaugeVec + unhealthyChecks *prometheus.GaugeVec + latestBlocks *prometheus.GaugeVec +} + +func NewHealthMetrics(networkAddress string) *HealthMetrics { + if networkAddress == DisabledFlagOption { + utils.LavaFormatWarning("prometheus endpoint inactive, option is disabled", nil) + return nil + } + + latestBlocks := prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "lava_health_latest_blocks", + Help: "The latest blocks queried on all checks", + }, []string{"identifier", "entity"}) + + failureAlerts := prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "lava_health_failure_alerts", + Help: "The current amount of active alerts", + }, []string{"identifier"}) + + healthyChecks := prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "lava_healthy_entities", + Help: "The current amount of healthy checks", + }, []string{"identifier"}) + + unhealthyChecks := prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "lava_unhealthy_entities", + Help: "The current amount of healthy checks", + }, []string{"identifier"}) + + failedRuns := prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "lava_health_failed_runs", + Help: "The total of runs failed", + }, []string{"identifier"}) + + successfulRuns := prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "lava_health_successful_runs", + Help: "The total of runs succeeded", + }, []string{"identifier"}) + // Register the metrics with the Prometheus registry. + prometheus.MustRegister(failedRuns) + prometheus.MustRegister(successfulRuns) + prometheus.MustRegister(failureAlerts) + prometheus.MustRegister(healthyChecks) + prometheus.MustRegister(unhealthyChecks) + prometheus.MustRegister(latestBlocks) + http.Handle("/metrics", promhttp.Handler()) + go func() { + utils.LavaFormatInfo("prometheus endpoint listening", utils.Attribute{Key: "Listen Address", Value: networkAddress}) + http.ListenAndServe(networkAddress, nil) + }() + return &HealthMetrics{ + failedRuns: failedRuns, + successfulRuns: successfulRuns, + failureAlerts: failureAlerts, + healthyChecks: healthyChecks, + unhealthyChecks: unhealthyChecks, + latestBlocks: latestBlocks, + } +} + +func (pme *HealthMetrics) SetFailedRun(label string) { + if pme == nil { + return + } + pme.failedRuns.WithLabelValues(label).Add(1) +} + +func (pme *HealthMetrics) SetSuccess(label string) { + if pme == nil { + return + } + pme.successfulRuns.WithLabelValues(label).Add(1) +} + +func (pme *HealthMetrics) SetLatestBlockData(label string, data map[string]uint64) { + if pme == nil { + return + } + for entity, value := range data { + pme.latestBlocks.WithLabelValues(label, entity).Set(float64(value)) + } +} + +func (pme *HealthMetrics) SetAlertResults(label string, fails uint64, unhealthy uint64, healthy uint64) { + if pme == nil { + return + } + pme.failureAlerts.WithLabelValues(label).Set(float64(fails)) + pme.unhealthyChecks.WithLabelValues(label).Set(float64(unhealthy)) + pme.healthyChecks.WithLabelValues(label).Set(float64(healthy)) +} diff --git a/protocol/monitoring/alerting.go b/protocol/monitoring/alerting.go new file mode 100644 index 0000000000..ad8502a60d --- /dev/null +++ b/protocol/monitoring/alerting.go @@ -0,0 +1,483 @@ +package monitoring + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "strconv" + "strings" + "time" + + "github.com/dgraph-io/ristretto" + "github.com/lavanet/lava/utils" + "github.com/lavanet/lava/utils/sigs" +) + +const ( + CacheMaxCost = 10 * 1024 // 10K cost + CacheNumCounters = 100000 // expect 10K items + OKString = "OK" + FrozenProviderAttribute = "frozen_provider_alert" + SubscriptionAlertAttribute = "subscription_limit_alert" + UnhealthyProviderAttribute = "unhealthy_provider_alert" + UnhealthyConsumerAttribute = "unhealthy_consumer_alert" + ProviderBlockGapAttribute = "provider_block_gap_alert" + ConsumerBlockGapAttribute = "consumer_block_gap_alert" + ProviderLatencyAttribute = "provider_latency_alert" + red = "#ff0000" + lessRed = "#990000" + green = "#00ff00" + UsagePercentageAlert = "percentage of cu too low" + LeftTimeAlert = "left subscription time is too low" + MonthDuration = 30 * 24 * time.Hour + defaultSameAlertInterval = 6 * time.Hour +) + +type AlertingOptions struct { + Url string // where to send the alerts + Logging bool // wether to log alerts to stdout + Identifier string // a unique identifier added to all alerts + SubscriptionCUPercentageAlert float64 + SubscriptionLeftTimeAlert time.Duration + AllowedTimeGapVsReference time.Duration + MaxProviderLatency time.Duration + SameAlertInterval time.Duration + DisableAlertSuppression bool + SuppressionCounterThreshold uint64 +} + +type AlertAttribute struct { + entity LavaEntity + data string +} + +type AlertEntry struct { + alertType string + entity LavaEntity +} + +type AlertCount struct { + active uint64 + recovery uint64 +} + +type Alerting struct { + url string + logging bool + identifier string + subscriptionCUPercentageAlert float64 + subscriptionLeftTimeAlert time.Duration + allowedTimeGapVsReference time.Duration + maxProviderLatency time.Duration + sameAlertInterval time.Duration + AlertsCache *ristretto.Cache + activeAlerts map[AlertEntry]AlertCount // count how many occurrences of an alert + healthy map[LavaEntity]struct{} + unhealthy map[LavaEntity]struct{} + currentAlerts map[AlertEntry]struct{} + suppressionCounterThreshold uint64 + suppressedAlerts uint64 // monitoring + payload map[string]interface{} + colorToggle bool +} + +func NewAlerting(options AlertingOptions) *Alerting { + al := &Alerting{ + activeAlerts: map[AlertEntry]AlertCount{}, + healthy: map[LavaEntity]struct{}{}, + unhealthy: map[LavaEntity]struct{}{}, + currentAlerts: map[AlertEntry]struct{}{}, + payload: map[string]interface{}{}, + } + if options.Url != "" { + al.url = options.Url + } + if options.Identifier != "" { + al.identifier = options.Identifier + } + if options.Logging { + al.logging = true + } + al.subscriptionCUPercentageAlert = options.SubscriptionCUPercentageAlert + al.subscriptionLeftTimeAlert = options.SubscriptionLeftTimeAlert + al.allowedTimeGapVsReference = options.AllowedTimeGapVsReference + al.maxProviderLatency = options.MaxProviderLatency + al.suppressionCounterThreshold = options.SuppressionCounterThreshold + if options.DisableAlertSuppression { + al.sameAlertInterval = 0 + al.suppressionCounterThreshold = 0 + } else { + if options.SameAlertInterval != 0 { + al.sameAlertInterval = options.SameAlertInterval + } else { + al.sameAlertInterval = defaultSameAlertInterval + } + cache, err := ristretto.NewCache(&ristretto.Config{NumCounters: CacheNumCounters, MaxCost: CacheMaxCost, BufferItems: 64, IgnoreInternalCost: true}) + if err != nil { + utils.LavaFormatFatal("failed setting up cache for queries", err) + } + al.AlertsCache = cache + } + return al +} + +func (al *Alerting) FilterOccurenceSuppresedAlerts(alert string, attributes []AlertAttribute) (filteredAttributes []AlertAttribute) { + if al.suppressionCounterThreshold <= 1 { + return attributes + } + for _, attr := range attributes { + alertEntity := AlertEntry{ + alertType: alert, + entity: attr.entity, + } + alertCount := al.activeAlerts[alertEntity] + alertCount.active++ + al.currentAlerts[alertEntity] = struct{}{} // so we can clear keys that weren't changed + + al.activeAlerts[alertEntity] = alertCount + if alertCount.active >= al.suppressionCounterThreshold { + filteredAttributes = append(filteredAttributes, attr) + continue + } + al.suppressedAlerts++ + } + return filteredAttributes +} + +// func (al *Alerting) SendAlert(alert string, attrs []utils.Attribute) { +func (al *Alerting) SendAlert(alert string, attributes []AlertAttribute) { + // check for occurrence suppression + attributes = al.FilterOccurenceSuppresedAlerts(alert, attributes) + if len(attributes) == 0 { + return + } + attrs := al.FilterTimeSuppresedAlerts(attributes, alert) + if len(attrs) == 0 { + return + } + + if al.url != "" { + go al.AppendUrlAlert(alert, attrs) + } + if al.logging { + if al.identifier != "" { + alert = alert + " - " + al.identifier + } + utils.LavaFormatError(alert, nil, attrs...) + } +} + +func (al *Alerting) FilterTimeSuppresedAlerts(attributes []AlertAttribute, alert string) []utils.Attribute { + attrs := []utils.Attribute{} + for _, attr := range attributes { + if al.sameAlertInterval > 0 && al.AlertsCache != nil { + // we only hash by keys, values can differ (like blocks or error) + hashStr := string(sigs.HashMsg([]byte(fmt.Sprintf("%s %s", alert, attr.entity.String())))) + storedVal, found := al.AlertsCache.Get(hashStr) + if found { + // was already in the cache + storedTime, ok := storedVal.(time.Time) + if !ok { + utils.LavaFormatFatal("invalid usage of cache", nil, utils.Attribute{Key: "storedVal", Value: storedVal}) + } + if !time.Now().After(storedTime.Add(al.sameAlertInterval)) { + // filter this alert + al.suppressedAlerts++ + continue + } + } + al.AlertsCache.SetWithTTL(hashStr, time.Now(), 1, al.sameAlertInterval) + } + attrs = append(attrs, utils.LogAttr(attr.entity.String(), attr.data)) + } + return attrs +} + +func (al *Alerting) SendRecoveryAlerts(alertEntries []AlertEntry) { + alertTypeAttributes := map[string][]utils.Attribute{} + for _, alertEntry := range alertEntries { + count, ok := al.activeAlerts[alertEntry] + if !ok { + continue + } + if count.active < al.suppressionCounterThreshold { + continue + } + attrs, ok := alertTypeAttributes[alertEntry.alertType] + if !ok { + attrs = []utils.Attribute{} + } + attrs = append(attrs, utils.Attribute{ + Key: alertEntry.entity.String(), + Value: OKString, + }) + alertTypeAttributes[alertEntry.alertType] = attrs + } + if len(alertTypeAttributes) == 0 { + return + } + for alertType, attrs := range alertTypeAttributes { + alertType = "recovered - " + alertType + if al.url != "" { + al.AppendUrlAlert(alertType, attrs) + } + if al.logging { + utils.LavaFormatInfo(alertType, attrs...) + } + } +} + +func (al *Alerting) SendAppendedAlerts() error { + if len(al.payload) == 0 { + return nil + } + if al.identifier != "" { + al.payload["text"] = al.identifier + al.payload["content"] = al.identifier + } + payloadBytes, err := json.Marshal(al.payload) + if err != nil { + return err + } + req, err := http.NewRequest("POST", al.url, bytes.NewBuffer(payloadBytes)) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + + // Make the HTTP request + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + return nil +} + +func (al *Alerting) AppendUrlAlert(alert string, attrs []utils.Attribute) { + attachments := []map[string]interface{}{} + if attachmentsProp, ok := al.payload["attachments"]; ok { + attachmentsCasted, ok := attachmentsProp.([]map[string]interface{}) + if ok { + attachments = attachmentsCasted + } + } + fields := []map[string]interface{}{} + colorToSet := green + for _, attr := range attrs { + if utils.StrValue(attr.Value) != OKString { + colorToSet = red + if al.colorToggle { + al.colorToggle = !al.colorToggle + colorToSet = lessRed + } + } + field := map[string]interface{}{ + "title": attr.Key, + "text": attr.Key, + "value": attr.Value, + "short": false, + "inline": false, + } + fields = append(fields, field) + } + attachment := map[string]interface{}{ + "text": alert, + "title": alert, + "color": colorToSet, + "fields": fields, + } + attachments = append(attachments, attachment) + al.payload["attachments"] = attachments + al.payload["embeds"] = attachments +} + +func (al *Alerting) SendFrozenProviders(frozenProviders map[LavaEntity]struct{}) { + providers := map[string][]string{} + attrs := []AlertAttribute{} + for frozen := range frozenProviders { + attrs = append(attrs, AlertAttribute{entity: frozen, data: "frozen"}) + providers[frozen.Address] = append(providers[frozen.Address], frozen.SpecId) + } + if len(attrs) > 0 { + al.SendAlert(FrozenProviderAttribute, attrs) + } +} + +func (al *Alerting) UnhealthyProviders(unhealthy map[LavaEntity]string) { + attrs := []AlertAttribute{} + for provider, errSt := range unhealthy { + attrs = append(attrs, AlertAttribute{entity: provider, data: errSt}) + } + if len(attrs) > 0 { + al.SendAlert(UnhealthyProviderAttribute, attrs) + } +} + +func (al *Alerting) ShouldAlertSubscription(data SubscriptionData) (reason string, alert bool) { + reasons := []string{} + if al.subscriptionCUPercentageAlert > 0 { + if data.UsagePercentageLeftThisMonth < al.subscriptionCUPercentageAlert { + alert = true + reasons = append(reasons, UsagePercentageAlert+" "+strconv.FormatFloat(data.UsagePercentageLeftThisMonth, 'f', 2, 64)+"/"+strconv.FormatFloat(al.subscriptionCUPercentageAlert, 'f', 2, 64)) + } + } + if al.subscriptionLeftTimeAlert != 0 { + timeLeft := data.DurationLeft + MonthDuration*time.Duration(data.FullMonthsLeft) + if timeLeft < al.subscriptionLeftTimeAlert { + alert = true + reasons = append(reasons, LeftTimeAlert+" "+timeLeft.String()+"/"+al.subscriptionLeftTimeAlert.String()) + } + } + reason = strings.Join(reasons, " & ") + return reason, alert +} + +func (al *Alerting) CheckSubscriptionData(subs map[string]SubscriptionData) { + attrs := []AlertAttribute{} + for subscriptionAddr, data := range subs { + if reason, alert := al.ShouldAlertSubscription(data); alert { + attrs = append(attrs, AlertAttribute{entity: LavaEntity{Address: subscriptionAddr, SpecId: ""}, data: reason}) + } + } + if len(attrs) > 0 { + al.SendAlert(SubscriptionAlertAttribute, attrs) + } +} + +func (al *Alerting) ProvidersAlerts(healthResults *HealthResults) { + attrs := []AlertAttribute{} + attrsForLatency := []AlertAttribute{} + for provider, data := range healthResults.ProviderData { + specId := provider.SpecId + if al.allowedTimeGapVsReference > 0 { + latestBlock := healthResults.LatestBlocks[specId] + if latestBlock > data.block { + gap := latestBlock - data.block + timeGap := time.Duration(gap*healthResults.Specs[specId].AverageBlockTime) * time.Millisecond + if timeGap > al.allowedTimeGapVsReference { + attrs = append(attrs, AlertAttribute{entity: provider, data: fmt.Sprintf("block gap: %s/%s", utils.StrValue(data.block), utils.StrValue(latestBlock))}) + } + } + } + if al.maxProviderLatency > 0 { + if data.latency > al.maxProviderLatency { + attrsForLatency = append(attrsForLatency, AlertAttribute{entity: provider, data: fmt.Sprintf("latency: %s/%s", utils.StrValue(data.latency), utils.StrValue(al.maxProviderLatency))}) + } + } + } + if len(attrs) > 0 { + al.SendAlert(ProviderBlockGapAttribute, attrs) + } + if len(attrsForLatency) > 0 { + al.SendAlert(ProviderLatencyAttribute, attrsForLatency) + } +} + +func (al *Alerting) ConsumerAlerts(healthResults *HealthResults) { + attrs := []AlertAttribute{} + for consumer, consumerBlock := range healthResults.ConsumerBlocks { + specId := consumer.SpecId + if consumerBlock == 0 { + // skip these, they are handled in unhealthyConsumers + continue + } else if al.allowedTimeGapVsReference > 0 { + latestBlock := healthResults.LatestBlocks[specId] + if latestBlock > consumerBlock { + gap := latestBlock - consumerBlock + timeGap := time.Duration(gap*healthResults.Specs[specId].AverageBlockTime) * time.Millisecond + if timeGap > al.allowedTimeGapVsReference { + attrs = append(attrs, AlertAttribute{entity: consumer, data: fmt.Sprintf("block gap: %s/%s", utils.StrValue(consumerBlock), utils.StrValue(latestBlock))}) + } + } + } + } + if len(attrs) > 0 { + al.SendAlert(ConsumerBlockGapAttribute, attrs) + } + attrsUnhealthy := []AlertAttribute{} + for consumer, errSt := range healthResults.UnhealthyConsumers { + attrsUnhealthy = append(attrsUnhealthy, AlertAttribute{entity: consumer, data: errSt}) + } + if len(attrsUnhealthy) > 0 { + al.SendAlert(UnhealthyConsumerAttribute, attrsUnhealthy) + } +} + +func (al *Alerting) CheckHealthResults(healthResults *HealthResults) { + healthResults.Lock.RLock() + defer healthResults.Lock.RUnlock() + al.payload = map[string]interface{}{} + suppressed := al.suppressedAlerts + // reset healthy + al.currentAlerts = map[AlertEntry]struct{}{} + + // handle frozen providers + if len(healthResults.FrozenProviders) > 0 { + al.SendFrozenProviders(healthResults.FrozenProviders) + } + + // handle subscriptions + al.CheckSubscriptionData(healthResults.SubscriptionsData) + + // unhealthy providers + if len(healthResults.UnhealthyProviders) > 0 { + al.UnhealthyProviders(healthResults.UnhealthyProviders) + } + + // check providers latestBlock vs reference + al.ProvidersAlerts(healthResults) + + // check consumers vs reference + al.ConsumerAlerts(healthResults) + + // delete alerts that are not active, reset recovery for those that are + keysToDelete := []AlertEntry{} + for alertEntry := range al.activeAlerts { + _, ok := al.currentAlerts[alertEntry] + if !ok { + // this entry wasn't alerted currently therefore we can shut it off + count := al.activeAlerts[alertEntry] + count.recovery++ // increase recovery + al.activeAlerts[alertEntry] = count + if count.recovery >= al.suppressionCounterThreshold { + keysToDelete = append(keysToDelete, alertEntry) + } + } else { + count := al.activeAlerts[alertEntry] + count.recovery = 0 + al.activeAlerts[alertEntry] = count + } + } + al.SendRecoveryAlerts(keysToDelete) + for _, keyToDelete := range keysToDelete { + delete(al.activeAlerts, keyToDelete) + } + al.healthy = map[LavaEntity]struct{}{} + al.unhealthy = map[LavaEntity]struct{}{} + + for entity := range al.currentAlerts { + al.unhealthy[entity.entity] = struct{}{} + } + + allEntities := healthResults.GetAllEntities() + for entity := range allEntities { + _, ok := al.unhealthy[entity] + if !ok { + // not unhealthy sets healthy + al.healthy[entity] = struct{}{} + } + } + if len(al.currentAlerts) == 0 { + utils.LavaFormatInfo("[+] healthy - no new alerts") + } else { + utils.LavaFormatInfo("[-] unhealthy", utils.LogAttr("count", uint64(len(al.unhealthy))), utils.LogAttr("currently suppressed", al.suppressedAlerts-suppressed)) + } + al.SendAppendedAlerts() +} + +func (al *Alerting) ActiveAlerts() (alerts uint64, unhealthy uint64, healthy uint64) { + return uint64(len(al.activeAlerts)), uint64(len(al.unhealthy)), uint64(len(al.healthy)) +} diff --git a/protocol/monitoring/health.go b/protocol/monitoring/health.go new file mode 100644 index 0000000000..c119e63c0d --- /dev/null +++ b/protocol/monitoring/health.go @@ -0,0 +1,573 @@ +package monitoring + +import ( + "context" + "fmt" + "strings" + "sync" + "time" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/gogo/status" + lvutil "github.com/lavanet/lava/ecosystem/lavavisor/pkg/util" + "github.com/lavanet/lava/protocol/chainlib" + "github.com/lavanet/lava/protocol/common" + "github.com/lavanet/lava/protocol/lavaprotocol" + "github.com/lavanet/lava/protocol/lavasession" + "github.com/lavanet/lava/protocol/rpcprovider" + "github.com/lavanet/lava/utils" + "github.com/lavanet/lava/utils/rand" + dualstakingtypes "github.com/lavanet/lava/x/dualstaking/types" + epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" + pairingtypes "github.com/lavanet/lava/x/pairing/types" + protocoltypes "github.com/lavanet/lava/x/protocol/types" + spectypes "github.com/lavanet/lava/x/spec/types" + subscriptiontypes "github.com/lavanet/lava/x/subscription/types" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" +) + +var QueryRetries = uint64(3) + +const ( + BasicQueryRetries = 3 + QuerySleepTime = 100 * time.Millisecond + NiceOutputLength = 40 +) + +type LavaEntity struct { + Address string + SpecId string + ApiInterface string +} + +func (e *LavaEntity) String() string { + if e.SpecId == "" && e.ApiInterface == "" { + return e.Address + } + return fmt.Sprintf("%s | %s | %s", e.Address, e.SpecId, e.ApiInterface) +} + +type ReplyData struct { + block int64 + latency time.Duration +} + +type SubscriptionData struct { + FullMonthsLeft uint64 + UsagePercentageLeftThisMonth float64 + DurationLeft time.Duration +} + +func RunHealth(ctx context.Context, + clientCtx client.Context, + subscriptionAddresses []string, + providerAddresses []string, + consumerEndpoints []*lavasession.RPCEndpoint, + referenceEndpoints []*lavasession.RPCEndpoint, + prometheusListenAddr string, +) (*HealthResults, error) { + specQuerier := spectypes.NewQueryClient(clientCtx) + healthResults := &HealthResults{ + LatestBlocks: map[string]int64{}, + ProviderData: map[LavaEntity]ReplyData{}, + ConsumerBlocks: map[LavaEntity]int64{}, + SubscriptionsData: map[string]SubscriptionData{}, + FrozenProviders: map[LavaEntity]struct{}{}, + UnhealthyProviders: map[LavaEntity]string{}, + UnhealthyConsumers: map[LavaEntity]string{}, + Specs: map[string]*spectypes.Spec{}, + } + currentBlock := int64(0) + for i := 0; i < BasicQueryRetries; i++ { + resultStatus, err := clientCtx.Client.Status(ctx) + if err == nil { + currentBlock = resultStatus.SyncInfo.LatestBlockHeight + break + } + time.Sleep(QuerySleepTime) + } + if currentBlock == 0 { + return nil, utils.LavaFormatError("failed querying lava chain for block", nil) + } + var err error + var allChains *spectypes.QueryShowAllChainsResponse + for i := 0; i < BasicQueryRetries; i++ { + allChains, err = specQuerier.ShowAllChains(ctx, &spectypes.QueryShowAllChainsRequest{}) + if err == nil { + break + } + time.Sleep(QuerySleepTime) + } + if err != nil { + return nil, err + } + chainIdToApiInterfaces := map[string][]string{} + for _, chainInfo := range allChains.ChainInfoList { + if len(chainInfo.EnabledApiInterfaces) > 0 { + chainIdToApiInterfaces[chainInfo.ChainID] = chainInfo.EnabledApiInterfaces + } + } + errCh := make(chan error, 1) + + // get a list of all necessary specs for the test + dualStakingQuerier := dualstakingtypes.NewQueryClient(clientCtx) + var wgspecs sync.WaitGroup + wgspecs.Add(len(providerAddresses)) + + processProvider := func(providerAddress string) { + defer wgspecs.Done() + var err error + for i := 0; i < BasicQueryRetries; i++ { + var response *dualstakingtypes.QueryDelegatorProvidersResponse + queryCtx, cancel := context.WithTimeout(ctx, 2*time.Second) + response, err = dualStakingQuerier.DelegatorProviders(queryCtx, &dualstakingtypes.QueryDelegatorProvidersRequest{ + Delegator: providerAddress, + WithPending: false, + }) + cancel() + if err != nil || response == nil { + time.Sleep(QuerySleepTime) + continue + } + delegations := response.GetDelegations() + for _, delegation := range delegations { + if delegation.Provider == providerAddress { + healthResults.setSpec(&spectypes.Spec{Index: delegation.ChainID}) + for _, apiInterface := range chainIdToApiInterfaces[delegation.ChainID] { + healthResults.SetProviderData(LavaEntity{ + Address: providerAddress, + SpecId: delegation.ChainID, + ApiInterface: apiInterface, + }, ReplyData{}) + } + } + } + return + } + if err != nil { + select { + case errCh <- err: + default: + } + } + } + + for _, providerAddress := range providerAddresses { + go processProvider(providerAddress) + } + + for _, consumerEndpoint := range consumerEndpoints { + healthResults.setSpec(&spectypes.Spec{Index: consumerEndpoint.ChainID}) + } + + for _, referenceEndpoint := range referenceEndpoints { + healthResults.setSpec(&spectypes.Spec{Index: referenceEndpoint.ChainID}) + } + + wgspecs.Wait() + if len(errCh) > 0 { + return nil, utils.LavaFormatWarning("[-] process providers specs", <-errCh) + } + // add specs + specs := healthResults.getSpecs() + processSpec := func(specId string) { + defer wgspecs.Done() + var err error + for i := 0; i < BasicQueryRetries; i++ { + var specResp *spectypes.QueryGetSpecResponse + queryCtx, cancel := context.WithTimeout(ctx, 2*time.Second) + specResp, err = specQuerier.Spec(queryCtx, &spectypes.QueryGetSpecRequest{ + ChainID: specId, + }) + cancel() + if err != nil || specResp == nil { + time.Sleep(QuerySleepTime) + continue + } + spec := specResp.GetSpec() + healthResults.setSpec(&spec) + return + } + select { + case errCh <- err: + default: + } + } + wgspecs.Add(len(specs)) + // populate the specs + utils.LavaFormatDebug("[+] populating specs") + for specId := range specs { + go processSpec(specId) + } + + wgspecs.Wait() + if len(errCh) > 0 { + return nil, utils.LavaFormatWarning("[-] populating specs", <-errCh) + } + pairingQuerier := pairingtypes.NewQueryClient(clientCtx) + utils.LavaFormatDebug("[+] getting provider entries") + stakeEntries := map[LavaEntity]epochstoragetypes.StakeEntry{} + var mutex sync.Mutex // Mutex to protect concurrent access to stakeEntries + wgspecs.Add(len(healthResults.getSpecs())) + processSpecProviders := func(specId string) { + defer wgspecs.Done() + var err error + for i := 0; i < BasicQueryRetries; i++ { + var response *pairingtypes.QueryProvidersResponse + queryCtx, cancel := context.WithTimeout(ctx, 2*time.Second) + response, err = pairingQuerier.Providers(queryCtx, &pairingtypes.QueryProvidersRequest{ + ChainID: specId, + ShowFrozen: true, + }) + cancel() + if err != nil || response == nil { + time.Sleep(QuerySleepTime) + continue + } + + for _, providerEntry := range response.StakeEntry { + providerKey := LavaEntity{ + Address: providerEntry.Address, + SpecId: specId, + } + apiInterfaces := chainIdToApiInterfaces[specId] + // just to check if this is a provider we need to check we need one of the apiInterfaces + if len(apiInterfaces) == 0 { + utils.LavaFormatError("invalid state len(apiInterfaces) == 0", nil, utils.LogAttr("specId", specId)) + // shouldn't happen + continue + } + lookupKey := LavaEntity{ + Address: providerEntry.Address, + SpecId: specId, + ApiInterface: apiInterfaces[0], + } + + mutex.Lock() // Lock before updating stakeEntries + if _, ok := healthResults.getProviderData(lookupKey); ok { + if providerEntry.StakeAppliedBlock > uint64(currentBlock) { + healthResults.FreezeProvider(providerKey) + } else { + stakeEntries[providerKey] = providerEntry + } + } + mutex.Unlock() + } + return + } + if err != nil { + select { + case errCh <- err: + default: + } + } + } + // get provider stake entries + for specId := range healthResults.getSpecs() { + go processSpecProviders(specId) + } + wgspecs.Wait() + if len(errCh) > 0 { + return nil, utils.LavaFormatWarning("[-] processing providers entries", <-errCh) + } + utils.LavaFormatDebug("[+] checking subscriptions") + err = checkSubscriptions(ctx, clientCtx, subscriptionAddresses, healthResults) + if err != nil { + return nil, utils.LavaFormatWarning("[-] checking subscriptions", <-errCh) + } + utils.LavaFormatDebug("[+] checking providers") + err = CheckProviders(ctx, clientCtx, healthResults, stakeEntries) + if err != nil { + return nil, utils.LavaFormatWarning("[-] checking providers health", <-errCh) + } + utils.LavaFormatDebug("[+] checking consumers") + err = CheckConsumersAndReferences(ctx, clientCtx, referenceEndpoints, consumerEndpoints, healthResults) + if err != nil { + return nil, utils.LavaFormatWarning("[-] checking consumers and references", <-errCh) + } + utils.LavaFormatDebug("health results", utils.LogAttr("dump", healthResults)) + return healthResults, nil +} + +func CheckConsumersAndReferences(ctx context.Context, + clientCtx client.Context, + referenceEndpoints []*lavasession.RPCEndpoint, + consumerEndpoints []*lavasession.RPCEndpoint, + healthResults *HealthResults, +) error { + // populate data from providers + for entry, data := range healthResults.ProviderData { + providerBlock := data.block + specId := entry.SpecId + healthResults.updateLatestBlock(specId, providerBlock) + } + errCh := make(chan error, 1) + queryEndpoint := func(endpoint *lavasession.RPCEndpoint, isReference bool) error { + chainParser, err := chainlib.NewChainParser(endpoint.ApiInterface) + if err != nil { + return err + } + spec := healthResults.getSpec(endpoint.ChainID) + if spec == nil { + return err + } + chainParser.SetSpec(*spec) + compatibleEndpoint := &lavasession.RPCProviderEndpoint{ + NetworkAddress: lavasession.NetworkAddressData{}, + ChainID: endpoint.ChainID, + ApiInterface: endpoint.ApiInterface, + Geolocation: 0, + NodeUrls: []common.NodeUrl{ + { + Url: endpoint.NetworkAddress, + }, + }, + } + var chainProxy chainlib.ChainRouter + for i := uint64(0); i <= QueryRetries; i++ { + sendCtx, cancel := context.WithTimeout(ctx, 2*time.Second) + chainProxy, err = chainlib.GetChainRouter(sendCtx, 1, compatibleEndpoint, chainParser) + cancel() + if err == nil { + break + } + } + if err != nil { + utils.LavaFormatDebug("failed creating chain proxy, continuing with others endpoints", utils.LogAttr("reference", isReference), utils.Attribute{Key: "endpoint", Value: compatibleEndpoint}) + if !isReference { + healthResults.updateConsumerError(endpoint, err) + } + } + chainFetcher := chainlib.NewChainFetcher(ctx, chainProxy, chainParser, compatibleEndpoint, nil) + var latestBlock int64 + for i := uint64(0); i <= QueryRetries; i++ { + sendCtx, cancel := context.WithTimeout(ctx, 2*time.Second) + latestBlock, err = chainFetcher.FetchLatestBlockNum(sendCtx) + cancel() + if err == nil { + break + } + } + if err != nil { + if isReference { + utils.LavaFormatDebug("failed querying latest block from reference", utils.LogAttr("endpoint", endpoint.String())) + } else { + healthResults.updateConsumerError(endpoint, err) + } + return nil + } + if !isReference { + healthResults.updateConsumer(endpoint, latestBlock) + } + healthResults.updateLatestBlock(endpoint.ChainID, latestBlock) + return nil + } + + // populate data from references + var wg sync.WaitGroup + wg.Add(len(referenceEndpoints)) + wg.Add(len(consumerEndpoints)) + for _, endpoint := range referenceEndpoints { + go func(ep *lavasession.RPCEndpoint) { + // Decrement the WaitGroup counter when the goroutine completes + defer wg.Done() + err := queryEndpoint(ep, true) + if err != nil { + select { + case errCh <- err: + default: + } + } + }(endpoint) + } + // query our consumers + for _, endpoint := range consumerEndpoints { + go func(ep *lavasession.RPCEndpoint) { + // Decrement the WaitGroup counter when the goroutine completes + defer wg.Done() + err := queryEndpoint(ep, false) + if err != nil { + select { + case errCh <- err: + default: + } + } + }(endpoint) + } + wg.Wait() + if len(errCh) > 0 { + return <-errCh + } + return nil +} + +func checkSubscriptions(ctx context.Context, clientCtx client.Context, subscriptionAddresses []string, healthResults *HealthResults) error { + subscriptionQuerier := subscriptiontypes.NewQueryClient(clientCtx) + var wg sync.WaitGroup + wg.Add(len(subscriptionAddresses)) + errCh := make(chan error, 1) + for _, subscriptionAddr := range subscriptionAddresses { + go func(addr string) { + defer wg.Done() + var err error + for i := 0; i < BasicQueryRetries; i++ { + var response *subscriptiontypes.QueryCurrentResponse + queryCtx, cancel := context.WithTimeout(ctx, 2*time.Second) + response, err = subscriptionQuerier.Current(queryCtx, &subscriptiontypes.QueryCurrentRequest{ + Consumer: addr, + }) + cancel() + if err != nil { + time.Sleep(QuerySleepTime) + continue + } + fullMonthsLeft := uint64(0) + if response.Sub.DurationLeft > 0 { + // DurationLeft is 0 when expired only, it is 1 for the last month + fullMonthsLeft = response.Sub.DurationLeft - 1 + } + healthResults.setSubscriptionData(addr, SubscriptionData{ + FullMonthsLeft: fullMonthsLeft, + UsagePercentageLeftThisMonth: float64(response.Sub.MonthCuLeft) / float64(response.Sub.MonthCuTotal), + DurationLeft: time.Until(time.Unix(int64(response.Sub.MonthExpiryTime), 0)), + }) + break + } + if err != nil { + select { + case errCh <- err: + default: + } + } + }(subscriptionAddr) + } + wg.Wait() + if len(errCh) > 0 { + return <-errCh + } + return nil +} + +func CheckProviders(ctx context.Context, clientCtx client.Context, healthResults *HealthResults, providerEntries map[LavaEntity]epochstoragetypes.StakeEntry) error { + protocolQuerier := protocoltypes.NewQueryClient(clientCtx) + var param *protocoltypes.QueryParamsResponse + var err error + for i := 0; i < BasicQueryRetries; i++ { + param, err = protocolQuerier.Params(ctx, &protocoltypes.QueryParamsRequest{}) + if err == nil { + break + } + } + if err != nil { + return err + } + lavaVersion := param.GetParams().Version + if err != nil { + return err + } + targetVersion := lvutil.ParseToSemanticVersion(lavaVersion.ProviderTarget) + var wg sync.WaitGroup + wg.Add(len(providerEntries)) + + checkProviderEndpoints := func(providerEntry epochstoragetypes.StakeEntry) { + defer wg.Done() + for _, endpoint := range providerEntry.Endpoints { + checkOneProvider := func(endpoint epochstoragetypes.Endpoint, apiInterface string, addon string, providerEntry epochstoragetypes.StakeEntry) (time.Duration, string, int64, error) { + cswp := lavasession.ConsumerSessionsWithProvider{} + relayerClientPt, conn, err := cswp.ConnectRawClientWithTimeout(ctx, endpoint.IPPORT) + if err != nil { + utils.LavaFormatDebug("failed connecting to provider endpoint", utils.LogAttr("error", err), utils.Attribute{Key: "apiInterface", Value: apiInterface}, utils.Attribute{Key: "addon", Value: addon}, utils.Attribute{Key: "chainID", Value: providerEntry.Chain}, utils.Attribute{Key: "network address", Value: endpoint.IPPORT}) + return 0, "", 0, err + } + defer conn.Close() + relayerClient := *relayerClientPt + guid := uint64(rand.Int63()) + relaySentTime := time.Now() + probeReq := &pairingtypes.ProbeRequest{ + Guid: guid, + SpecId: providerEntry.Chain, + ApiInterface: apiInterface, + } + var trailer metadata.MD + probeResp, err := relayerClient.Probe(ctx, probeReq, grpc.Trailer(&trailer)) + if err != nil { + utils.LavaFormatDebug("failed probing provider endpoint", utils.LogAttr("error", err), utils.Attribute{Key: "apiInterface", Value: apiInterface}, utils.Attribute{Key: "addon", Value: addon}, utils.Attribute{Key: "chainID", Value: providerEntry.Chain}, utils.Attribute{Key: "network address", Value: endpoint.IPPORT}) + return 0, "", 0, err + } + versions := strings.Join(trailer.Get(common.VersionMetadataKey), ",") + relayLatency := time.Since(relaySentTime) + if guid != probeResp.GetGuid() { + return 0, versions, 0, utils.LavaFormatWarning("probe returned invalid value", err, utils.Attribute{Key: "returnedGuid", Value: probeResp.GetGuid()}, utils.Attribute{Key: "guid", Value: guid}, utils.Attribute{Key: "apiInterface", Value: apiInterface}, utils.Attribute{Key: "addon", Value: addon}, utils.Attribute{Key: "chainID", Value: providerEntry.Chain}, utils.Attribute{Key: "network address", Value: endpoint.IPPORT}) + } + + // CORS check + if err := rpcprovider.PerformCORSCheck(endpoint); err != nil { + return 0, versions, 0, err + } + + relayRequest := &pairingtypes.RelayRequest{ + RelaySession: &pairingtypes.RelaySession{SpecId: providerEntry.Chain}, + RelayData: &pairingtypes.RelayPrivateData{ApiInterface: apiInterface, Addon: addon}, + } + _, err = relayerClient.Relay(ctx, relayRequest) + if err == nil { + return 0, "", 0, utils.LavaFormatWarning("relay Without signature did not error, unexpected", nil, utils.Attribute{Key: "apiInterface", Value: apiInterface}, utils.Attribute{Key: "addon", Value: addon}, utils.Attribute{Key: "chainID", Value: providerEntry.Chain}, utils.Attribute{Key: "network address", Value: endpoint.IPPORT}) + } + code := status.Code(err) + if code != codes.Code(lavasession.EpochMismatchError.ABCICode()) { + return 0, versions, 0, utils.LavaFormatWarning("relay returned unexpected error", err, utils.Attribute{Key: "apiInterface", Value: apiInterface}, utils.Attribute{Key: "addon", Value: addon}, utils.Attribute{Key: "chainID", Value: providerEntry.Chain}, utils.Attribute{Key: "network address", Value: endpoint.IPPORT}) + } + return relayLatency, versions, probeResp.GetLatestBlock(), nil + } + endpointServices := endpoint.GetSupportedServices() + if len(endpointServices) == 0 { + utils.LavaFormatWarning("endpoint has no supported services", nil, utils.Attribute{Key: "endpoint", Value: endpoint}) + } + for _, endpointService := range endpointServices { + providerKey := LavaEntity{ + Address: providerEntry.Address, + SpecId: providerEntry.Chain, + ApiInterface: endpointService.ApiInterface, + } + probeLatency, version, latestBlockFromProbe, err := checkOneProvider(endpoint, endpointService.ApiInterface, endpointService.Addon, providerEntry) + if err != nil { + errMsg := prettifyProviderError(err) + healthResults.SetUnhealthyProvider(providerKey, errMsg) + continue + } + parsedVer := lvutil.ParseToSemanticVersion(strings.TrimPrefix(version, "v")) + if lvutil.IsVersionLessThan(parsedVer, targetVersion) || lvutil.IsVersionGreaterThan(parsedVer, targetVersion) { + healthResults.SetUnhealthyProvider(providerKey, "Version:"+version+" should be: "+lavaVersion.ProviderTarget) + continue + } + latestData := ReplyData{ + block: latestBlockFromProbe, + latency: probeLatency, + } + healthResults.SetProviderData(providerKey, latestData) + } + } + } + + for _, providerEntry := range providerEntries { + go checkProviderEndpoints(providerEntry) + } + wg.Wait() + return nil +} + +func prettifyProviderError(err error) string { + code := status.Code(err) + if code == codes.Code(lavaprotocol.UnhandledRelayReceiverError.ABCICode()) { + return "provider running with unhandled support" + } + if code == codes.Code(lavaprotocol.DisabledRelayReceiverError.ABCICode()) { + return "provider running with disabled support due to verification" + } + if len(err.Error()) < NiceOutputLength { + return err.Error() + } + return err.Error()[:NiceOutputLength] +} diff --git a/protocol/monitoring/health_cmd.go b/protocol/monitoring/health_cmd.go new file mode 100644 index 0000000000..4c80e2c6ed --- /dev/null +++ b/protocol/monitoring/health_cmd.go @@ -0,0 +1,226 @@ +package monitoring + +import ( + "context" + "os" + "os/signal" + "time" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/config" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/lavanet/lava/app" + "github.com/lavanet/lava/protocol/common" + "github.com/lavanet/lava/protocol/lavasession" + "github.com/lavanet/lava/protocol/metrics" + "github.com/lavanet/lava/utils" + "github.com/lavanet/lava/utils/rand" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +const ( + allowedBlockTimeDefaultLag = 30 * time.Second + intervalDefaultDuration = 0 * time.Second + defaultCUPercentageThreshold = 0.2 + defaultSubscriptionLeftDays = 10 + defaultMaxProviderLatency = 200 * time.Millisecond + defaultAlertSuppressionInterval = 6 * time.Hour + DefaultSuppressionCountThreshold = 3 + DisableAlertLogging = "disable-alert-logging" + maxProviderLatencyFlagName = "max-provider-latency" + subscriptionLeftTimeFlagName = "subscription-days-left-alert" + providerAddressesFlagName = "provider_addresses" + subscriptionAddressesFlagName = "subscription_addresses" + intervalFlagName = "interval" + consumerEndpointPropertyName = "consumer_endpoints" + referenceEndpointPropertyName = "reference_endpoints" + allowedBlockTimeLagFlagName = "allowed_time_lag" + queryRetriesFlagName = "query-retries" + alertingWebHookFlagName = "alert-webhook-url" + identifierFlagName = "identifier" + percentageCUFlagName = "cu-percent-threshold" + alertSuppressionIntervalFlagName = "alert-suppression-interval" + disableAlertSuppressionFlagName = "disable-alert-suppression" + SuppressionCountThresholdFlagName = "suppression-alert-count-threshold" +) + +func ParseEndpoints(keyName string, viper_endpoints *viper.Viper) (endpoints []*lavasession.RPCEndpoint, err error) { + err = viper_endpoints.UnmarshalKey(keyName, &endpoints) + if err != nil { + utils.LavaFormatError("could not unmarshal key to endpoints", err, utils.LogAttr("key", keyName), utils.Attribute{Key: "viper_endpoints", Value: viper_endpoints.AllSettings()}) + } + return +} + +func CreateHealthCobraCommand() *cobra.Command { + cmdTestHealth := &cobra.Command{ + Use: `health config_file`, + Short: `start monitoring the health of the protocol processes defined in the config`, + Long: `config_file if a path to a yml file`, + Example: `health config/health_examples/health_config.yml +example health config files can be found in https://github.com/lavanet/lava/blob/main/config/health_examples +subscription_addresses: + - lava@... + - lava@... +provider_addresses: + - lava@... + - lava@... + - lava@... +consumer_endpoints: + - chain-id: ETH1 + api-interface: jsonrpc + network-address: 127.0.0.1:3333 +reference_endpoints: + - chain-id: ETH1 + api-interface: jsonrpc + network-address: public-rpc-1 + - chain-id: ETH1 + api-interface: jsonrpc + network-address: public-rpc-2`, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + ctx, cancel := context.WithCancel(context.Background()) + signalChan := make(chan os.Signal, 1) + signal.Notify(signalChan, os.Interrupt) + defer func() { + signal.Stop(signalChan) + cancel() + }() + config_name := args[0] // name of config file (without extension) + viper.SetConfigName(config_name) + viper.SetConfigType("yml") + viper.AddConfigPath(".") + viper.AddConfigPath("./config") + viper.AddConfigPath(app.DefaultNodeHome) + err = viper.ReadInConfig() + if err != nil { + utils.LavaFormatFatal("could not load config file", err, utils.Attribute{Key: "expected_config_name", Value: viper.ConfigFileUsed()}) + } + // set log format + logFormat := viper.GetString(flags.FlagLogFormat) + utils.JsonFormat = logFormat == "json" + // set rolling log. + closeLoggerOnFinish := common.SetupRollingLogger() + defer closeLoggerOnFinish() + logLevel, err := cmd.Flags().GetString(flags.FlagLogLevel) + if err != nil { + utils.LavaFormatFatal("failed to read log level flag", err) + } + utils.SetGlobalLoggingLevel(logLevel) + networkChainId := viper.GetString(flags.FlagChainID) + if networkChainId == app.Name { + clientTomlConfig, err := config.ReadFromClientConfig(clientCtx) + if err == nil { + if clientTomlConfig.ChainID != "" { + networkChainId = clientTomlConfig.ChainID + } + } + } + lavasession.AllowInsecureConnectionToProviders = viper.GetBool(lavasession.AllowInsecureConnectionToProvidersFlag) + if lavasession.AllowInsecureConnectionToProviders { + utils.LavaFormatWarning("AllowInsecureConnectionToProviders is set to true, this should be used only in development", nil, utils.Attribute{Key: lavasession.AllowInsecureConnectionToProvidersFlag, Value: lavasession.AllowInsecureConnectionToProviders}) + } + clientCtx = clientCtx.WithChainID(networkChainId) + rand.InitRandomSeed() + prometheusListenAddr := viper.GetString(metrics.MetricsListenFlagName) + providerAddresses := viper.GetStringSlice(providerAddressesFlagName) + subscriptionAddresses := viper.GetStringSlice(subscriptionAddressesFlagName) + keyName := consumerEndpointPropertyName + consumerEndpoints, _ := ParseEndpoints(keyName, viper.GetViper()) + keyName = referenceEndpointPropertyName + referenceEndpoints, _ := ParseEndpoints(keyName, viper.GetViper()) + interval := viper.GetDuration(intervalFlagName) + healthMetrics := metrics.NewHealthMetrics(prometheusListenAddr) + identifier := viper.GetString(identifierFlagName) + utils.SetGlobalLoggingLevel(logLevel) + alertingOptions := AlertingOptions{ + Url: viper.GetString(alertingWebHookFlagName), + Logging: !viper.GetBool(DisableAlertLogging), + Identifier: identifier, + SubscriptionCUPercentageAlert: viper.GetFloat64(percentageCUFlagName), + SubscriptionLeftTimeAlert: time.Duration(viper.GetUint64(subscriptionLeftTimeFlagName)) * time.Hour * 24, + AllowedTimeGapVsReference: viper.GetDuration(allowedBlockTimeLagFlagName), + MaxProviderLatency: viper.GetDuration(maxProviderLatencyFlagName), + SameAlertInterval: viper.GetDuration(alertSuppressionIntervalFlagName), + DisableAlertSuppression: viper.GetBool(disableAlertSuppressionFlagName), + SuppressionCounterThreshold: viper.GetUint64(SuppressionCountThresholdFlagName), + } + alerting := NewAlerting(alertingOptions) + RunHealthCheck := func(ctx context.Context, + clientCtx client.Context, + subscriptionAddresses []string, + providerAddresses []string, + consumerEndpoints []*lavasession.RPCEndpoint, + referenceEndpoints []*lavasession.RPCEndpoint, + prometheusListenAddr string, + ) { + utils.LavaFormatInfo("[+] starting health run") + healthResult, err := RunHealth(ctx, clientCtx, subscriptionAddresses, providerAddresses, consumerEndpoints, referenceEndpoints, prometheusListenAddr) + if err != nil { + utils.LavaFormatError("[-] invalid health run", err) + healthMetrics.SetFailedRun(identifier) + } else { + utils.LavaFormatInfo("[+] completed health run") + healthMetrics.SetLatestBlockData(identifier, healthResult.FormatForLatestBlock()) + alerting.CheckHealthResults(healthResult) + activeAlerts, unhealthy, healthy := alerting.ActiveAlerts() + healthMetrics.SetSuccess(identifier) + healthMetrics.SetAlertResults(identifier, activeAlerts, unhealthy, healthy) + } + } + + RunHealthCheck(ctx, clientCtx, subscriptionAddresses, providerAddresses, consumerEndpoints, referenceEndpoints, prometheusListenAddr) + + var ticker *time.Ticker + if interval > 0*time.Second { + ticker = time.NewTicker(interval) // initially every block we check for a polling time + } else { + // never tick again + ticker = time.NewTicker(1 * time.Second) + ticker.Stop() + } + for { + select { + case <-ticker.C: + RunHealthCheck(ctx, clientCtx, subscriptionAddresses, providerAddresses, consumerEndpoints, referenceEndpoints, prometheusListenAddr) + case <-ctx.Done(): + utils.LavaFormatInfo("health ctx.Done") + return nil + case <-signalChan: + utils.LavaFormatInfo("health signalChan") + return nil + } + } + }, + } + + cmdTestHealth.Flags().Bool(lavasession.AllowInsecureConnectionToProvidersFlag, false, "allows connecting to providers without TLS mostly for local health checks inside the same vpc/server") + cmdTestHealth.Flags().Bool(DisableAlertLogging, false, "set to true to disable printing alerts to stdout") + cmdTestHealth.Flags().Uint64(SuppressionCountThresholdFlagName, DefaultSuppressionCountThreshold, "how many consecutive alerts need to be triggered so an alert is emitted") + cmdTestHealth.Flags().Bool(disableAlertSuppressionFlagName, false, "if set to true, this will disable alert suppression and send all alerts every health run") + cmdTestHealth.Flags().Duration(alertSuppressionIntervalFlagName, defaultAlertSuppressionInterval, "interval of time in which the same alert won't be triggered") + cmdTestHealth.Flags().Duration(maxProviderLatencyFlagName, defaultMaxProviderLatency, "the maximum allowed provider latency, above which it will alert") + cmdTestHealth.Flags().Uint64(subscriptionLeftTimeFlagName, defaultSubscriptionLeftDays, "the amount of days left in a subscription to trigger an alert") + cmdTestHealth.Flags().Float64(percentageCUFlagName, defaultCUPercentageThreshold, "the left cu percentage threshold to trigger a subscription alert") + cmdTestHealth.Flags().String(identifierFlagName, "", "an identifier to this instance of health added to all alerts, used to differentiate different sources") + cmdTestHealth.Flags().String(alertingWebHookFlagName, "", "a url to post an alert to") + cmdTestHealth.Flags().String(metrics.MetricsListenFlagName, metrics.DisabledFlagOption, "the address to expose prometheus metrics (such as localhost:7779)") + cmdTestHealth.Flags().Duration(intervalFlagName, intervalDefaultDuration, "the interval duration for the health check, (defaults to 0s) if 0 runs once") + cmdTestHealth.Flags().Duration(allowedBlockTimeLagFlagName, allowedBlockTimeDefaultLag, "the amount of time one rpc can be behind the most advanced one") + cmdTestHealth.Flags().Uint64Var(&QueryRetries, queryRetriesFlagName, QueryRetries, "set the amount of max queries to send every health run to consumers and references") + viper.BindPFlag(queryRetriesFlagName, cmdTestHealth.Flags().Lookup(queryRetriesFlagName)) // bind the flag + flags.AddQueryFlagsToCmd(cmdTestHealth) + common.AddRollingLogConfig(cmdTestHealth) + // add prefix config + // add monitoring endpoint + // add the ability to quiet it down + // add prometheus + // add health run times + // add latest health results to prom + return cmdTestHealth +} diff --git a/protocol/monitoring/health_results.go b/protocol/monitoring/health_results.go new file mode 100644 index 0000000000..df75225cba --- /dev/null +++ b/protocol/monitoring/health_results.go @@ -0,0 +1,171 @@ +package monitoring + +import ( + "sync" + "time" + + "github.com/lavanet/lava/protocol/common" + "github.com/lavanet/lava/protocol/lavasession" + "github.com/lavanet/lava/utils/slices" + spectypes "github.com/lavanet/lava/x/spec/types" +) + +type HealthResults struct { + LatestBlocks map[string]int64 + ProviderData map[LavaEntity]ReplyData + ConsumerBlocks map[LavaEntity]int64 + SubscriptionsData map[string]SubscriptionData + FrozenProviders map[LavaEntity]struct{} + UnhealthyProviders map[LavaEntity]string + UnhealthyConsumers map[LavaEntity]string + Specs map[string]*spectypes.Spec + Lock sync.RWMutex +} + +func (healthResults *HealthResults) FormatForLatestBlock() map[string]uint64 { + healthResults.Lock.RLock() + defer healthResults.Lock.RUnlock() + results := map[string]uint64{} + for entity, block := range healthResults.ConsumerBlocks { + results[entity.String()] = uint64(block) + } + for entity, data := range healthResults.ProviderData { + results[entity.String()] = uint64(data.block) + } + for entity := range healthResults.UnhealthyProviders { + results[entity.String()] = 0 + } + for entity := range healthResults.UnhealthyConsumers { + results[entity.String()] = 0 + } + return results +} + +func (healthResults *HealthResults) GetAllEntities() map[LavaEntity]struct{} { + healthResults.Lock.RLock() + defer healthResults.Lock.RUnlock() + entities := map[LavaEntity]struct{}{} + for entity := range healthResults.FrozenProviders { + entities[entity] = struct{}{} + } + for entity := range healthResults.UnhealthyProviders { + entities[entity] = struct{}{} + } + for entity := range healthResults.UnhealthyConsumers { + entities[entity] = struct{}{} + } + for entity := range healthResults.ConsumerBlocks { + entities[entity] = struct{}{} + } + for entity := range healthResults.ProviderData { + entities[entity] = struct{}{} + } + for entitySt := range healthResults.SubscriptionsData { + entity := LavaEntity{ + Address: entitySt, + SpecId: "", + } + entities[entity] = struct{}{} + } + return entities +} + +func (healthResults *HealthResults) FreezeProvider(providerKey LavaEntity) { + healthResults.Lock.Lock() + defer healthResults.Lock.Unlock() + healthResults.FrozenProviders[providerKey] = struct{}{} +} + +func (healthResults *HealthResults) setSpec(spec *spectypes.Spec) { + healthResults.Lock.Lock() + defer healthResults.Lock.Unlock() + healthResults.Specs[spec.Index] = spec +} + +func (healthResults *HealthResults) updateLatestBlock(specId string, latestBlock int64) { + healthResults.Lock.Lock() + defer healthResults.Lock.Unlock() + existing, ok := healthResults.LatestBlocks[specId] + if !ok { + healthResults.LatestBlocks[specId] = latestBlock + } else { + healthResults.LatestBlocks[specId] = slices.Max([]int64{existing, latestBlock}) + } +} + +func (healthResults *HealthResults) updateConsumerError(endpoint *lavasession.RPCEndpoint, err error) { + healthResults.Lock.Lock() + defer healthResults.Lock.Unlock() + healthResults.ConsumerBlocks[LavaEntity{ + Address: endpoint.String(), + SpecId: endpoint.ChainID, + ApiInterface: endpoint.ApiInterface, + }] = 0 + msg := "invalid response" + if len(err.Error()) < NiceOutputLength { + msg = err.Error() + } + if common.IsTimeout(err) { + msg = "timeout" + } + healthResults.UnhealthyConsumers[LavaEntity{ + Address: endpoint.String(), + SpecId: endpoint.ChainID, + ApiInterface: endpoint.ApiInterface, + }] = msg +} + +func (healthResults *HealthResults) updateConsumer(endpoint *lavasession.RPCEndpoint, latestBlock int64) { + healthResults.Lock.Lock() + defer healthResults.Lock.Unlock() + healthResults.ConsumerBlocks[LavaEntity{ + Address: endpoint.String(), + SpecId: endpoint.ChainID, + ApiInterface: endpoint.ApiInterface, + }] = latestBlock +} + +func (healthResults *HealthResults) getSpecs() map[string]*spectypes.Spec { + healthResults.Lock.RLock() + defer healthResults.Lock.RUnlock() + return healthResults.Specs +} + +func (healthResults *HealthResults) getSpec(specId string) *spectypes.Spec { + healthResults.Lock.RLock() + defer healthResults.Lock.RUnlock() + return healthResults.Specs[specId] +} + +func (healthResults *HealthResults) getProviderData(providerKey LavaEntity) (latestData ReplyData, ok bool) { + healthResults.Lock.Lock() + defer healthResults.Lock.Unlock() + data, ok := healthResults.ProviderData[providerKey] + return data, ok +} + +func (healthResults *HealthResults) SetProviderData(providerKey LavaEntity, latestData ReplyData) { + healthResults.Lock.Lock() + defer healthResults.Lock.Unlock() + if existing, ok := healthResults.ProviderData[providerKey]; ok { + if existing.block == 0 { + existing.block = latestData.block + } else { + latestData.block = slices.Min([]int64{existing.block, latestData.block}) + } + latestData.latency = slices.Max([]time.Duration{existing.latency, latestData.latency}) + } + healthResults.ProviderData[providerKey] = latestData +} + +func (healthResults *HealthResults) SetUnhealthyProvider(providerKey LavaEntity, errMsg string) { + healthResults.Lock.Lock() + defer healthResults.Lock.Unlock() + healthResults.UnhealthyProviders[providerKey] = errMsg +} + +func (healthResults *HealthResults) setSubscriptionData(subscriptionAddr string, data SubscriptionData) { + healthResults.Lock.Lock() + defer healthResults.Lock.Unlock() + healthResults.SubscriptionsData[subscriptionAddr] = data +} diff --git a/protocol/rpcprovider/cors_test.go b/protocol/rpcprovider/cors_test.go index e034acaa79..098c646e62 100644 --- a/protocol/rpcprovider/cors_test.go +++ b/protocol/rpcprovider/cors_test.go @@ -90,7 +90,7 @@ func TestPerformCORSCheckFail(t *testing.T) { IPPORT: "localhost:8080", } - err := performCORSCheck(endpoint) + err := PerformCORSCheck(endpoint) require.NotNil(t, err, "Expected CORS check to fail but it passed") require.True(t, strings.Contains(err.Error(), "CORS check failed"), "Expected CORS related error message", err) } @@ -100,7 +100,7 @@ func TestPerformCORSCheckFailXGrpcWeb(t *testing.T) { IPPORT: "localhost:8081", } - err := performCORSCheck(endpoint) + err := PerformCORSCheck(endpoint) require.NotNil(t, err, "Expected CORS check to fail but it passed") require.True(t, strings.Contains(err.Error(), "x-grpc-web"), "Expected error to relate to x-grpc-web") } @@ -110,7 +110,7 @@ func TestPerformCORSCheckFailLavaSdkRelayTimeout(t *testing.T) { IPPORT: "localhost:8082", } - err := performCORSCheck(endpoint) + err := PerformCORSCheck(endpoint) require.NotNil(t, err, "Expected CORS check to fail but it passed") require.True(t, strings.Contains(err.Error(), "lava-sdk-relay-timeout"), "Expected error to relate to lava-sdk-relay-timeout") } @@ -120,7 +120,7 @@ func TestPerformCORSCheckSuccess(t *testing.T) { IPPORT: "localhost:8083", // pointing to the server with all headers } - err := performCORSCheck(endpoint) + err := PerformCORSCheck(endpoint) require.Nil(t, err, "Expected CORS check to pass but it failed") } diff --git a/protocol/rpcprovider/provider_listener.go b/protocol/rpcprovider/provider_listener.go index f9d5768d46..51a83706a8 100644 --- a/protocol/rpcprovider/provider_listener.go +++ b/protocol/rpcprovider/provider_listener.go @@ -7,14 +7,17 @@ import ( "strings" "sync" + "github.com/gogo/status" "github.com/improbable-eng/grpc-web/go/grpcweb" "github.com/lavanet/lava/protocol/chainlib" + "github.com/lavanet/lava/protocol/lavaprotocol" "github.com/lavanet/lava/protocol/lavasession" "github.com/lavanet/lava/utils" pairingtypes "github.com/lavanet/lava/x/pairing/types" "golang.org/x/net/http2" "golang.org/x/net/http2/h2c" grpc "google.golang.org/grpc" + "google.golang.org/grpc/codes" ) type ProviderListener struct { @@ -145,10 +148,12 @@ func (rs *relayServer) findReceiver(apiInterface string, specID string) (RelayRe for k := range rs.relayReceivers { keys = append(keys, k) } - return nil, utils.LavaFormatError("got called with unhandled relay receiver", nil, utils.Attribute{Key: "requested_receiver", Value: endpoint.Key()}, utils.Attribute{Key: "handled_receivers", Value: strings.Join(keys, ",")}) + err := utils.LavaFormatError("got called with unhandled relay receiver", lavaprotocol.UnhandledRelayReceiverError, utils.Attribute{Key: "requested_receiver", Value: endpoint.Key()}, utils.Attribute{Key: "handled_receivers", Value: strings.Join(keys, ",")}) + return nil, status.Error(codes.Code(lavaprotocol.UnhandledRelayReceiverError.ABCICode()), err.Error()) } if !relayReceiver.enabled { - return nil, utils.LavaFormatError("relayReceiver is disabled", nil, utils.Attribute{Key: "relayReceiver", Value: endpoint.Key()}) + err := utils.LavaFormatError("relayReceiver is disabled", lavaprotocol.DisabledRelayReceiverError, utils.Attribute{Key: "relayReceiver", Value: endpoint.Key()}) + return nil, status.Error(codes.Code(lavaprotocol.DisabledRelayReceiverError.ABCICode()), err.Error()) } return *relayReceiver.relayReceiver, nil } diff --git a/protocol/rpcprovider/rpcprovider.go b/protocol/rpcprovider/rpcprovider.go index 6ae82d3eb3..e0c7d4e627 100644 --- a/protocol/rpcprovider/rpcprovider.go +++ b/protocol/rpcprovider/rpcprovider.go @@ -308,7 +308,7 @@ func (rpcp *RPCProvider) SetupEndpoint(ctx context.Context, rpcProviderEndpoint // Add the chain fetcher to the spec validator err := specValidator.AddChainFetcher(ctx, &chainFetcher, chainID) if err != nil { - return err + return utils.LavaFormatError("panic severity critical error, failed validating chain", err, utils.Attribute{Key: "rpcProviderEndpoint", Value: rpcProviderEndpoint}) } var found bool diff --git a/protocol/rpcprovider/testing.go b/protocol/rpcprovider/testing.go index 5cfb6953fb..12b4247846 100644 --- a/protocol/rpcprovider/testing.go +++ b/protocol/rpcprovider/testing.go @@ -47,7 +47,7 @@ func validatePortNumber(ipPort string) string { return ipPort } -func performCORSCheck(endpoint epochstoragetypes.Endpoint) error { +func PerformCORSCheck(endpoint epochstoragetypes.Endpoint) error { utils.LavaFormatDebug("Checking CORS", utils.Attribute{Key: "endpoint", Value: endpoint}) // Construct the URL for the RPC endpoint endpointURL := "https://" + endpoint.IPPORT // Providers must have HTTPS support @@ -165,7 +165,7 @@ func startTesting(ctx context.Context, clientCtx client.Context, txFactory tx.Fa } // CORS check - if err := performCORSCheck(endpoint); err != nil { + if err := PerformCORSCheck(endpoint); err != nil { return 0, versions, 0, err } diff --git a/protocol/statetracker/state_tracker.go b/protocol/statetracker/state_tracker.go index abd3c2d4e4..7881a697d1 100644 --- a/protocol/statetracker/state_tracker.go +++ b/protocol/statetracker/state_tracker.go @@ -54,15 +54,19 @@ func NewStateTracker(ctx context.Context, txFactory tx.Factory, clientCtx client return nil, utils.LavaFormatError("failed getting blockResults after retries", err) } specQueryClient := spectypes.NewQueryClient(clientCtx) - specResponse, err := specQueryClient.Spec(ctx, &spectypes.QueryGetSpecRequest{ - ChainID: "LAV1", - }) - for i := 0; i < BlockResultRetry && err != nil; i++ { + var specResponse *spectypes.QueryGetSpecResponse + for i := 0; i < BlockResultRetry; i++ { specResponse, err = specQueryClient.Spec(ctx, &spectypes.QueryGetSpecRequest{ ChainID: "LAV1", }) + if err == nil { + break + } + time.Sleep(20 * time.Millisecond) + } + if err != nil { + utils.LavaFormatFatal("failed querying lava spec for state tracker", err) } - cst := &StateTracker{newLavaBlockUpdaters: map[string]Updater{}, EventTracker: eventTracker} chainTrackerConfig := chaintracker.ChainTrackerConfig{ NewLatestCallback: cst.newLavaBlock, diff --git a/scripts/init_chain_commands.sh b/scripts/init_chain_commands.sh index ec0372e9f9..78c018be80 100755 --- a/scripts/init_chain_commands.sh +++ b/scripts/init_chain_commands.sh @@ -53,7 +53,12 @@ lavad tx dualstaking delegate $(lavad keys show servicer3 -a) ETH1 $PROVIDERSTAK # we need to wait for the next epoch for the stake to take action. sleep_until_next_epoch +HEALTH_FILE="config/health_examples/health_template.yml" +create_health_config $HEALTH_FILE $(lavad keys show user1 -a) $(lavad keys show servicer2 -a) $(lavad keys show servicer3 -a) if [[ "$1" != "--skip-providers" ]]; then . ${__dir}/setup_providers.sh +echo "letting providers start and running health check" +sleep 10 +lavap test health $HEALTH_FILE fi \ No newline at end of file diff --git a/scripts/init_install.sh b/scripts/init_install.sh index f533d019e4..86e246eb64 100755 --- a/scripts/init_install.sh +++ b/scripts/init_install.sh @@ -84,8 +84,8 @@ fi if ! command_exists yq; then if ! check_go_version; then - echo "Go 1.20 is not installed. Installing..." - sudo apt install -y golang-1.20 + echo "Go 1.21 is not installed. Installing..." + sudo apt install -y golang-1.21 fi go install github.com/mikefarah/yq/v4@latest diff --git a/scripts/useful_commands.sh b/scripts/useful_commands.sh index 7974033540..298023a17b 100644 --- a/scripts/useful_commands.sh +++ b/scripts/useful_commands.sh @@ -53,9 +53,9 @@ command_exists() { command -v "$1" >/dev/null 2>&1 } -# Function to check the Go version is at least 1.20 +# Function to check the Go version is at least 1.21 check_go_version() { - local GO_VERSION=1.20 + local GO_VERSION=1.21 if ! command_exists go; then return 1 @@ -81,3 +81,40 @@ latest_vote() { fi lavad q gov proposals 2> /dev/null | yq eval '.proposals[].id' | wc -l } + +create_health_config() { + local source_file="$1" + local destination_file="${source_file%.*}_gen.yml" + local subscription_address="$2" + local provider_address_1="$3" + local provider_address_2="$4" + local provider_address_3="$5" + + # Use awk to find the line number of the comment + local comment_line_number=$(awk '/#REPLACED/ {print NR; exit}' "$source_file") + + # If the comment is found, create a new file with the updated content + if [ -n "$comment_line_number" ]; then + # Use awk to update the content and create a new file + awk -v line="$comment_line_number" -v sub_addr="$subscription_address" \ + -v prov_addr_1="$provider_address_1" -v prov_addr_2="$provider_address_2" \ + -v prov_addr_3="$provider_address_3" \ + '{ + if (NR <= line) { + print; + } else if (NR == line + 1) { + print "subscription_addresses:"; + print " - " sub_addr; + print "provider_addresses:"; + print " - " prov_addr_1; + print " - " prov_addr_2; + print " - " prov_addr_3; + } + }' "$source_file" > "$destination_file" + + echo "File $destination_file created successfully." + else + echo "Comment #REPLACED not found in the file." + exit 1 + fi +} \ No newline at end of file diff --git a/utils/lavalog.go b/utils/lavalog.go index b86c4765b5..1655c8dac8 100644 --- a/utils/lavalog.go +++ b/utils/lavalog.go @@ -143,6 +143,65 @@ func RollingLoggerSetup(rollingLogLevel string, filePath string, maxSize string, return func() { rollingLogOutput.Close() } } +func StrValueForLog(val interface{}, key string, idx int, attributes []Attribute) string { + st_val := "" + switch value := val.(type) { + case context.Context: + // we don't want to print the whole context so change it + switch key { + case "GUID": + guid, found := GetUniqueIdentifier(value) + if found { + st_val = strconv.FormatUint(guid, 10) + attributes[idx] = Attribute{Key: key, Value: guid} + } else { + attributes[idx] = Attribute{Key: key, Value: "no-guid"} + } + default: + attributes[idx] = Attribute{Key: key, Value: "context-masked"} + } + default: + st_val = StrValue(val) + } + return st_val +} + +func StrValue(val interface{}) string { + st_val := "" + switch value := val.(type) { + case context.Context: + // we don't want to print the whole context so change it + case bool: + if value { + st_val = "true" + } else { + st_val = "false" + } + case fmt.Stringer: + st_val = value.String() + case string: + st_val = value + case int: + st_val = strconv.Itoa(value) + case int64: + st_val = strconv.FormatInt(value, 10) + case uint64: + st_val = strconv.FormatUint(value, 10) + case error: + st_val = value.Error() + case []string: + st_val = strings.Join(value, ",") + // needs to come after stringer so byte inheriting objects will use their string method if implemented (like AccAddress) + case []byte: + st_val = string(value) + case nil: + st_val = "" + default: + st_val = fmt.Sprintf("%+v", value) + } + return st_val +} + func LavaFormatLog(description string, err error, attributes []Attribute, severity uint) error { zerolog.TimeFieldFormat = zerolog.TimeFormatUnix if JsonFormat { @@ -157,11 +216,15 @@ func LavaFormatLog(description string, err error, attributes []Attribute, severi case LAVA_LOG_PANIC: // prefix = "Panic:" logEvent = zerologlog.Panic() - rollingLoggerEvent = rollingLogLogger.Panic() + if rollingLogLogger.GetLevel() != zerolog.Disabled { + rollingLoggerEvent = rollingLogLogger.Panic() + } case LAVA_LOG_FATAL: // prefix = "Fatal:" logEvent = zerologlog.Fatal() - rollingLoggerEvent = rollingLogLogger.Fatal() + if rollingLogLogger.GetLevel() != zerolog.Disabled { + rollingLoggerEvent = rollingLogLogger.Fatal() + } case LAVA_LOG_ERROR: // prefix = "Error:" logEvent = zerologlog.Error() @@ -190,50 +253,7 @@ func LavaFormatLog(description string, err error, attributes []Attribute, severi for idx, attr := range attributes { key := attr.Key val := attr.Value - st_val := "" - switch value := val.(type) { - case context.Context: - // we don't want to print the whole context so change it - switch key { - case "GUID": - guid, found := GetUniqueIdentifier(value) - if found { - st_val = strconv.FormatUint(guid, 10) - attributes[idx] = Attribute{Key: key, Value: guid} - } else { - attributes[idx] = Attribute{Key: key, Value: "no-guid"} - } - default: - attributes[idx] = Attribute{Key: key, Value: "context-masked"} - } - case bool: - if value { - st_val = "true" - } else { - st_val = "false" - } - case fmt.Stringer: - st_val = value.String() - case string: - st_val = value - case int: - st_val = strconv.Itoa(value) - case int64: - st_val = strconv.FormatInt(value, 10) - case uint64: - st_val = strconv.FormatUint(value, 10) - case error: - st_val = value.Error() - case []string: - st_val = strings.Join(value, ",") - // needs to come after stringer so byte inheriting objects will use their string method if implemented (like AccAddress) - case []byte: - st_val = string(value) - case nil: - st_val = "" - default: - st_val = fmt.Sprintf("%+v", value) - } + st_val := StrValueForLog(val, key, idx, attributes) logEvent = logEvent.Str(key, st_val) rollingLoggerEvent = rollingLoggerEvent.Str(key, st_val) attrStrings = append(attrStrings, fmt.Sprintf("%s:%s", attr.Key, st_val)) From 24e920385065806bb300736ee2b0edc24a3048ab Mon Sep 17 00:00:00 2001 From: Ran Mishael <106548467+ranlavanet@users.noreply.github.com> Date: Thu, 14 Dec 2023 11:07:07 +0100 Subject: [PATCH 72/85] increasing protocol target version to 0.31.2 (#1045) --- x/protocol/types/params.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/protocol/types/params.go b/x/protocol/types/params.go index cf99c326c8..bc7ec7f70e 100644 --- a/x/protocol/types/params.go +++ b/x/protocol/types/params.go @@ -12,7 +12,7 @@ import ( var _ paramtypes.ParamSet = (*Params)(nil) const ( - TARGET_VERSION = "0.31.1" + TARGET_VERSION = "0.31.2" MIN_VERSION = "0.30.1" ) From 29384399c89fad19d76729d62e9c0ddda3ee2160 Mon Sep 17 00:00:00 2001 From: Omer <100387053+omerlavanet@users.noreply.github.com> Date: Thu, 14 Dec 2023 13:06:16 +0200 Subject: [PATCH 73/85] added a test for a load balancer (#1046) * working connection server, prober * lint --- cmd/lavap/main.go | 3 + .../health_examples/health_template_gen.yml | 33 ++++ .../performance/connection/connection_cmd.go | 162 ++++++++++++++++++ protocol/performance/connection/prober.go | 58 +++++++ protocol/performance/connection/server.go | 31 ++++ 5 files changed, 287 insertions(+) create mode 100644 config/health_examples/health_template_gen.yml create mode 100644 protocol/performance/connection/connection_cmd.go create mode 100644 protocol/performance/connection/prober.go create mode 100644 protocol/performance/connection/server.go diff --git a/cmd/lavap/main.go b/cmd/lavap/main.go index f7ef58d863..6dab418f9e 100644 --- a/cmd/lavap/main.go +++ b/cmd/lavap/main.go @@ -12,6 +12,7 @@ import ( "github.com/lavanet/lava/ecosystem/cache" "github.com/lavanet/lava/protocol/badgegenerator" "github.com/lavanet/lava/protocol/monitoring" + "github.com/lavanet/lava/protocol/performance/connection" "github.com/lavanet/lava/protocol/rpcconsumer" "github.com/lavanet/lava/protocol/rpcprovider" "github.com/lavanet/lava/protocol/statetracker" @@ -53,6 +54,8 @@ func main() { testCmd.AddCommand(rpcconsumer.CreateTestRPCConsumerCobraCommand()) testCmd.AddCommand(rpcprovider.CreateTestRPCProviderCobraCommand()) testCmd.AddCommand(statetracker.CreateEventsCobraCommand()) + testCmd.AddCommand(connection.CreateTestConnectionServerCobraCommand()) + testCmd.AddCommand(connection.CreateTestConnectionProbeCobraCommand()) testCmd.AddCommand(monitoring.CreateHealthCobraCommand()) rootCmd.AddCommand(cache.CreateCacheCobraCommand()) if err := svrcmd.Execute(rootCmd, "", app.DefaultNodeHome); err != nil { diff --git a/config/health_examples/health_template_gen.yml b/config/health_examples/health_template_gen.yml new file mode 100644 index 0000000000..44cc616f01 --- /dev/null +++ b/config/health_examples/health_template_gen.yml @@ -0,0 +1,33 @@ +max-provider-latency: 150ms +subscription-days-left-alert: 10 +interval: 5s +allowed_time_lag: 30s +query-retries: 5 +identifier: health_example +cu-percent-threshold: 0.2 +alert-suppression-interval: 60s +disable-alert-suppression: false +suppression-alert-count-threshold: 2 +metrics-listen-address: ":7776" +disable-alert-logging: false +allow-insecure-provider-dialing: true +consumer_endpoints: + - chain-id: ETH1 + api-interface: jsonrpc + network-address: http://127.0.0.1:3333 + - chain-id: LAV1 + api-interface: rest + network-address: http://127.0.0.1:3360 + - chain-id: LAV1 + api-interface: tendermintrpc + network-address: http://127.0.0.1:3361 + - chain-id: LAV1 + api-interface: grpc + network-address: 127.0.0.1:3362 +#REPLACED +subscription_addresses: + - lava@1dpr9377jlt0jkcrdetjvp4hlzeypacz2yeehkf +provider_addresses: + - lava@1ue77wfp7nru7kwh6ca2twrs4l4t9wgwndf0h43 + - lava@14q33eq0emr95jw5urjcfamylrz3z6qsyjv2wpl + - diff --git a/protocol/performance/connection/connection_cmd.go b/protocol/performance/connection/connection_cmd.go new file mode 100644 index 0000000000..4f88321ae7 --- /dev/null +++ b/protocol/performance/connection/connection_cmd.go @@ -0,0 +1,162 @@ +package connection + +import ( + "context" + "errors" + "net/http" + "os" + "os/signal" + "time" + + "github.com/improbable-eng/grpc-web/go/grpcweb" + "github.com/lavanet/lava/protocol/chainlib" + "github.com/lavanet/lava/protocol/lavasession" + "github.com/lavanet/lava/utils" + pairingtypes "github.com/lavanet/lava/x/pairing/types" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "golang.org/x/net/http2" + "golang.org/x/net/http2/h2c" + "google.golang.org/grpc" +) + +const ( + intervalFlagName = "interval" + disableTLSFlagName = "disable-tls" +) + +func CreateTestConnectionServerCobraCommand() *cobra.Command { + cmdTestConnectionServer := &cobra.Command{ + Use: `connection-server [listen_address:port]`, + Short: `test an incoming connection`, + Long: `sets up a grpc server listning to the probe grpc query and logs connection`, + Example: `connection-server 127.0.0.1:3333`, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + utils.LavaFormatInfo("Connection-server started") + ctx := context.Background() + listenAddr := args[0] + ctx, cancel := context.WithCancel(ctx) + signalChan := make(chan os.Signal, 1) + signal.Notify(signalChan, os.Interrupt) + defer func() { + signal.Stop(signalChan) + cancel() + }() + + // GRPC + lis := chainlib.GetListenerWithRetryGrpc("tcp", listenAddr) + serverReceiveMaxMessageSize := grpc.MaxRecvMsgSize(1024 * 1024 * 32) // setting receive size to 32mb instead of 4mb default + grpcServer := grpc.NewServer(serverReceiveMaxMessageSize) + + wrappedServer := grpcweb.WrapServer(grpcServer) + handler := func(resp http.ResponseWriter, req *http.Request) { + // Set CORS headers + resp.Header().Set("Access-Control-Allow-Origin", "*") + resp.Header().Set("Access-Control-Allow-Headers", "Content-Type, x-grpc-web, lava-sdk-relay-timeout") + + wrappedServer.ServeHTTP(resp, req) + } + + httpServer := http.Server{ + Handler: h2c.NewHandler(http.HandlerFunc(handler), &http2.Server{}), + } + + disableTLS := viper.GetBool(disableTLSFlagName) + var serveExecutor func() error + if disableTLS { + utils.LavaFormatWarning("Running with disabled TLS configuration", nil) + serveExecutor = func() error { return httpServer.Serve(lis) } + } else { + NetworkAddressData := lavasession.NetworkAddressData{} + httpServer.TLSConfig = lavasession.GetTlsConfig(NetworkAddressData) + serveExecutor = func() error { return httpServer.ServeTLS(lis, "", "") } + } + + guid := utils.GenerateUniqueIdentifier() + utils.LavaFormatInfo("running with unique identifier", utils.LogAttr("guid", guid)) + Server := &RelayerConnectionServer{guid: guid} + + pairingtypes.RegisterRelayerServer(grpcServer, Server) + + go func() { + select { + case <-ctx.Done(): + _ = utils.LavaFormatInfo("connection-server ctx.Done") + case <-signalChan: + _ = utils.LavaFormatInfo("connection-server signalChan") + } + + shutdownCtx, shutdownRelease := context.WithTimeout(ctx, 10*time.Second) + defer shutdownRelease() + + if err := httpServer.Shutdown(shutdownCtx); err != nil { + utils.LavaFormatFatal("connection-server failed to shutdown", err) + } + }() + + utils.LavaFormatInfo("connection-server active", utils.Attribute{Key: "address", Value: listenAddr}) + if err := serveExecutor(); !errors.Is(err, http.ErrServerClosed) { + utils.LavaFormatFatal("connection-server failed to serve", err, utils.Attribute{Key: "Address", Value: lis.Addr().String()}) + } + utils.LavaFormatInfo("connection-server closed server", utils.Attribute{Key: "address", Value: listenAddr}) + + return nil + }, + } + cmdTestConnectionServer.Flags().Bool(disableTLSFlagName, false, "used to disable tls in the server, if false will serve secure grpc with a floating certificate") + return cmdTestConnectionServer +} + +func CreateTestConnectionProbeCobraCommand() *cobra.Command { + cmdTestConnectionProbe := &cobra.Command{ + Use: `connection-probe [target_address:port]`, + Short: `test an a grpc server by probing`, + Long: `sets up a grpc client probing the provided grpc server`, + Example: `connection-probe 127.0.0.1:3333 --interval 2s`, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + utils.LavaFormatInfo("Connection-prober started") + ctx, cancel := context.WithCancel(context.Background()) + signalChan := make(chan os.Signal, 1) + signal.Notify(signalChan, os.Interrupt) + defer func() { + signal.Stop(signalChan) + cancel() + }() + lavasession.AllowInsecureConnectionToProviders = viper.GetBool(lavasession.AllowInsecureConnectionToProvidersFlag) + if lavasession.AllowInsecureConnectionToProviders { + utils.LavaFormatWarning("AllowInsecureConnectionToProviders is set to true, this should be used only in development", nil, utils.Attribute{Key: lavasession.AllowInsecureConnectionToProvidersFlag, Value: lavasession.AllowInsecureConnectionToProviders}) + } + address := args[0] + prober := NewProber(address) + utils.LavaFormatInfo("[+] making a run") + err := prober.RunOnce(ctx) + if err != nil { + utils.LavaFormatError("failed a run", err) + } + interval := viper.GetDuration(intervalFlagName) + if interval > 0*time.Second { + ticker := time.NewTicker(interval) // initially every block we check for a polling time + for { + select { + case <-ticker.C: + utils.LavaFormatInfo("[+] making a run") + err = prober.RunOnce(ctx) + utils.LavaFormatError("failed a run", err) + case <-ctx.Done(): + utils.LavaFormatInfo("prober ctx.Done") + return nil + case <-signalChan: + utils.LavaFormatInfo("prober signalChan") + return nil + } + } + } + return err + }, + } + cmdTestConnectionProbe.Flags().Bool(lavasession.AllowInsecureConnectionToProvidersFlag, false, "allow insecure provider-dialing. used for development and testing without TLS") + cmdTestConnectionProbe.Flags().Duration(intervalFlagName, 0, "the interval duration for the health check, (defaults to 0s) if 0 runs once") + return cmdTestConnectionProbe +} diff --git a/protocol/performance/connection/prober.go b/protocol/performance/connection/prober.go new file mode 100644 index 0000000000..add6bd38be --- /dev/null +++ b/protocol/performance/connection/prober.go @@ -0,0 +1,58 @@ +package connection + +import ( + "context" + "fmt" + "math/rand" + + "github.com/lavanet/lava/protocol/lavasession" + "github.com/lavanet/lava/utils" + pairingtypes "github.com/lavanet/lava/x/pairing/types" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" +) + +type Prober struct { + address string + conn *grpc.ClientConn + relayerClient *pairingtypes.RelayerClient +} + +func NewProber(addrss string) *Prober { + return &Prober{address: addrss} +} + +func createConnection(ctx context.Context, address string) (*pairingtypes.RelayerClient, *grpc.ClientConn, error) { + cswp := lavasession.ConsumerSessionsWithProvider{} + return cswp.ConnectRawClientWithTimeout(ctx, address) +} + +func (p *Prober) RunOnce(ctx context.Context) error { + if p.address == "" { + return fmt.Errorf("can't run with address empty") + } + if p.conn == nil || p.relayerClient == nil { + relayer, conn, err := createConnection(ctx, p.address) + if err != nil { + return err + } + p.relayerClient = relayer + p.conn = conn + } + relayerClient := *p.relayerClient + guid := uint64(rand.Int63()) + + probeReq := &pairingtypes.ProbeRequest{ + Guid: guid, + SpecId: "prober", + ApiInterface: "", + } + var trailer metadata.MD + utils.LavaFormatInfo("[+] sending probe", utils.LogAttr("guid", guid)) + probeResp, err := relayerClient.Probe(ctx, probeReq, grpc.Trailer(&trailer)) + if err != nil { + return err + } + utils.LavaFormatInfo("probe response", utils.LogAttr("guid", probeResp.Guid)) + return nil +} diff --git a/protocol/performance/connection/server.go b/protocol/performance/connection/server.go new file mode 100644 index 0000000000..aabfcba51a --- /dev/null +++ b/protocol/performance/connection/server.go @@ -0,0 +1,31 @@ +package connection + +import ( + "context" + "fmt" + + "github.com/lavanet/lava/protocol/common" + "github.com/lavanet/lava/utils" + pairingtypes "github.com/lavanet/lava/x/pairing/types" +) + +type RelayerConnectionServer struct { + pairingtypes.UnimplementedRelayerServer + guid uint64 +} + +func (rs *RelayerConnectionServer) Relay(ctx context.Context, request *pairingtypes.RelayRequest) (*pairingtypes.RelayReply, error) { + return nil, fmt.Errorf("unimplemented") +} + +func (rs *RelayerConnectionServer) Probe(ctx context.Context, probeReq *pairingtypes.ProbeRequest) (*pairingtypes.ProbeReply, error) { + peerAddress := common.GetIpFromGrpcContext(ctx) + utils.LavaFormatInfo("received probe", utils.LogAttr("incoming-ip", peerAddress)) + return &pairingtypes.ProbeReply{ + Guid: rs.guid, + }, nil +} + +func (rs *RelayerConnectionServer) RelaySubscribe(request *pairingtypes.RelayRequest, srv pairingtypes.Relayer_RelaySubscribeServer) error { + return fmt.Errorf("unimplemented") +} From f18f11330f6fff78728ae723ec96fc132c76b0cb Mon Sep 17 00:00:00 2001 From: Omer <100387053+omerlavanet@users.noreply.github.com> Date: Sun, 17 Dec 2023 10:54:07 +0200 Subject: [PATCH 74/85] fix health alerting when flaky (#1049) * fix health alerting when flaky * lint * fix an error in health * added print to debug * change ticker order --- protocol/monitoring/alerting.go | 10 +++++++--- protocol/monitoring/health.go | 1 + protocol/monitoring/health_cmd.go | 4 ++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/protocol/monitoring/alerting.go b/protocol/monitoring/alerting.go index ad8502a60d..e9e2f68316 100644 --- a/protocol/monitoring/alerting.go +++ b/protocol/monitoring/alerting.go @@ -441,10 +441,14 @@ func (al *Alerting) CheckHealthResults(healthResults *HealthResults) { // this entry wasn't alerted currently therefore we can shut it off count := al.activeAlerts[alertEntry] count.recovery++ // increase recovery - al.activeAlerts[alertEntry] = count if count.recovery >= al.suppressionCounterThreshold { keysToDelete = append(keysToDelete, alertEntry) + } else if count.active < al.suppressionCounterThreshold { + // if the threshold for an alert wasn't reached we suppress alerting too + count.active = 0 } + + al.activeAlerts[alertEntry] = count } else { count := al.activeAlerts[alertEntry] count.recovery = 0 @@ -471,9 +475,9 @@ func (al *Alerting) CheckHealthResults(healthResults *HealthResults) { } } if len(al.currentAlerts) == 0 { - utils.LavaFormatInfo("[+] healthy - no new alerts") + utils.LavaFormatInfo("[+] healthy - no new alerts", utils.LogAttr("healthy", uint64(len(al.healthy)))) } else { - utils.LavaFormatInfo("[-] unhealthy", utils.LogAttr("count", uint64(len(al.unhealthy))), utils.LogAttr("currently suppressed", al.suppressedAlerts-suppressed)) + utils.LavaFormatInfo("[-] unhealthy", utils.LogAttr("healthy", uint64(len(al.healthy))), utils.LogAttr("count", uint64(len(al.unhealthy))), utils.LogAttr("currently suppressed", al.suppressedAlerts-suppressed)) } al.SendAppendedAlerts() } diff --git a/protocol/monitoring/health.go b/protocol/monitoring/health.go index c119e63c0d..24aa3bb989 100644 --- a/protocol/monitoring/health.go +++ b/protocol/monitoring/health.go @@ -339,6 +339,7 @@ func CheckConsumersAndReferences(ctx context.Context, if !isReference { healthResults.updateConsumerError(endpoint, err) } + return nil } chainFetcher := chainlib.NewChainFetcher(ctx, chainProxy, chainParser, compatibleEndpoint, nil) var latestBlock int64 diff --git a/protocol/monitoring/health_cmd.go b/protocol/monitoring/health_cmd.go index 4c80e2c6ed..30ee238d08 100644 --- a/protocol/monitoring/health_cmd.go +++ b/protocol/monitoring/health_cmd.go @@ -186,14 +186,14 @@ reference_endpoints: } for { select { - case <-ticker.C: - RunHealthCheck(ctx, clientCtx, subscriptionAddresses, providerAddresses, consumerEndpoints, referenceEndpoints, prometheusListenAddr) case <-ctx.Done(): utils.LavaFormatInfo("health ctx.Done") return nil case <-signalChan: utils.LavaFormatInfo("health signalChan") return nil + case <-ticker.C: + RunHealthCheck(ctx, clientCtx, subscriptionAddresses, providerAddresses, consumerEndpoints, referenceEndpoints, prometheusListenAddr) } } }, From 970a75277844f81511fdc02e26b588539e92f92b Mon Sep 17 00:00:00 2001 From: Ran Mishael <106548467+ranlavanet@users.noreply.github.com> Date: Mon, 18 Dec 2023 10:06:45 +0100 Subject: [PATCH 75/85] PRT-1046 Adding error handling and timeout parsing for better UX for the user. (#1048) * adding error handling and timeout parsing for better UX for the user. * splitting stake size fetching and cu addition. changed lock to RW mutex * Changed to private * creating zero dec upon failing to compute or nil qos * adding generics max value type, and changing error threshold to be 50% for string comparison * lint fix * fix majority test --- protocol/common/endpoints.go | 11 +- .../lavasession/consumer_session_manager.go | 9 +- protocol/lavasession/consumer_types.go | 58 +++- protocol/rpcconsumer/relay_errors.go | 59 +++++ protocol/rpcconsumer/relay_errors_test.go | 249 ++++++++++++++++++ protocol/rpcconsumer/rpcconsumer_server.go | 57 ++-- .../reliability_manager_test.go | 40 +-- protocol/statetracker/pairing_updater.go | 17 +- utils/maps/maps.go | 17 ++ 9 files changed, 446 insertions(+), 71 deletions(-) create mode 100644 protocol/rpcconsumer/relay_errors.go create mode 100644 protocol/rpcconsumer/relay_errors_test.go create mode 100644 utils/maps/maps.go diff --git a/protocol/common/endpoints.go b/protocol/common/endpoints.go index eebb971dde..82013c2f78 100644 --- a/protocol/common/endpoints.go +++ b/protocol/common/endpoints.go @@ -7,6 +7,7 @@ import ( "strings" "time" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/utils" "github.com/lavanet/lava/utils/sigs" pairingtypes "github.com/lavanet/lava/x/pairing/types" @@ -173,10 +174,16 @@ type ConflictHandlerInterface interface { StoreConflictReported() } +type ProviderInfo struct { + ProviderAddress string + ProviderQoSExcellenceSummery sdk.Dec // the number represents the average qos for this provider session + ProviderStake sdk.Coin +} + type RelayResult struct { Request *pairingtypes.RelayRequest Reply *pairingtypes.RelayReply - ProviderAddress string + ProviderInfo ProviderInfo ReplyServer *pairingtypes.Relayer_RelaySubscribeClient Finalized bool ConflictHandler ConflictHandlerInterface @@ -208,7 +215,7 @@ func (rr *RelayResult) GetProvider() string { if rr == nil { return "" } - return rr.ProviderAddress + return rr.ProviderInfo.ProviderAddress } func GetIpFromGrpcContext(ctx context.Context) string { diff --git a/protocol/lavasession/consumer_session_manager.go b/protocol/lavasession/consumer_session_manager.go index e001faf6de..b6784b4441 100644 --- a/protocol/lavasession/consumer_session_manager.go +++ b/protocol/lavasession/consumer_session_manager.go @@ -426,13 +426,20 @@ func (csm *ConsumerSessionManager) GetSessions(ctx context.Context, cuNeededForS utils.Attribute{Key: "consumerSession.SessionId", Value: consumerSession.SessionId}, ) } + // If no error, add provider session map - sessions[providerAddress] = &SessionInfo{ + sessionInfo := &SessionInfo{ + StakeSize: consumerSessionsWithProvider.getProviderStakeSize(), Session: consumerSession, Epoch: sessionEpoch, ReportedProviders: reportedProviders, } + // adding qos summery for error parsing. + // consumer session is locked here so its ok to read the qos report. + sessionInfo.QoSSummeryResult = consumerSession.getQosComputedResultOrZero() + sessions[providerAddress] = sessionInfo + if consumerSession.RelayNum > 1 { // we only set excellence for sessions with more than one successful relays, this guarantees data within the epoch exists consumerSession.QoSInfo.LastExcellenceQoSReport = csm.providerOptimizer.GetExcellenceQoSReportForProvider(providerAddress) diff --git a/protocol/lavasession/consumer_types.go b/protocol/lavasession/consumer_types.go index 8a9c66ba7a..720b71d482 100644 --- a/protocol/lavasession/consumer_types.go +++ b/protocol/lavasession/consumer_types.go @@ -5,6 +5,7 @@ import ( "math" "sort" "strconv" + "sync" "sync/atomic" "time" @@ -24,6 +25,8 @@ var AllowInsecureConnectionToProviders = false type SessionInfo struct { Session *SingleConsumerSession + StakeSize sdk.Coin + QoSSummeryResult sdk.Dec // using ComputeQoS to get the total QOS Epoch uint64 ReportedProviders []*pairingtypes.ReportedProvider } @@ -120,7 +123,7 @@ func (rpce *RPCEndpoint) Key() string { } type ConsumerSessionsWithProvider struct { - Lock utils.LavaMutex + Lock sync.RWMutex PublicLavaAddress string Endpoints []*Endpoint Sessions map[int64]*SingleConsumerSession @@ -128,7 +131,19 @@ type ConsumerSessionsWithProvider struct { UsedComputeUnits uint64 PairingEpoch uint64 // whether we already reported this provider this epoch, we can only report one conflict per provider per epoch - conflictFoundAndReported uint32 // 0 == not reported, 1 == reported + conflictFoundAndReported uint32 // 0 == not reported, 1 == reported + stakeSize sdk.Coin // the stake size the provider staked +} + +func NewConsumerSessionWithProvider(publicLavaAddress string, pairingEndpoints []*Endpoint, maxCu uint64, epoch uint64, stakeSize sdk.Coin) *ConsumerSessionsWithProvider { + return &ConsumerSessionsWithProvider{ + PublicLavaAddress: publicLavaAddress, + Endpoints: pairingEndpoints, + Sessions: map[int64]*SingleConsumerSession{}, + MaxComputeUnits: maxCu, + PairingEpoch: epoch, + stakeSize: stakeSize, + } } func (cswp *ConsumerSessionsWithProvider) atomicReadConflictReported() bool { @@ -151,8 +166,8 @@ func (cswp *ConsumerSessionsWithProvider) StoreConflictReported() { } func (cswp *ConsumerSessionsWithProvider) IsSupportingAddon(addon string) bool { - cswp.Lock.Lock() - defer cswp.Lock.Unlock() + cswp.Lock.RLock() + defer cswp.Lock.RUnlock() if addon == "" { return true } @@ -165,8 +180,8 @@ func (cswp *ConsumerSessionsWithProvider) IsSupportingAddon(addon string) bool { } func (cswp *ConsumerSessionsWithProvider) IsSupportingExtensions(extensions []string) bool { - cswp.Lock.Lock() - defer cswp.Lock.Unlock() + cswp.Lock.RLock() + defer cswp.Lock.RUnlock() endpointLoop: for _, endpoint := range cswp.Endpoints { for _, extension := range extensions { @@ -187,8 +202,8 @@ func (cswp *ConsumerSessionsWithProvider) atomicReadUsedComputeUnits() uint64 { // verify data reliability session exists or not func (cswp *ConsumerSessionsWithProvider) verifyDataReliabilitySessionWasNotAlreadyCreated() (singleConsumerSession *SingleConsumerSession, pairingEpoch uint64, err error) { - cswp.Lock.Lock() - defer cswp.Lock.Unlock() + cswp.Lock.RLock() + defer cswp.Lock.RUnlock() if dataReliabilitySession, ok := cswp.Sessions[DataReliabilitySessionId]; ok { // check if we already have a data reliability session. // validate our relay number reached the data reliability relay number limit if dataReliabilitySession.RelayNum >= DataReliabilityRelayNumber { @@ -230,15 +245,15 @@ func (cswp *ConsumerSessionsWithProvider) GetPairingEpoch() uint64 { } func (cswp *ConsumerSessionsWithProvider) getPublicLavaAddressAndPairingEpoch() (string, uint64) { - cswp.Lock.Lock() // TODO: change to RLock when LavaMutex is changed - defer cswp.Lock.Unlock() + cswp.Lock.RLock() + defer cswp.Lock.RUnlock() return cswp.PublicLavaAddress, cswp.PairingEpoch } // Validate the compute units for this provider func (cswp *ConsumerSessionsWithProvider) validateComputeUnits(cu uint64, virtualEpoch uint64) error { - cswp.Lock.Lock() - defer cswp.Lock.Unlock() + cswp.Lock.RLock() + defer cswp.Lock.RUnlock() // add additional CU for virtual epochs if (cswp.UsedComputeUnits + cu) > cswp.MaxComputeUnits*(virtualEpoch+1) { return utils.LavaFormatWarning("validateComputeUnits", MaxComputeUnitsExceededError, @@ -262,6 +277,13 @@ func (cswp *ConsumerSessionsWithProvider) addUsedComputeUnits(cu, virtualEpoch u return nil } +// Validate and add the compute units for this provider +func (cswp *ConsumerSessionsWithProvider) getProviderStakeSize() sdk.Coin { + cswp.Lock.RLock() + defer cswp.Lock.RUnlock() + return cswp.stakeSize +} + // Validate and add the compute units for this provider func (cswp *ConsumerSessionsWithProvider) decreaseUsedComputeUnits(cu uint64) error { cswp.Lock.Lock() @@ -440,6 +462,18 @@ func (cs *SingleConsumerSession) CalculateExpectedLatency(timeoutGivenToRelay ti return expectedLatency } +// cs should be locked here to use this method, returns the computed qos or zero if last qos is nil or failed to compute. +func (cs *SingleConsumerSession) getQosComputedResultOrZero() sdk.Dec { + if cs.QoSInfo.LastExcellenceQoSReport != nil { + qosComputed, errComputing := cs.QoSInfo.LastExcellenceQoSReport.ComputeQoS() + if errComputing == nil { // if we failed to compute the qos will be 0 so this provider wont be picked to return the error in case we get it + return qosComputed + } + utils.LavaFormatError("Failed computing QoS used for error parsing", errComputing, utils.LogAttr("Report", cs.QoSInfo.LastExcellenceQoSReport)) + } + return sdk.ZeroDec() +} + func (cs *SingleConsumerSession) CalculateQoS(latency, expectedLatency time.Duration, blockHeightDiff int64, numOfProviders int, servicersToCount int64) { // Add current Session QoS cs.QoSInfo.TotalRelays++ // increase total relays diff --git a/protocol/rpcconsumer/relay_errors.go b/protocol/rpcconsumer/relay_errors.go new file mode 100644 index 0000000000..1865c74e1a --- /dev/null +++ b/protocol/rpcconsumer/relay_errors.go @@ -0,0 +1,59 @@ +package rpcconsumer + +import ( + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + "github.com/lavanet/lava/protocol/common" + "github.com/lavanet/lava/utils" + "github.com/lavanet/lava/utils/maps" +) + +type RelayErrors struct { + relayErrors []RelayError +} + +func (r *RelayErrors) GetBestErrorMessageForUser() utils.Attribute { + bestIndex := -1 + bestResult := github_com_cosmos_cosmos_sdk_types.ZeroDec() + errorMap := make(map[string]int) + for idx, relayError := range r.relayErrors { + errorMessage := relayError.err.Error() + errorMap[errorMessage]++ + if relayError.ProviderInfo.ProviderQoSExcellenceSummery.IsNil() || relayError.ProviderInfo.ProviderStake.Amount.IsNil() { + continue + } + currentResult := relayError.ProviderInfo.ProviderQoSExcellenceSummery.MulInt(relayError.ProviderInfo.ProviderStake.Amount) + if currentResult.GTE(bestResult) { // 0 or 1 here are valid replacements, so even 0 scores will return the error value + bestResult.Set(currentResult) + bestIndex = idx + } + } + + errorKey, errorCount := maps.FindLargestIntValueInMap(errorMap) + if errorCount >= (len(r.relayErrors) / 2) { + // we have majority of errors we can return this error. + return utils.LogAttr("error", errorKey) + } + + if bestIndex != -1 { + // Return the chosen error. + // Print info for the consumer to know which errors happened + utils.LavaFormatInfo("Failed all relays", utils.LogAttr("error_map", errorMap)) + return utils.LogAttr("error", r.relayErrors[bestIndex].err.Error()) + } + // if we didn't manage to find any index return all. + utils.LavaFormatError("Failed finding the best error index in GetErrorMessageForUser", nil, utils.LogAttr("relayErrors", r.relayErrors)) + return utils.LogAttr("errors", r.getAllErrors()) +} + +func (r *RelayErrors) getAllErrors() []error { + allErrors := make([]error, len(r.relayErrors)) + for idx, relayError := range r.relayErrors { + allErrors[idx] = relayError.err + } + return allErrors +} + +type RelayError struct { + err error + ProviderInfo common.ProviderInfo +} diff --git a/protocol/rpcconsumer/relay_errors_test.go b/protocol/rpcconsumer/relay_errors_test.go new file mode 100644 index 0000000000..06659a21f5 --- /dev/null +++ b/protocol/rpcconsumer/relay_errors_test.go @@ -0,0 +1,249 @@ +package rpcconsumer + +import ( + "fmt" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/lavanet/lava/protocol/common" + "github.com/stretchr/testify/require" +) + +func TestRelayError(t *testing.T) { + expectedValue := "Expected Error" + testStruct := []struct { + name string + relayErrors RelayErrors + }{ + { + name: "test stake majority error reply", + relayErrors: RelayErrors{ + relayErrors: []RelayError{ + { + err: fmt.Errorf("test1"), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.OneDec(), + ProviderStake: sdk.NewInt64Coin("ulava", 10), + }, + }, + { + err: fmt.Errorf("test2"), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.OneDec(), + ProviderStake: sdk.NewInt64Coin("ulava", 20), + }, + }, + { + err: fmt.Errorf("test3"), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.OneDec(), + ProviderStake: sdk.NewInt64Coin("ulava", 30), + }, + }, + { + err: fmt.Errorf("test4"), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.OneDec(), + ProviderStake: sdk.NewInt64Coin("ulava", 40), + }, + }, + { + err: fmt.Errorf(expectedValue), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.OneDec(), + ProviderStake: sdk.NewInt64Coin("ulava", 50), + }, + }, + }, + }, + }, + { + name: "test qos majority error reply", + relayErrors: RelayErrors{ + relayErrors: []RelayError{ + { + err: fmt.Errorf("test1"), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.MustNewDecFromStr("0.5"), + ProviderStake: sdk.NewInt64Coin("ulava", 10), + }, + }, + { + err: fmt.Errorf("test1"), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.MustNewDecFromStr("0.25"), + ProviderStake: sdk.NewInt64Coin("ulava", 10), + }, + }, + { + err: fmt.Errorf("test3"), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.MustNewDecFromStr("0.6"), + ProviderStake: sdk.NewInt64Coin("ulava", 10), + }, + }, + { + err: fmt.Errorf("test3"), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.MustNewDecFromStr("0.7"), + ProviderStake: sdk.NewInt64Coin("ulava", 10), + }, + }, + { + err: fmt.Errorf("test4"), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.MustNewDecFromStr("0.7"), + ProviderStake: sdk.NewInt64Coin("ulava", 10), + }, + }, + { + err: fmt.Errorf("test4"), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.MustNewDecFromStr("0.7"), + ProviderStake: sdk.NewInt64Coin("ulava", 10), + }, + }, + { + err: fmt.Errorf(expectedValue), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.MustNewDecFromStr("0.8"), + ProviderStake: sdk.NewInt64Coin("ulava", 10), + }, + }, + }, + }, + }, + { + name: "test text majority over score majority", + relayErrors: RelayErrors{ + relayErrors: []RelayError{ + { + err: fmt.Errorf("test1"), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.OneDec(), + ProviderStake: sdk.NewInt64Coin("ulava", 1000), + }, + }, + { + err: fmt.Errorf("test2"), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.OneDec(), + ProviderStake: sdk.NewInt64Coin("ulava", 1000), + }, + }, + { + err: fmt.Errorf(expectedValue), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.ZeroDec(), + ProviderStake: sdk.NewInt64Coin("ulava", 0), + }, + }, + { + err: fmt.Errorf(expectedValue), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.ZeroDec(), + ProviderStake: sdk.NewInt64Coin("ulava", 0), + }, + }, + { + err: fmt.Errorf(expectedValue), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.ZeroDec(), + ProviderStake: sdk.NewInt64Coin("ulava", 0), + }, + }, + }, + }, + }, + { + name: "test majority of error body", + relayErrors: RelayErrors{ + relayErrors: []RelayError{ + { + err: fmt.Errorf(expectedValue), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.OneDec(), + ProviderStake: sdk.NewInt64Coin("ulava", 10), + }, + }, + { + err: fmt.Errorf(expectedValue), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.OneDec(), + ProviderStake: sdk.NewInt64Coin("ulava", 20), + }, + }, + { + err: fmt.Errorf("test3"), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.OneDec(), + ProviderStake: sdk.NewInt64Coin("ulava", 30), + }, + }, + { + err: fmt.Errorf("test4"), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.OneDec(), + ProviderStake: sdk.NewInt64Coin("ulava", 40), + }, + }, + { + err: fmt.Errorf(expectedValue), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.OneDec(), + ProviderStake: sdk.NewInt64Coin("ulava", 10), + }, + }, + }, + }, + }, + { + name: "test no majority and no dec", + relayErrors: RelayErrors{ + relayErrors: []RelayError{ + { + err: fmt.Errorf(expectedValue), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.OneDec(), + ProviderStake: sdk.NewInt64Coin("ulava", 10), + }, + }, + { + err: fmt.Errorf(expectedValue), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.OneDec(), + ProviderStake: sdk.NewInt64Coin("ulava", 20), + }, + }, + { + err: fmt.Errorf("test3"), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.OneDec(), + ProviderStake: sdk.NewInt64Coin("ulava", 30), + }, + }, + { + err: fmt.Errorf("test4"), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.OneDec(), + ProviderStake: sdk.NewInt64Coin("ulava", 40), + }, + }, + { + err: fmt.Errorf(expectedValue), + ProviderInfo: common.ProviderInfo{ + ProviderQoSExcellenceSummery: sdk.OneDec(), + ProviderStake: sdk.NewInt64Coin("ulava", 10), + }, + }, + }, + }, + }, + } + for _, te := range testStruct { + t.Run(te.name, func(t *testing.T) { + result := te.relayErrors.GetBestErrorMessageForUser() + require.Equal(t, result.Value, expectedValue) + }) + } +} diff --git a/protocol/rpcconsumer/rpcconsumer_server.go b/protocol/rpcconsumer/rpcconsumer_server.go index 4c2e122375..c94ea7a845 100644 --- a/protocol/rpcconsumer/rpcconsumer_server.go +++ b/protocol/rpcconsumer/rpcconsumer_server.go @@ -157,15 +157,15 @@ func (rpccs *RPCConsumerServer) sendInitialRelays(count int) { relayResult, err := rpccs.sendRelayToProvider(ctx, chainMessage, relayRequestData, "-init-", "", &unwantedProviders, timeouts) if err != nil { utils.LavaFormatError("[-] failed sending init relay", err, []utils.Attribute{{Key: "chainID", Value: rpccs.listenEndpoint.ChainID}, {Key: "APIInterface", Value: rpccs.listenEndpoint.ApiInterface}, {Key: "unwantedProviders", Value: unwantedProviders}}...) - if relayResult != nil && relayResult.ProviderAddress != "" { - unwantedProviders[relayResult.ProviderAddress] = struct{}{} + if relayResult != nil && relayResult.ProviderInfo.ProviderAddress != "" { + unwantedProviders[relayResult.ProviderInfo.ProviderAddress] = struct{}{} } if common.IsTimeout(err) { timeouts++ } } else { unwantedProviders = map[string]struct{}{} - utils.LavaFormatInfo("[+] init relay succeeded", []utils.Attribute{{Key: "chainID", Value: rpccs.listenEndpoint.ChainID}, {Key: "APIInterface", Value: rpccs.listenEndpoint.ApiInterface}, {Key: "latestBlock", Value: relayResult.Reply.LatestBlock}, {Key: "provider address", Value: relayResult.ProviderAddress}}...) + utils.LavaFormatInfo("[+] init relay succeeded", []utils.Attribute{{Key: "chainID", Value: rpccs.listenEndpoint.ChainID}, {Key: "APIInterface", Value: rpccs.listenEndpoint.ApiInterface}, {Key: "latestBlock", Value: relayResult.Reply.LatestBlock}, {Key: "provider address", Value: relayResult.ProviderInfo.ProviderAddress}}...) } time.Sleep(2 * time.Millisecond) } @@ -208,7 +208,7 @@ func (rpccs *RPCConsumerServer) SendRelay( // temporarily disable subscriptions isSubscription := chainlib.IsSubscription(chainMessage) if isSubscription { - return &common.RelayResult{ProviderAddress: ""}, utils.LavaFormatError("Subscriptions are not supported at the moment", nil) + return &common.RelayResult{ProviderInfo: common.ProviderInfo{ProviderAddress: ""}}, utils.LavaFormatError("Subscriptions are not supported at the moment", nil) } rpccs.HandleDirectiveHeadersForMessage(chainMessage, directiveHeaders) @@ -226,7 +226,7 @@ func (rpccs *RPCConsumerServer) SendRelay( } relayRequestData := lavaprotocol.NewRelayData(ctx, connectionType, url, []byte(req), seenBlock, reqBlock, rpccs.listenEndpoint.ApiInterface, chainMessage.GetRPCMessage().GetHeaders(), chainlib.GetAddon(chainMessage), common.GetExtensionNames(chainMessage.GetExtensions())) relayResults := []*common.RelayResult{} - relayErrors := []error{} + relayErrors := &RelayErrors{} blockOnSyncLoss := map[string]struct{}{} modifiedOnLatestReq := false errorRelayResult := &common.RelayResult{} // returned on error @@ -236,20 +236,20 @@ func (rpccs *RPCConsumerServer) SendRelay( for ; retries < MaxRelayRetries; retries++ { // TODO: make this async between different providers relayResult, err := rpccs.sendRelayToProvider(ctx, chainMessage, relayRequestData, dappID, consumerIp, &unwantedProviders, timeouts) - if relayResult.ProviderAddress != "" { + if relayResult.ProviderInfo.ProviderAddress != "" { if err != nil { // add this provider to the erroring providers - if errorRelayResult.ProviderAddress != "" { - errorRelayResult.ProviderAddress += "," + if errorRelayResult.ProviderInfo.ProviderAddress != "" { + errorRelayResult.ProviderInfo.ProviderAddress += "," } - errorRelayResult.ProviderAddress += relayResult.ProviderAddress - _, ok := blockOnSyncLoss[relayResult.ProviderAddress] + errorRelayResult.ProviderInfo.ProviderAddress += relayResult.ProviderInfo.ProviderAddress + _, ok := blockOnSyncLoss[relayResult.ProviderInfo.ProviderAddress] if !ok && lavasession.IsSessionSyncLoss(err) { // allow this provider to be wantedProvider on a retry, if it didnt fail once on syncLoss - blockOnSyncLoss[relayResult.ProviderAddress] = struct{}{} - utils.LavaFormatWarning("Identified SyncLoss in provider, not removing it from list for another attempt", err, utils.Attribute{Key: "address", Value: relayResult.ProviderAddress}) + blockOnSyncLoss[relayResult.ProviderInfo.ProviderAddress] = struct{}{} + utils.LavaFormatWarning("Identified SyncLoss in provider, not removing it from list for another attempt", err, utils.Attribute{Key: "address", Value: relayResult.ProviderInfo.ProviderAddress}) } else { - unwantedProviders[relayResult.ProviderAddress] = struct{}{} + unwantedProviders[relayResult.ProviderInfo.ProviderAddress] = struct{}{} } if common.IsTimeout(err) { timeouts++ @@ -261,7 +261,7 @@ func (rpccs *RPCConsumerServer) SendRelay( // keep the error status code errorRelayResult.StatusCode = relayResult.GetStatusCode() } - relayErrors = append(relayErrors, err) + relayErrors.relayErrors = append(relayErrors.relayErrors, RelayError{err: err, ProviderInfo: relayResult.ProviderInfo}) if lavasession.PairingListEmptyError.Is(err) { // if we ran out of pairings because unwantedProviders is too long or validProviders is too short, continue to reply handling code break @@ -271,7 +271,7 @@ func (rpccs *RPCConsumerServer) SendRelay( continue } relayResults = append(relayResults, relayResult) - unwantedProviders[relayResult.ProviderAddress] = struct{}{} + unwantedProviders[relayResult.ProviderInfo.ProviderAddress] = struct{}{} // future relay requests and data reliability requests need to ask for the same specific block height to get consensus on the reply // we do not modify the chain message data on the consumer, only it's requested block, so we let the provider know it can't put any block height it wants by setting a specific block height reqBlock, _ := chainMessage.RequestedBlock() @@ -300,11 +300,15 @@ func (rpccs *RPCConsumerServer) SendRelay( } } - // TODO: secure, go over relay results to find discrepancies and choose majority, or trigger a second wallet relay if len(relayResults) == 0 { rpccs.appendHeadersToRelayResult(ctx, errorRelayResult, retries) - return errorRelayResult, utils.LavaFormatError("Failed all retries", nil, utils.Attribute{Key: "GUID", Value: ctx}, utils.Attribute{Key: "errors", Value: relayErrors}) - } else if len(relayErrors) > 0 { + // suggest the user to add the timeout flag + if uint64(timeouts) == retries { + utils.LavaFormatDebug("all relays timeout", utils.Attribute{Key: "GUID", Value: ctx}, utils.Attribute{Key: "errors", Value: relayErrors.relayErrors}) + return errorRelayResult, utils.LavaFormatError("Failed all relay retries due to timeout consider adding 'lava-relay-timeout' header to extend the allowed timeout duration", nil, utils.Attribute{Key: "GUID", Value: ctx}) + } + return errorRelayResult, utils.LavaFormatError("Failed all retries", nil, utils.Attribute{Key: "GUID", Value: ctx}, relayErrors.GetBestErrorMessageForUser()) + } else if len(relayErrors.relayErrors) > 0 { utils.LavaFormatDebug("relay succeeded but had some errors", utils.Attribute{Key: "GUID", Value: ctx}, utils.Attribute{Key: "errors", Value: relayErrors}) } var returnedResult *common.RelayResult @@ -350,7 +354,7 @@ func (rpccs *RPCConsumerServer) sendRelayToProvider( if isSubscription { // temporarily disable subscriptions // TODO: fix subscription and disable this case. - return &common.RelayResult{ProviderAddress: ""}, utils.LavaFormatError("Subscriptions are disabled currently", nil) + return &common.RelayResult{ProviderInfo: common.ProviderInfo{ProviderAddress: ""}}, utils.LavaFormatError("Subscriptions are disabled currently", nil) } privKey := rpccs.privKey @@ -367,7 +371,7 @@ func (rpccs *RPCConsumerServer) sendRelayToProvider( virtualEpoch := rpccs.consumerTxSender.GetLatestVirtualEpoch() sessions, err := rpccs.consumerSessionManager.GetSessions(ctx, chainlib.GetComputeUnits(chainMessage), *unwantedProviders, reqBlock, chainlib.GetAddon(chainMessage), chainMessage.GetExtensions(), chainlib.GetStateful(chainMessage), virtualEpoch) if err != nil { - return &common.RelayResult{ProviderAddress: ""}, err + return &common.RelayResult{ProviderInfo: common.ProviderInfo{ProviderAddress: ""}}, err } type relayResponse struct { @@ -399,10 +403,9 @@ func (rpccs *RPCConsumerServer) sendRelayToProvider( // Close context goroutineCtxCancel() }() - localRelayResult = &common.RelayResult{ - ProviderAddress: providerPublicAddress, - Finalized: false, + ProviderInfo: common.ProviderInfo{ProviderAddress: providerPublicAddress, ProviderStake: sessionInfo.StakeSize, ProviderQoSExcellenceSummery: sessionInfo.QoSSummeryResult}, + Finalized: false, // setting the single consumer session as the conflict handler. // to be able to validate if we need to report this provider or not. // holding the pointer is ok because the session is locked atm, @@ -567,7 +570,7 @@ func (rpccs *RPCConsumerServer) sendRelayToProvider( func (rpccs *RPCConsumerServer) relayInner(ctx context.Context, singleConsumerSession *lavasession.SingleConsumerSession, relayResult *common.RelayResult, relayTimeout time.Duration, chainMessage chainlib.ChainMessage, consumerToken string) (relayResultRet *common.RelayResult, relayLatency time.Duration, err error, needsBackoff bool) { existingSessionLatestBlock := singleConsumerSession.LatestBlock // we read it now because singleConsumerSession is locked, and later it's not endpointClient := *singleConsumerSession.Endpoint.Client - providerPublicAddress := relayResult.ProviderAddress + providerPublicAddress := relayResult.ProviderInfo.ProviderAddress relayRequest := relayResult.Request callRelay := func() (reply *pairingtypes.RelayReply, relayLatency time.Duration, err error, backoff bool) { relaySentTime := time.Now() @@ -699,14 +702,14 @@ func (rpccs *RPCConsumerServer) sendDataReliabilityRelayIfApplicable(ctx context if err != nil { errAttributes := []utils.Attribute{} // failed to send to a provider - if relayResultDataReliability.ProviderAddress != "" { - errAttributes = append(errAttributes, utils.Attribute{Key: "address", Value: relayResultDataReliability.ProviderAddress}) + if relayResultDataReliability.ProviderInfo.ProviderAddress != "" { + errAttributes = append(errAttributes, utils.Attribute{Key: "address", Value: relayResultDataReliability.ProviderInfo.ProviderAddress}) } errAttributes = append(errAttributes, utils.Attribute{Key: "relayRequestData", Value: relayRequestData}) return utils.LavaFormatWarning("failed data reliability relay to provider", err, errAttributes...) } if !relayResultDataReliability.Finalized { - utils.LavaFormatInfo("skipping data reliability check since response from second provider was not finalized", utils.Attribute{Key: "providerAddress", Value: relayResultDataReliability.ProviderAddress}) + utils.LavaFormatInfo("skipping data reliability check since response from second provider was not finalized", utils.Attribute{Key: "providerAddress", Value: relayResultDataReliability.ProviderInfo.ProviderAddress}) return nil } conflict := lavaprotocol.VerifyReliabilityResults(ctx, relayResult, relayResultDataReliability, chainMessage.GetApiCollection(), rpccs.chainParser) diff --git a/protocol/rpcprovider/reliabilitymanager/reliability_manager_test.go b/protocol/rpcprovider/reliabilitymanager/reliability_manager_test.go index 7c43d62dd4..289de56adb 100644 --- a/protocol/rpcprovider/reliabilitymanager/reliability_manager_test.go +++ b/protocol/rpcprovider/reliabilitymanager/reliability_manager_test.go @@ -98,11 +98,11 @@ func TestFullFlowReliabilityCompare(t *testing.T) { require.NoError(t, err) relayResult := &common.RelayResult{ - Request: relay, - Reply: reply, - ProviderAddress: provider_address.String(), - ReplyServer: nil, - Finalized: true, + Request: relay, + Reply: reply, + ProviderInfo: common.ProviderInfo{ProviderAddress: provider_address.String()}, + ReplyServer: nil, + Finalized: true, } // now send this to another provider @@ -130,11 +130,11 @@ func TestFullFlowReliabilityCompare(t *testing.T) { _, _, err = lavaprotocol.VerifyFinalizationData(replyDR, relayDR, providerDR_address.String(), consumer_address, int64(0), 0) require.NoError(t, err) relayResultDR := &common.RelayResult{ - Request: relayDR, - Reply: replyDR, - ProviderAddress: providerDR_address.String(), - ReplyServer: nil, - Finalized: true, + Request: relayDR, + Reply: replyDR, + ProviderInfo: common.ProviderInfo{ProviderAddress: provider_address.String()}, + ReplyServer: nil, + Finalized: true, } conflict := lavaprotocol.VerifyReliabilityResults(ctx, relayResult, relayResultDR, nil, mockFilter{}) @@ -255,11 +255,11 @@ func TestFullFlowReliabilityConflict(t *testing.T) { require.NoError(t, err) relayResult := &common.RelayResult{ - Request: relay, - Reply: reply, - ProviderAddress: provider_address.String(), - ReplyServer: nil, - Finalized: true, + Request: relay, + Reply: reply, + ProviderInfo: common.ProviderInfo{ProviderAddress: provider_address.String()}, + ReplyServer: nil, + Finalized: true, } relayExchange := pairingtypes.NewRelayExchange(*relay, *reply) @@ -292,11 +292,11 @@ func TestFullFlowReliabilityConflict(t *testing.T) { _, _, err = lavaprotocol.VerifyFinalizationData(replyDR, relayDR, providerDR_address.String(), consumer_address, int64(0), 0) require.NoError(t, err) relayResultDR := &common.RelayResult{ - Request: relayDR, - Reply: replyDR, - ProviderAddress: providerDR_address.String(), - ReplyServer: nil, - Finalized: true, + Request: relayDR, + Reply: replyDR, + ProviderInfo: common.ProviderInfo{ProviderAddress: provider_address.String()}, + ReplyServer: nil, + Finalized: true, } conflict := lavaprotocol.VerifyReliabilityResults(ts.Ctx, relayResult, relayResultDR, chainMessage.GetApiCollection(), chainParser) diff --git a/protocol/statetracker/pairing_updater.go b/protocol/statetracker/pairing_updater.go index e53a01bc4c..7eb12d9115 100644 --- a/protocol/statetracker/pairing_updater.go +++ b/protocol/statetracker/pairing_updater.go @@ -153,7 +153,7 @@ func (pu *PairingUpdater) filterPairingListByEndpoint(ctx context.Context, curre continue } - maxcu, err := pu.stateQuery.GetMaxCUForUser(ctx, provider.Chain, epoch) + maxCu, err := pu.stateQuery.GetMaxCUForUser(ctx, provider.Chain, epoch) if err != nil { return nil, err } @@ -173,14 +173,13 @@ func (pu *PairingUpdater) filterPairingListByEndpoint(ctx context.Context, curre pairingEndpoints[idx] = endp } lavasession.SortByGeolocations(pairingEndpoints, currentGeo) - - pairing[uint64(providerIdx)] = &lavasession.ConsumerSessionsWithProvider{ - PublicLavaAddress: provider.Address, - Endpoints: pairingEndpoints, - Sessions: map[int64]*lavasession.SingleConsumerSession{}, - MaxComputeUnits: maxcu, - PairingEpoch: epoch, - } + pairing[uint64(providerIdx)] = lavasession.NewConsumerSessionWithProvider( + provider.Address, + pairingEndpoints, + maxCu, + epoch, + provider.Stake, + ) } if len(pairing) == 0 { return nil, utils.LavaFormatError("Failed getting pairing for consumer, pairing is empty", err, utils.Attribute{Key: "apiInterface", Value: rpcEndpoint.ApiInterface}, utils.Attribute{Key: "ChainID", Value: rpcEndpoint.ChainID}, utils.Attribute{Key: "geolocation", Value: rpcEndpoint.Geolocation}) diff --git a/utils/maps/maps.go b/utils/maps/maps.go new file mode 100644 index 0000000000..35ed70e593 --- /dev/null +++ b/utils/maps/maps.go @@ -0,0 +1,17 @@ +package maps + +func FindLargestIntValueInMap[K comparable](myMap map[K]int) (K, int) { + var maxVal int + var maxKey K + firstIteration := true + + for key, val := range myMap { + if firstIteration || val > maxVal { + maxVal = val + maxKey = key + firstIteration = false + } + } + + return maxKey, maxVal +} From caadd1940431569b90803c007658e9d48eb9ac4a Mon Sep 17 00:00:00 2001 From: Ran Mishael <106548467+ranlavanet@users.noreply.github.com> Date: Mon, 18 Dec 2023 11:07:09 +0100 Subject: [PATCH 76/85] PRT-1050 adding reward unified delay (#1050) * adding reward unified delay * fix reward server test * prettify --- protocol/common/tx_parsing.go | 1 + .../rpcprovider/rewardserver/reward_server.go | 30 +++++++++++++++++-- .../rewardserver/reward_server_test.go | 24 +++++++++++---- protocol/rpcprovider/rpcprovider.go | 1 + .../statetracker/provider_state_tracker.go | 5 ++++ protocol/statetracker/state_tracker.go | 15 ++++++++++ protocol/statetracker/tx_sender.go | 3 +- .../pre_setups/init_evmos_only_with_node.sh | 2 +- .../pre_setups/init_lava_only_with_node.sh | 2 +- utils/rand/rand.go | 4 +++ x/protocol/types/params.go | 2 +- 11 files changed, 77 insertions(+), 12 deletions(-) diff --git a/protocol/common/tx_parsing.go b/protocol/common/tx_parsing.go index 0088723c15..5572049497 100644 --- a/protocol/common/tx_parsing.go +++ b/protocol/common/tx_parsing.go @@ -28,6 +28,7 @@ type TxResultData struct { func ParseTransactionResult(parsedValues map[string]any) (retData TxResultData, err error) { ret := TxResultData{} + utils.LavaFormatDebug("result", utils.LogAttr("parsedValues", parsedValues)) txHash, ok := parsedValues["txhash"] if ok { txHashStr, ok := txHash.(string) diff --git a/protocol/rpcprovider/rewardserver/reward_server.go b/protocol/rpcprovider/rewardserver/reward_server.go index 4c2536023f..7006609774 100644 --- a/protocol/rpcprovider/rewardserver/reward_server.go +++ b/protocol/rpcprovider/rewardserver/reward_server.go @@ -95,6 +95,9 @@ type RewardsTxSender interface { TxRelayPayment(ctx context.Context, relayRequests []*pairingtypes.RelaySession, description string, latestBlocks []*pairingtypes.LatestBlockReport) error GetEpochSizeMultipliedByRecommendedEpochNumToCollectPayment(ctx context.Context) (uint64, error) EarliestBlockInMemory(ctx context.Context) (uint64, error) + GetEpochSize(ctx context.Context) (uint64, error) + LatestBlock() int64 + GetAverageBlockTime() time.Duration } type ChainTrackerSpecsInf interface { @@ -153,9 +156,32 @@ func (rws *RewardServer) saveProofInMemory(ctx context.Context, consumerRewardsK } func (rws *RewardServer) UpdateEpoch(epoch uint64) { + go rws.runRewardServerEpochUpdate(epoch) +} + +func (rws *RewardServer) runRewardServerEpochUpdate(epoch uint64) { ctx := context.Background() - _ = rws.sendRewardsClaim(ctx, epoch) - _, _ = rws.identifyMissingPayments(ctx) + rws.AddRewardDelayForUnifiedRewardDistribution(ctx, epoch) + rws.sendRewardsClaim(ctx, epoch) + rws.identifyMissingPayments(ctx) +} + +func (rws *RewardServer) AddRewardDelayForUnifiedRewardDistribution(ctx context.Context, epochStart uint64) { + epochSize, err := rws.rewardsTxSender.GetEpochSize(ctx) + if err != nil { + utils.LavaFormatError("Failed fetching epoch size in reward server delay, skipping delay", err) + return + } + halfEpochSize := (epochSize / 2) + 1 // +1 for random to choose 0 to number + chosenBlocksForRewardDelay := uint64(rand.Intn(int(halfEpochSize))) + utils.LavaFormatDebug("Waiting for number of blocks to send the reward", utils.LogAttr("blocks_delay", chosenBlocksForRewardDelay)) + for { + latestBlock := rws.rewardsTxSender.LatestBlock() + if uint64(latestBlock)-epochStart >= chosenBlocksForRewardDelay { + return + } + time.Sleep(rws.rewardsTxSender.GetAverageBlockTime()) // sleep the average block time, to wait for the next block. + } } func (rws *RewardServer) sendRewardsClaim(ctx context.Context, epoch uint64) error { diff --git a/protocol/rpcprovider/rewardserver/reward_server_test.go b/protocol/rpcprovider/rewardserver/reward_server_test.go index 73ecbfe9f4..87e3e0bfb7 100644 --- a/protocol/rpcprovider/rewardserver/reward_server_test.go +++ b/protocol/rpcprovider/rewardserver/reward_server_test.go @@ -5,6 +5,7 @@ import ( "os" "strconv" "testing" + "time" "github.com/lavanet/lava/testutil/common" "github.com/lavanet/lava/utils/rand" @@ -266,12 +267,12 @@ func TestUpdateEpoch(t *testing.T) { // Make sure that the rewards are flushed to DB rws.resetSnapshotTimerAndSaveRewardsSnapshotToDB() - rws.UpdateEpoch(1) + rws.runRewardServerEpochUpdate(1) // 2 payments for epoch 1 require.Len(t, stubRewardsTxSender.sentPayments, 2) - rws.UpdateEpoch(2) + rws.runRewardServerEpochUpdate(2) // another 3 payments for epoch 2 require.Len(t, stubRewardsTxSender.sentPayments, 5) @@ -299,8 +300,7 @@ func TestUpdateEpoch(t *testing.T) { stubRewardsTxSender.earliestBlockInMemory = 2 - rws.UpdateEpoch(3) - + rws.runRewardServerEpochUpdate(3) // ensure no payments have been sent require.Len(t, stubRewardsTxSender.sentPayments, 0) rewards, err := db.FindAll() @@ -416,7 +416,7 @@ func TestDeleteRewardsFromDBWhenRewardEpochNotInMemory(t *testing.T) { newEpoch := epoch + 1 stubRewardsTxSender.earliestBlockInMemory = newEpoch - rws.UpdateEpoch(newEpoch) + rws.runRewardServerEpochUpdate(newEpoch) for _, chainId := range specs { epochRewards, err := rewardDB.FindAllInDB(chainId) require.NoError(t, err) @@ -462,7 +462,7 @@ func TestRestoreRewardsFromDB(t *testing.T) { rws.restoreRewardsFromDB(spec) } - rws.UpdateEpoch(epoch + 3) + rws.runRewardServerEpochUpdate(epoch + 3) require.Equal(t, 2, len(stubRewardsTxSender.sentPayments)) } @@ -644,6 +644,18 @@ func (rts *rewardsTxSenderMock) GetEpochSizeMultipliedByRecommendedEpochNumToCol return 0, nil } +func (rts *rewardsTxSenderMock) LatestBlock() int64 { + return 0 +} + +func (rts *rewardsTxSenderMock) GetEpochSize(ctx context.Context) (uint64, error) { + return 0, nil +} + +func (rts *rewardsTxSenderMock) GetAverageBlockTime() time.Duration { + return time.Second +} + func (rts *rewardsTxSenderMock) EarliestBlockInMemory(_ context.Context) (uint64, error) { return rts.earliestBlockInMemory, nil } diff --git a/protocol/rpcprovider/rpcprovider.go b/protocol/rpcprovider/rpcprovider.go index e0c7d4e627..14b13931e3 100644 --- a/protocol/rpcprovider/rpcprovider.go +++ b/protocol/rpcprovider/rpcprovider.go @@ -71,6 +71,7 @@ type ProviderStateTrackerInf interface { GetEpochSizeMultipliedByRecommendedEpochNumToCollectPayment(ctx context.Context) (uint64, error) GetProtocolVersion(ctx context.Context) (*statetracker.ProtocolVersionResponse, error) GetVirtualEpoch(epoch uint64) uint64 + GetAverageBlockTime() time.Duration } type RPCProvider struct { diff --git a/protocol/statetracker/provider_state_tracker.go b/protocol/statetracker/provider_state_tracker.go index 8dd53aa0f4..8db7b79ef6 100644 --- a/protocol/statetracker/provider_state_tracker.go +++ b/protocol/statetracker/provider_state_tracker.go @@ -2,6 +2,7 @@ package statetracker import ( "context" + "time" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/tx" @@ -164,3 +165,7 @@ func (pst *ProviderStateTracker) GetEpochSizeMultipliedByRecommendedEpochNumToCo func (pst *ProviderStateTracker) GetProtocolVersion(ctx context.Context) (*ProtocolVersionResponse, error) { return pst.stateQuery.GetProtocolVersion(ctx) } + +func (pst *ProviderStateTracker) GetAverageBlockTime() time.Duration { + return pst.StateTracker.GetAverageBlockTime() +} diff --git a/protocol/statetracker/state_tracker.go b/protocol/statetracker/state_tracker.go index 7881a697d1..b632d6d9fc 100644 --- a/protocol/statetracker/state_tracker.go +++ b/protocol/statetracker/state_tracker.go @@ -25,6 +25,7 @@ type StateTracker struct { registrationLock sync.RWMutex newLavaBlockUpdaters map[string]Updater EventTracker *EventTracker + AverageBlockTime time.Duration } type Updater interface { @@ -75,10 +76,24 @@ func NewStateTracker(ctx context.Context, txFactory tx.Factory, clientCtx client AverageBlockTime: time.Duration(specResponse.Spec.AverageBlockTime) * time.Millisecond, ServerBlockMemory: 25 + BlocksToSaveLavaChainTracker, } + cst.AverageBlockTime = chainTrackerConfig.AverageBlockTime cst.chainTracker, err = chaintracker.NewChainTracker(ctx, chainFetcher, chainTrackerConfig) + cst.chainTracker.RegisterForBlockTimeUpdates(cst) // registering for block time updates. return cst, err } +func (st *StateTracker) UpdateBlockTime(blockTime time.Duration) { + st.registrationLock.Lock() + defer st.registrationLock.Unlock() + st.AverageBlockTime = blockTime +} + +func (st *StateTracker) GetAverageBlockTime() time.Duration { + st.registrationLock.RLock() + defer st.registrationLock.RUnlock() + return st.AverageBlockTime +} + func (st *StateTracker) newLavaBlock(latestBlock int64, hash string) { // go over the registered updaters and trigger update st.registrationLock.RLock() diff --git a/protocol/statetracker/tx_sender.go b/protocol/statetracker/tx_sender.go index 3d8f51631f..4be0a855b7 100644 --- a/protocol/statetracker/tx_sender.go +++ b/protocol/statetracker/tx_sender.go @@ -221,6 +221,7 @@ func (ts *TxSender) waitForTxCommit(resultData common.TxResultData) (common.TxRe txResultChan <- result return } + utils.LavaFormatDebug("Keep Waiting tx results...", utils.LogAttr("reason", err)) if debug { utils.LavaFormatWarning("Tx query got error", err, utils.Attribute{Key: "GUID", Value: ctx}, utils.Attribute{Key: "resultData", Value: resultData}) } @@ -236,7 +237,7 @@ func (ts *TxSender) waitForTxCommit(resultData common.TxResultData) (common.TxRe } break case <-time.After(5 * time.Minute): - return common.TxResultData{}, utils.LavaFormatError("failed sending tx, wasn't found after timeout", nil, utils.Attribute{Key: "prev resultData", Value: resultData}) + return common.TxResultData{}, utils.LavaFormatError("failed sending tx, wasn't found after timeout", nil, utils.Attribute{Key: "hash", Value: string(resultData.Txhash)}) } // we found the tx on chain and it failed if resultData.Code != 0 { diff --git a/scripts/pre_setups/init_evmos_only_with_node.sh b/scripts/pre_setups/init_evmos_only_with_node.sh index 7731619fb5..2c2e8510af 100755 --- a/scripts/pre_setups/init_evmos_only_with_node.sh +++ b/scripts/pre_setups/init_evmos_only_with_node.sh @@ -20,7 +20,7 @@ echo "[Test Setup] sleeping 20 seconds for node to finish setup (if its not enou sleep 20 GASPRICE="0.000000001ulava" -lavad tx gov submit-legacy-proposal spec-add ./cookbook/specs/spec_add_ibc.json,./cookbook/specs/spec_add_cosmoswasm.json,./cookbook/specs/spec_add_cosmossdk.json,./cookbook/specs/spec_add_cosmossdk_45.json,./cookbook/specs/spec_add_cosmossdk_full.json,./cookbook/specs/spec_add_ethereum.json,./cookbook/specs/spec_add_cosmoshub.json,./cookbook/specs/spec_add_lava.json,./cookbook/specs/spec_add_osmosis.json,./cookbook/specs/spec_add_fantom.json,./cookbook/specs/spec_add_celo.json,./cookbook/specs/spec_add_optimism.json,./cookbook/specs/spec_add_arbitrum.json,./cookbook/specs/spec_add_starknet.json,./cookbook/specs/spec_add_aptos.json,./cookbook/specs/spec_add_juno.json,./cookbook/specs/spec_add_polygon.json,./cookbook/specs/spec_add_evmos.json,./cookbook/specs/spec_add_base.json,./cookbook/specs/spec_add_canto.json,./cookbook/specs/spec_add_sui.json,./cookbook/specs/spec_add_solana.json,./cookbook/specs/spec_add_bsc.json,./cookbook/specs/spec_add_axelar.json,./cookbook/specs/spec_add_avalanche.json,./cookbook/specs/spec_add_fvm.json -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE & +lavad tx gov submit-legacy-proposal spec-add ./cookbook/specs/spec_add_ibc.json,./cookbook/specs/spec_add_cosmoswasm.json,./cookbook/specs/spec_add_cosmossdk.json,./cookbook/specs/spec_add_cosmossdk_45.json,./cookbook/specs/spec_add_cosmossdk_full.json,./cookbook/specs/spec_add_ethereum.json,./cookbook/specs/spec_add_cosmoshub.json,./cookbook/specs/spec_add_lava.json,./cookbook/specs/spec_add_osmosis.json,./cookbook/specs/spec_add_fantom.json,./cookbook/specs/spec_add_celo.json,./cookbook/specs/spec_add_optimism.json,./cookbook/specs/spec_add_arbitrum.json,./cookbook/specs/spec_add_starknet.json,./cookbook/specs/spec_add_aptos.json,./cookbook/specs/spec_add_juno.json,./cookbook/specs/spec_add_polygon.json,./cookbook/specs/spec_add_evmos.json,./cookbook/specs/spec_add_base.json,./cookbook/specs/spec_add_canto.json,./cookbook/specs/spec_add_sui.json,./cookbook/specs/spec_add_solana.json,./cookbook/specs/spec_add_bsc.json,./cookbook/specs/spec_add_axelar.json,./cookbook/specs/spec_add_avalanche.json,./cookbook/specs/spec_add_fvm.json --lava-dev-test -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE & wait_next_block wait_next_block lavad tx gov vote 1 yes -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE diff --git a/scripts/pre_setups/init_lava_only_with_node.sh b/scripts/pre_setups/init_lava_only_with_node.sh index a7f200e167..7bf88afbd6 100755 --- a/scripts/pre_setups/init_lava_only_with_node.sh +++ b/scripts/pre_setups/init_lava_only_with_node.sh @@ -20,7 +20,7 @@ echo "[Test Setup] sleeping 20 seconds for node to finish setup (if its not enou sleep 20 GASPRICE="0.000000001ulava" -lavad tx gov submit-legacy-proposal spec-add ./cookbook/specs/spec_add_ibc.json,./cookbook/specs/spec_add_cosmoswasm.json,./cookbook/specs/spec_add_cosmossdk.json,./cookbook/specs/spec_add_cosmossdk_45.json,./cookbook/specs/spec_add_cosmossdk_full.json,./cookbook/specs/spec_add_ethereum.json,./cookbook/specs/spec_add_cosmoshub.json,./cookbook/specs/spec_add_lava.json,./cookbook/specs/spec_add_osmosis.json,./cookbook/specs/spec_add_fantom.json,./cookbook/specs/spec_add_celo.json,./cookbook/specs/spec_add_optimism.json,./cookbook/specs/spec_add_arbitrum.json,./cookbook/specs/spec_add_starknet.json,./cookbook/specs/spec_add_aptos.json,./cookbook/specs/spec_add_juno.json,./cookbook/specs/spec_add_polygon.json,./cookbook/specs/spec_add_evmos.json,./cookbook/specs/spec_add_base.json,./cookbook/specs/spec_add_canto.json,./cookbook/specs/spec_add_sui.json,./cookbook/specs/spec_add_solana.json,./cookbook/specs/spec_add_bsc.json,./cookbook/specs/spec_add_axelar.json,./cookbook/specs/spec_add_avalanche.json,./cookbook/specs/spec_add_fvm.json -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE & +lavad tx gov submit-legacy-proposal spec-add ./cookbook/specs/spec_add_ibc.json,./cookbook/specs/spec_add_cosmoswasm.json,./cookbook/specs/spec_add_cosmossdk.json,./cookbook/specs/spec_add_cosmossdk_45.json,./cookbook/specs/spec_add_cosmossdk_full.json,./cookbook/specs/spec_add_ethereum.json,./cookbook/specs/spec_add_cosmoshub.json,./cookbook/specs/spec_add_lava.json,./cookbook/specs/spec_add_osmosis.json,./cookbook/specs/spec_add_fantom.json,./cookbook/specs/spec_add_celo.json,./cookbook/specs/spec_add_optimism.json,./cookbook/specs/spec_add_arbitrum.json,./cookbook/specs/spec_add_starknet.json,./cookbook/specs/spec_add_aptos.json,./cookbook/specs/spec_add_juno.json,./cookbook/specs/spec_add_polygon.json,./cookbook/specs/spec_add_evmos.json,./cookbook/specs/spec_add_base.json,./cookbook/specs/spec_add_canto.json,./cookbook/specs/spec_add_sui.json,./cookbook/specs/spec_add_solana.json,./cookbook/specs/spec_add_bsc.json,./cookbook/specs/spec_add_axelar.json,./cookbook/specs/spec_add_avalanche.json,./cookbook/specs/spec_add_fvm.json --lava-dev-test -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE & wait_next_block wait_next_block lavad tx gov vote 1 yes -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE diff --git a/utils/rand/rand.go b/utils/rand/rand.go index 97752d5cf7..65fe2465d3 100644 --- a/utils/rand/rand.go +++ b/utils/rand/rand.go @@ -55,6 +55,10 @@ func Uint32() uint32 { return protocolRand.Uint32() } +func Uint64() uint64 { + return protocolRand.Uint64() +} + func Int63() int64 { return protocolRand.Int63() } diff --git a/x/protocol/types/params.go b/x/protocol/types/params.go index bc7ec7f70e..0b20f4dca4 100644 --- a/x/protocol/types/params.go +++ b/x/protocol/types/params.go @@ -12,7 +12,7 @@ import ( var _ paramtypes.ParamSet = (*Params)(nil) const ( - TARGET_VERSION = "0.31.2" + TARGET_VERSION = "0.31.3" MIN_VERSION = "0.30.1" ) From bb47d0207937f9a2985249792663f89ddbcf59a8 Mon Sep 17 00:00:00 2001 From: oren-lava Date: Mon, 18 Dec 2023 12:22:56 +0200 Subject: [PATCH 77/85] CNS-694: adding rewards tests to github action --- .github/workflows/consensus_tests.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/consensus_tests.yml b/.github/workflows/consensus_tests.yml index 809a49aab2..6ab7f52438 100644 --- a/.github/workflows/consensus_tests.yml +++ b/.github/workflows/consensus_tests.yml @@ -76,4 +76,7 @@ jobs: run: go test ./x/timerstore/... - name: lava downtime unit Tests - run: go test ./x/downtime/... \ No newline at end of file + run: go test ./x/downtime/... + + - name: lava rewards unit Tests + run: go test ./x/rewards/... \ No newline at end of file From 4a53b4ec5ed0e8aedbc1f70e718d48a080e46f2e Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Mon, 18 Dec 2023 12:19:37 +0000 Subject: [PATCH 78/85] fix --- x/dualstaking/types/delegate.go | 1 - x/rewards/keeper/pool.go | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/x/dualstaking/types/delegate.go b/x/dualstaking/types/delegate.go index 8c8435b03c..bac2fdefc5 100644 --- a/x/dualstaking/types/delegate.go +++ b/x/dualstaking/types/delegate.go @@ -6,7 +6,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/utils" "github.com/lavanet/lava/utils/slices" - subscriptionkeeper "github.com/lavanet/lava/x/subscription/keeper" ) func NewDelegation(delegator, provider, chainID string, blockTime time.Time, tokenDenom string) Delegation { diff --git a/x/rewards/keeper/pool.go b/x/rewards/keeper/pool.go index fb7c42947f..0cbc0aa816 100644 --- a/x/rewards/keeper/pool.go +++ b/x/rewards/keeper/pool.go @@ -4,13 +4,12 @@ import ( "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" ) // TotalPoolTokens gets the total tokens supply from a pool func (k Keeper) TotalPoolTokens(ctx sdk.Context, pool string) math.Int { poolAddr := k.accountKeeper.GetModuleAddress(pool) - return k.bankKeeper.GetBalance(ctx, poolAddr, epochstoragetypes.TokenDenom).Amount + return k.bankKeeper.GetBalance(ctx, poolAddr, k.stakingKeeper.BondDenom(ctx)).Amount } // BurnPoolTokens removes coins from a pool module account @@ -20,7 +19,7 @@ func (k Keeper) BurnPoolTokens(ctx sdk.Context, pool string, amt math.Int) error return nil } - coins := sdk.NewCoins(sdk.NewCoin(epochstoragetypes.TokenDenom, amt)) + coins := sdk.NewCoins(sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), amt)) return k.bankKeeper.BurnCoins(ctx, pool, coins) } From 74a7c18f6b6b9764918f3999d62589e8dc143b63 Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Mon, 18 Dec 2023 12:21:21 +0000 Subject: [PATCH 79/85] upgrade --- app/app.go | 2 +- app/upgrades/empty_upgrades.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/app.go b/app/app.go index 8bbac21d89..0db5b112de 100644 --- a/app/app.go +++ b/app/app.go @@ -163,7 +163,7 @@ var Upgrades = []upgrades.Upgrade{ upgrades.Upgrade_0_30_2, upgrades.Upgrade_0_31_0, upgrades.Upgrade_0_31_1, - upgrades.Upgrade_remove_mint_add_rewards, + upgrades.Upgrade_0_32_0, } // this line is used by starport scaffolding # stargate/wasm/app/enabledProposals diff --git a/app/upgrades/empty_upgrades.go b/app/upgrades/empty_upgrades.go index 17c6801aa3..f07c2b573d 100644 --- a/app/upgrades/empty_upgrades.go +++ b/app/upgrades/empty_upgrades.go @@ -173,8 +173,8 @@ var Upgrade_0_31_1 = Upgrade{ StoreUpgrades: store.StoreUpgrades{}, } -var Upgrade_remove_mint_add_rewards = Upgrade{ - UpgradeName: "remove-mint-add-rewards", +var Upgrade_0_32_0 = Upgrade{ + UpgradeName: "v0.32.0", CreateUpgradeHandler: defaultUpgradeHandler, StoreUpgrades: store.StoreUpgrades{ Added: []string{rewardstypes.StoreKey}, From dcf5215c77737976455796415f4cafca5fbf001a Mon Sep 17 00:00:00 2001 From: Yarom Swisa Date: Mon, 18 Dec 2023 12:23:58 +0000 Subject: [PATCH 80/85] fix --- x/rewards/types/expected_keepers.go | 1 + 1 file changed, 1 insertion(+) diff --git a/x/rewards/types/expected_keepers.go b/x/rewards/types/expected_keepers.go index 30aeacbcf4..f44472f650 100644 --- a/x/rewards/types/expected_keepers.go +++ b/x/rewards/types/expected_keepers.go @@ -29,6 +29,7 @@ type DowntimeKeeper interface { type StakingKeeper interface { BondedRatio(ctx sdk.Context) math.LegacyDec + BondDenom(ctx sdk.Context) string // Methods imported from bank should be defined here } From 3989558182001ea7363bb9e9cbb567bb3a6b96a8 Mon Sep 17 00:00:00 2001 From: oren-lava Date: Mon, 18 Dec 2023 14:40:43 +0200 Subject: [PATCH 81/85] CNS-694: fix denom --- testutil/common/tester.go | 1 + testutil/keeper/keepers_init.go | 2 +- testutil/keeper/rewards.go | 8 ++++---- x/rewards/keeper/grpc_query_block_reward.go | 3 +-- x/rewards/keeper/grpc_query_pools.go | 5 ++--- x/rewards/keeper/pool_test.go | 5 ++--- x/rewards/keeper/rewards.go | 5 ++--- 7 files changed, 13 insertions(+), 16 deletions(-) diff --git a/testutil/common/tester.go b/testutil/common/tester.go index b2b3345a39..a12b12e2e0 100644 --- a/testutil/common/tester.go +++ b/testutil/common/tester.go @@ -2,6 +2,7 @@ package common import ( "context" + "fmt" "sort" "strconv" "strings" diff --git a/testutil/keeper/keepers_init.go b/testutil/keeper/keepers_init.go index a94f3fe2da..403d1b2d55 100644 --- a/testutil/keeper/keepers_init.go +++ b/testutil/keeper/keepers_init.go @@ -309,7 +309,7 @@ func InitAllKeepers(t testing.TB) (*Servers, *Keepers, *RewardsPools, context.Co p.ValidatorsDistributionPool = mockRewardsPool{} err := ks.BankKeeper.AddToBalance( p.ValidatorsAllocationPool.GetModuleAddress(string(rewardstypes.ValidatorsRewardsAllocationPoolName)), - sdk.NewCoins(sdk.NewCoin(epochstoragetypes.TokenDenom, sdk.NewIntFromUint64(allocationPoolBalance)))) + sdk.NewCoins(sdk.NewCoin(stakingparams.BondDenom, sdk.NewIntFromUint64(allocationPoolBalance)))) require.Nil(t, err) ctx = ctx.WithBlockTime(time.Now()) diff --git a/testutil/keeper/rewards.go b/testutil/keeper/rewards.go index a709bb728a..911e2e5f6d 100644 --- a/testutil/keeper/rewards.go +++ b/testutil/keeper/rewards.go @@ -63,16 +63,16 @@ func RewardsKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { downtimeKey := sdk.NewKVStoreKey(downtimemoduletypes.StoreKey) stateStore.MountStoreWithDB(downtimeKey, storetypes.StoreTypeIAVL, db) - epochstorageKeeper := epochstoragekeeper.NewKeeper(cdc, nil, nil, paramsSubspaceEpochstorage, nil, nil, nil) + stakingStoreKey := sdk.NewKVStoreKey(stakingtypes.StoreKey) + stakingKeeper := *stakingkeeper.NewKeeper(cdc, stakingStoreKey, mockAccountKeeper{}, mockBankKeeper{}, authtypes.NewModuleAddress(govtypes.ModuleName).String()) + + epochstorageKeeper := epochstoragekeeper.NewKeeper(cdc, nil, nil, paramsSubspaceEpochstorage, nil, nil, nil, stakingKeeper) downtimeKeeper := downtimekeeper.NewKeeper(cdc, downtimeKey, paramsSubspaceDowntime, epochstorageKeeper) ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) downtimeKeeper.SetParams(ctx, v1.DefaultParams()) - stakingStoreKey := sdk.NewKVStoreKey(stakingtypes.StoreKey) - stakingKeeper := *stakingkeeper.NewKeeper(cdc, stakingStoreKey, mockAccountKeeper{}, mockBankKeeper{}, authtypes.NewModuleAddress(govtypes.ModuleName).String()) - k := keeper.NewKeeper( cdc, storeKey, diff --git a/x/rewards/keeper/grpc_query_block_reward.go b/x/rewards/keeper/grpc_query_block_reward.go index 5bd03a0187..392fcf6ae2 100644 --- a/x/rewards/keeper/grpc_query_block_reward.go +++ b/x/rewards/keeper/grpc_query_block_reward.go @@ -4,7 +4,6 @@ import ( "context" sdk "github.com/cosmos/cosmos-sdk/types" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" "github.com/lavanet/lava/x/rewards/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -26,7 +25,7 @@ func (k Keeper) BlockReward(goCtx context.Context, req *types.QueryBlockRewardRe // validators bonus rewards = (blockPoolBalance * bondedTargetFactor) / blocksToNextTimerExpiry validatorsRewards := bondedTargetFactor.MulInt(blockPoolBalance).TruncateInt().QuoRaw(blocksToNextTimerExpiry) - reward := sdk.NewCoin(epochstoragetypes.TokenDenom, validatorsRewards) + reward := sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), validatorsRewards) return &types.QueryBlockRewardResponse{Reward: reward}, nil } diff --git a/x/rewards/keeper/grpc_query_pools.go b/x/rewards/keeper/grpc_query_pools.go index e2c5ab81f9..803413b0be 100644 --- a/x/rewards/keeper/grpc_query_pools.go +++ b/x/rewards/keeper/grpc_query_pools.go @@ -4,7 +4,6 @@ import ( "context" sdk "github.com/cosmos/cosmos-sdk/types" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" "github.com/lavanet/lava/x/rewards/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -20,11 +19,11 @@ func (k Keeper) Pools(goCtx context.Context, req *types.QueryPoolsRequest) (*typ pools := []types.PoolInfo{ { Name: string(types.ValidatorsRewardsDistributionPoolName), - Balance: sdk.NewCoin(epochstoragetypes.TokenDenom, k.TotalPoolTokens(ctx, types.ValidatorsRewardsDistributionPoolName)), + Balance: sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), k.TotalPoolTokens(ctx, types.ValidatorsRewardsDistributionPoolName)), }, { Name: string(types.ValidatorsRewardsAllocationPoolName), - Balance: sdk.NewCoin(epochstoragetypes.TokenDenom, k.TotalPoolTokens(ctx, types.ValidatorsRewardsAllocationPoolName)), + Balance: sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), k.TotalPoolTokens(ctx, types.ValidatorsRewardsAllocationPoolName)), }, } diff --git a/x/rewards/keeper/pool_test.go b/x/rewards/keeper/pool_test.go index 7ba427e6cf..e40fd7b7bd 100644 --- a/x/rewards/keeper/pool_test.go +++ b/x/rewards/keeper/pool_test.go @@ -6,7 +6,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" testkeeper "github.com/lavanet/lava/testutil/keeper" "github.com/lavanet/lava/utils" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" "github.com/lavanet/lava/x/rewards/types" "github.com/stretchr/testify/require" ) @@ -200,7 +199,7 @@ func TestValidatorBlockRewards(t *testing.T) { ts.Ctx, string(types.ValidatorsRewardsDistributionPoolName), string(types.ValidatorsRewardsAllocationPoolName), - sdk.NewCoins(sdk.NewCoin(epochstoragetypes.TokenDenom, distPoolBalance.QuoRaw(2))), + sdk.NewCoins(sdk.NewCoin(ts.TokenDenom(), distPoolBalance.QuoRaw(2))), ) require.Nil(t, err) @@ -215,7 +214,7 @@ func TestValidatorBlockRewards(t *testing.T) { ts.Ctx, string(types.ValidatorsRewardsAllocationPoolName), string(types.ValidatorsRewardsDistributionPoolName), - sdk.NewCoins(sdk.NewCoin(epochstoragetypes.TokenDenom, distPoolBalance.QuoRaw(2))), + sdk.NewCoins(sdk.NewCoin(ts.TokenDenom(), distPoolBalance.QuoRaw(2))), ) require.Nil(t, err) diff --git a/x/rewards/keeper/rewards.go b/x/rewards/keeper/rewards.go index a5ee5f3114..9a33e88dcd 100644 --- a/x/rewards/keeper/rewards.go +++ b/x/rewards/keeper/rewards.go @@ -8,7 +8,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/lavanet/lava/utils" - epochstoragetypes "github.com/lavanet/lava/x/epochstorage/types" "github.com/lavanet/lava/x/rewards/types" timerstoretypes "github.com/lavanet/lava/x/timerstore/types" ) @@ -33,7 +32,7 @@ func (k Keeper) DistributeBlockReward(ctx sdk.Context) error { return nil } - coins := sdk.NewCoins(sdk.NewCoin(epochstoragetypes.TokenDenom, validatorsRewards)) + coins := sdk.NewCoins(sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), validatorsRewards)) // distribute rewards to validators (same as Cosmos mint module) err := k.addCollectedFees(ctx, coins) @@ -102,7 +101,7 @@ func (k Keeper) refillAllocationPool(ctx sdk.Context, monthsLeft uint64, allocat } // transfer the new monthly quota (if allocation pool is expired, rewards=0) - monthlyQuota := sdk.Coins{sdk.Coin{Denom: epochstoragetypes.TokenDenom, Amount: sdk.ZeroInt()}} + monthlyQuota := sdk.Coins{sdk.Coin{Denom: k.stakingKeeper.BondDenom(ctx), Amount: sdk.ZeroInt()}} allocPoolBalance := k.TotalPoolTokens(ctx, allocationPool) if monthsLeft != 0 && !allocPoolBalance.IsZero() { monthlyQuota[0] = monthlyQuota[0].AddAmount(allocPoolBalance.QuoRaw(int64(monthsLeft))) From 4d5b1f2e23b283c0d15e25791b09b83a94e38431 Mon Sep 17 00:00:00 2001 From: oren-lava Date: Mon, 18 Dec 2023 14:56:54 +0200 Subject: [PATCH 82/85] CNS-694: fix unit tests --- testutil/keeper/keepers_init.go | 1 + testutil/keeper/mock_keepers.go | 6 ++++++ x/rewards/keeper/rewards.go | 4 ++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/testutil/keeper/keepers_init.go b/testutil/keeper/keepers_init.go index 403d1b2d55..6f6ad4dae8 100644 --- a/testutil/keeper/keepers_init.go +++ b/testutil/keeper/keepers_init.go @@ -240,6 +240,7 @@ func InitAllKeepers(t testing.TB) (*Servers, *Keepers, *RewardsPools, context.Co ks.TimerStoreKeeper = timerstorekeeper.NewKeeper(cdc) ks.AccountKeeper = mockAccountKeeper{} ks.BankKeeper = mockBankKeeper{} + init_balance() ks.StakingKeeper = *stakingkeeper.NewKeeper(cdc, stakingStoreKey, ks.AccountKeeper, ks.BankKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String()) ks.Spec = *speckeeper.NewKeeper(cdc, specStoreKey, specMemStoreKey, specparamsSubspace, ks.StakingKeeper) ks.Epochstorage = *epochstoragekeeper.NewKeeper(cdc, epochStoreKey, epochMemStoreKey, epochparamsSubspace, &ks.BankKeeper, &ks.AccountKeeper, ks.Spec, ks.StakingKeeper) diff --git a/testutil/keeper/mock_keepers.go b/testutil/keeper/mock_keepers.go index a3c9b7c202..5c1cb05bb9 100644 --- a/testutil/keeper/mock_keepers.go +++ b/testutil/keeper/mock_keepers.go @@ -38,6 +38,10 @@ var balance map[string]sdk.Coins = make(map[string]sdk.Coins) type mockBankKeeper struct{} +func init_balance() { + balance = make(map[string]sdk.Coins) +} + func (k mockBankKeeper) SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins { return nil } @@ -164,11 +168,13 @@ func (k mockBankKeeper) SetBalance(ctx sdk.Context, addr sdk.AccAddress, amounts func (k mockBankKeeper) AddToBalance(addr sdk.AccAddress, amounts sdk.Coins) error { if _, ok := balance[addr.String()]; ok { for _, coin := range amounts { + fmt.Printf("before balance[addr.String()].String(): %v\n", balance[addr.String()].String()) balance[addr.String()] = balance[addr.String()].Add(coin) } } else { balance[addr.String()] = amounts } + fmt.Printf("after balance[addr.String()].String(): %v\n", balance[addr.String()].String()) return nil } diff --git a/x/rewards/keeper/rewards.go b/x/rewards/keeper/rewards.go index 9a33e88dcd..2f7b27b114 100644 --- a/x/rewards/keeper/rewards.go +++ b/x/rewards/keeper/rewards.go @@ -66,7 +66,7 @@ func (k Keeper) RefillRewardsPools(ctx sdk.Context, _ []byte, data []byte) { monthsLeft = binary.BigEndian.Uint64(data) } - k.refillAllocationPool(ctx, monthsLeft, types.ValidatorsRewardsAllocationPoolName, types.ValidatorsRewardsDistributionPoolName) + k.refillDistributionPool(ctx, monthsLeft, types.ValidatorsRewardsAllocationPoolName, types.ValidatorsRewardsDistributionPoolName) if monthsLeft > 0 { monthsLeft -= 1 @@ -88,7 +88,7 @@ func (k Keeper) RefillRewardsPools(ctx sdk.Context, _ []byte, data []byte) { k.refillRewardsPoolTS.AddTimerByBlockTime(ctx, uint64(nextMonth), blocksToNextTimerExpirybytes, monthsLeftBytes) } -func (k Keeper) refillAllocationPool(ctx sdk.Context, monthsLeft uint64, allocationPool types.Pool, distributionPool types.Pool) { +func (k Keeper) refillDistributionPool(ctx sdk.Context, monthsLeft uint64, allocationPool types.Pool, distributionPool types.Pool) { // burn remaining tokens in the distribution pool burnRate := k.GetParams(ctx).LeftoverBurnRate tokensToBurn := burnRate.MulInt(k.TotalPoolTokens(ctx, distributionPool)).TruncateInt() From 29ad7479c3d67c8b7f7e99adca38d72c5ddfb628 Mon Sep 17 00:00:00 2001 From: oren-lava Date: Mon, 18 Dec 2023 16:07:50 +0200 Subject: [PATCH 83/85] CNS-694: remove redundant test --- x/rewards/genesis_test.go | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 x/rewards/genesis_test.go diff --git a/x/rewards/genesis_test.go b/x/rewards/genesis_test.go deleted file mode 100644 index 6e87249cbf..0000000000 --- a/x/rewards/genesis_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package rewards_test - -import ( - "testing" - - keepertest "github.com/lavanet/lava/testutil/keeper" - "github.com/lavanet/lava/testutil/nullify" - "github.com/lavanet/lava/x/rewards" - "github.com/lavanet/lava/x/rewards/types" - "github.com/stretchr/testify/require" -) - -func TestGenesis(t *testing.T) { - genesisState := types.GenesisState{ - Params: types.DefaultParams(), - - // this line is used by starport scaffolding # genesis/test/state - } - - k, ctx := keepertest.RewardsKeeper(t) - rewards.InitGenesis(ctx, *k, genesisState) - got := rewards.ExportGenesis(ctx, *k) - require.NotNil(t, got) - - nullify.Fill(&genesisState) - nullify.Fill(got) - - // this line is used by starport scaffolding # genesis/test/assert -} From 3c190e65adf95d112a07287483dce09123539c1a Mon Sep 17 00:00:00 2001 From: oren-lava Date: Tue, 19 Dec 2023 13:57:45 +0200 Subject: [PATCH 84/85] CNS-694: fix PR issues --- app/app.go | 3 --- x/rewards/abci.go | 5 +---- x/rewards/keeper/keeper.go | 5 +---- x/rewards/keeper/rewards.go | 9 ++++----- 4 files changed, 6 insertions(+), 16 deletions(-) diff --git a/app/app.go b/app/app.go index d58203dfd2..2219890ace 100644 --- a/app/app.go +++ b/app/app.go @@ -237,9 +237,6 @@ var ( govtypes.ModuleName: {authtypes.Burner}, ibctransfertypes.ModuleName: {authtypes.Burner}, subscriptionmoduletypes.ModuleName: {authtypes.Burner, authtypes.Staking}, - dualstakingmoduletypes.BondedPoolName: {authtypes.Burner, authtypes.Staking}, - dualstakingmoduletypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, - pairingmoduletypes.ModuleName: {authtypes.Burner, authtypes.Staking}, string(rewardsmoduletypes.ValidatorsRewardsAllocationPoolName): {authtypes.Burner, authtypes.Staking}, string(rewardsmoduletypes.ValidatorsRewardsDistributionPoolName): {authtypes.Burner, authtypes.Staking}, // this line is used by starport scaffolding # stargate/app/maccPerms diff --git a/x/rewards/abci.go b/x/rewards/abci.go index 1658ec8257..a09abee94c 100644 --- a/x/rewards/abci.go +++ b/x/rewards/abci.go @@ -7,8 +7,5 @@ import ( // BeginBlocker calculates the validators block rewards and transfers them to the fee collector func BeginBlocker(ctx sdk.Context, k keeper.Keeper) { - err := k.DistributeBlockReward(ctx) - if err != nil { - panic(err) - } + k.DistributeBlockReward(ctx) } diff --git a/x/rewards/keeper/keeper.go b/x/rewards/keeper/keeper.go index c2400812cb..065cb1a8e6 100644 --- a/x/rewards/keeper/keeper.go +++ b/x/rewards/keeper/keeper.go @@ -84,10 +84,7 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { // redeclaring BeginBlock for testing (this is not called outside of unit tests) func (k Keeper) BeginBlock(ctx sdk.Context) { - err := k.DistributeBlockReward(ctx) - if err != nil { - panic(err) - } + k.DistributeBlockReward(ctx) } // bondedTargetFactor calculates the bonded target factor which is used to calculate the validators diff --git a/x/rewards/keeper/rewards.go b/x/rewards/keeper/rewards.go index 2f7b27b114..6b87d90295 100644 --- a/x/rewards/keeper/rewards.go +++ b/x/rewards/keeper/rewards.go @@ -12,7 +12,7 @@ import ( timerstoretypes "github.com/lavanet/lava/x/timerstore/types" ) -func (k Keeper) DistributeBlockReward(ctx sdk.Context) error { +func (k Keeper) DistributeBlockReward(ctx sdk.Context) { // get params for validator rewards calculation bondedTargetFactor := k.bondedTargetFactor(ctx) blocksToNextTimerExpiry := k.BlocksToNextTimerExpiry(ctx) @@ -29,7 +29,6 @@ func (k Keeper) DistributeBlockReward(ctx sdk.Context) error { utils.Attribute{Key: "distribution_pool_balance", Value: distributionPoolBalance.String()}, utils.Attribute{Key: "blocks_to_next_timer_expiry", Value: strconv.FormatInt(blocksToNextTimerExpiry, 10)}, ) - return nil } coins := sdk.NewCoins(sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), validatorsRewards)) @@ -37,10 +36,10 @@ func (k Keeper) DistributeBlockReward(ctx sdk.Context) error { // distribute rewards to validators (same as Cosmos mint module) err := k.addCollectedFees(ctx, coins) if err != nil { - return err + utils.LavaFormatError("critical - could not send validators rewards to fee collector", err, + utils.Attribute{Key: "rewards", Value: coins.String()}, + ) } - - return nil } // addCollectedFees transfer the validators block rewards from the validators distribution pool to From f0e86a906efd6cfc82a0d78236f5d50825fc9b84 Mon Sep 17 00:00:00 2001 From: oren-lava Date: Tue, 19 Dec 2023 14:37:05 +0200 Subject: [PATCH 85/85] CNS-694: fix unit test --- testutil/keeper/mock_keepers.go | 2 -- x/rewards/keeper/rewards.go | 18 +++++++++--------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/testutil/keeper/mock_keepers.go b/testutil/keeper/mock_keepers.go index 5c1cb05bb9..f4e61409f3 100644 --- a/testutil/keeper/mock_keepers.go +++ b/testutil/keeper/mock_keepers.go @@ -168,13 +168,11 @@ func (k mockBankKeeper) SetBalance(ctx sdk.Context, addr sdk.AccAddress, amounts func (k mockBankKeeper) AddToBalance(addr sdk.AccAddress, amounts sdk.Coins) error { if _, ok := balance[addr.String()]; ok { for _, coin := range amounts { - fmt.Printf("before balance[addr.String()].String(): %v\n", balance[addr.String()].String()) balance[addr.String()] = balance[addr.String()].Add(coin) } } else { balance[addr.String()] = amounts } - fmt.Printf("after balance[addr.String()].String(): %v\n", balance[addr.String()].String()) return nil } diff --git a/x/rewards/keeper/rewards.go b/x/rewards/keeper/rewards.go index 6b87d90295..1f0b4088f0 100644 --- a/x/rewards/keeper/rewards.go +++ b/x/rewards/keeper/rewards.go @@ -29,16 +29,16 @@ func (k Keeper) DistributeBlockReward(ctx sdk.Context) { utils.Attribute{Key: "distribution_pool_balance", Value: distributionPoolBalance.String()}, utils.Attribute{Key: "blocks_to_next_timer_expiry", Value: strconv.FormatInt(blocksToNextTimerExpiry, 10)}, ) - } - - coins := sdk.NewCoins(sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), validatorsRewards)) + } else { + coins := sdk.NewCoins(sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), validatorsRewards)) - // distribute rewards to validators (same as Cosmos mint module) - err := k.addCollectedFees(ctx, coins) - if err != nil { - utils.LavaFormatError("critical - could not send validators rewards to fee collector", err, - utils.Attribute{Key: "rewards", Value: coins.String()}, - ) + // distribute rewards to validators (same as Cosmos mint module) + err := k.addCollectedFees(ctx, coins) + if err != nil { + utils.LavaFormatError("critical - could not send validators rewards to fee collector", err, + utils.Attribute{Key: "rewards", Value: coins.String()}, + ) + } } }