From afa45b7c0f56d66ea8426001087233f64ba3ce5a Mon Sep 17 00:00:00 2001 From: oren-lava <111131399+oren-lava@users.noreply.github.com> Date: Wed, 14 Aug 2024 12:26:40 +0300 Subject: [PATCH] refactor: CNS-999 - Pairing cache (#1576) * CNS-994: use utils to encode/decode epoch * CNS-994: stake storage refactor not final * CNS-994: fix some of the unit tests * CNS-994: finish refactor * CNS-994: fix serialization to be big endian (avoid common 0 prefix of little endian) * CNS-994: fix unit test * CNS-994: fix e2e * CNS-998: install collections * CNS-998: rename collections.go to collcompat (for standard) * CNS-998: make stake entries use collections * CNS-994: migrator * CNS-994: fix migrator * CNS-994: updated readme * CNS-994: the pairing mechanism assumes that the retrived entries are with decending order of stake * CNS-998: iterate over providers in reverse * CNS-994: fix unit test * CNS-998: fix unit test * CNS-999: pairing cache implementation * CNS-999: small change * CNS-999: remove test code * CNS-999: rename * CNS-999: relay pairing cache implementaion + unit tests * CNS-994: revert Serialize to little endian and created SerializeBigEndian * CNS-994: remove outdated migrators * CNS-994: complete migrator removal * CNS-994: delete outdated test file * CNS-994: sort stake storage in GetAllStakeEntriesForGenesis * CNS-994: reverted removal of stakeEntries map in unresponsive provider code * CNS-994: test scripts 100 providers * CNS-994: migrator fix order stake entries for pairing * CNS-994: another migrator fix * refactor: CNS-998 - use collections instead of KV stores (#1570) * CNS-998: install collections * CNS-998: rename collections.go to collcompat (for standard) * CNS-998: make stake entries use collections * CNS-998: iterate over providers in reverse * CNS-998: fix unit test * CNS-998: make stakeEntries hold extra unique index of epoch, chainid and address * CNS-998: add chain id and vault indices for stake entries current * CNS-998: small changes * CNS-998: added comment * CNS-998: other part of merge * CNS-998: make epoch hashes a collections map * CNS-998: add error handling for epoch hash remove * CNS-998: migrator fix * Update scripts/test/inich_100_providers.sh Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * CNS-994: fix lint and small issues * CNS-994: fix lint * CNS-999: fix unit tests * Update scripts/test/inich_100_providers.sh Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update x/epochstorage/keeper/stake_entries.go Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * CNS-994: enhance error messages in stake entries methods * CNS-999: rabbitAi changes * CNS-999: lint * CNS-999: fix protocgen * CNS-999: fix lint * CNS-999: lint fix * CNS-999: make relay pairing cache use a KV store * CNS-999: lint fix * CNS-999: change relay cache key and save allowed_cu in cache * Update x/pairing/keeper/pairing.go * Update x/pairing/keeper/pairing_cache.go * Update pairing_cache.go * CNS-999: added unit test * CNS-999: lint fixes * CNS-999: more lint fixes * CNS-999: lint fixes * CNS-999: lint * CNS-999: lint --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Omer <100387053+omerlavanet@users.noreply.github.com> --- proto/lavanet/lava/pairing/relay.proto | 6 + protocol/chainlib/chain_fetcher.go | 2 +- protocol/chainlib/chain_message.go | 2 +- .../chainlib/chainproxy/rpcclient/http.go | 4 +- .../chainlib/chainproxy/rpcclient/service.go | 2 +- .../chainproxy/rpcclient/subscription.go | 4 +- protocol/chainlib/grpc.go | 2 +- protocol/chainlib/node_error_handler.go | 4 +- protocol/chaintracker/wanted_block_data.go | 2 +- protocol/rpcconsumer/relay_errors.go | 2 +- protocol/rpcconsumer/relay_errors_test.go | 22 +- protocol/rpcconsumer/relay_processor.go | 2 +- .../rewardserver/reward_server_test.go | 2 +- protocol/rpcprovider/rpcprovider_server.go | 2 +- protocol/statetracker/tx_sender.go | 2 +- scripts/protocgen.sh | 1 + scripts/test/inich_100_providers.sh | 2 +- scripts/test/unstake_100_providers.sh | 1 + testutil/e2e/protocolE2E.go | 16 +- testutil/e2e/proxy/helper.go | 4 +- utils/lavalog.go | 2 +- x/epochstorage/keeper/fixated_params.go | 2 +- x/pairing/keeper/keeper.go | 13 + x/pairing/keeper/msg_server_relay_payment.go | 67 ++-- x/pairing/keeper/pairing.go | 62 ++- x/pairing/keeper/pairing_cache.go | 64 +++ x/pairing/keeper/pairing_cache_test.go | 121 ++++++ x/pairing/module.go | 3 +- x/pairing/types/pairing_cache.go | 10 + x/pairing/types/relay.pb.go | 376 ++++++++++++++---- x/spec/proposal_handler.go | 2 +- 31 files changed, 633 insertions(+), 173 deletions(-) create mode 100644 x/pairing/keeper/pairing_cache.go create mode 100644 x/pairing/keeper/pairing_cache_test.go create mode 100644 x/pairing/types/pairing_cache.go diff --git a/proto/lavanet/lava/pairing/relay.proto b/proto/lavanet/lava/pairing/relay.proto index 0f4346a999..1b10b8f5ae 100644 --- a/proto/lavanet/lava/pairing/relay.proto +++ b/proto/lavanet/lava/pairing/relay.proto @@ -6,6 +6,7 @@ option go_package = "github.com/lavanet/lava/v2/x/pairing/types"; import "gogoproto/gogo.proto"; import "google/protobuf/wrappers.proto"; import "google/protobuf/timestamp.proto"; +import "lavanet/lava/epochstorage/stake_entry.proto"; service Relayer { rpc Relay (RelayRequest) returns (RelayReply) {} @@ -110,3 +111,8 @@ message QualityOfServiceReport{ (gogoproto.nullable) = false ]; } + +message PairingRelayCache { + repeated lavanet.lava.epochstorage.StakeEntry entries = 1 [(gogoproto.nullable) = false]; + uint64 allowed_cu = 2; +} \ No newline at end of file diff --git a/protocol/chainlib/chain_fetcher.go b/protocol/chainlib/chain_fetcher.go index 4df67be44b..e045d264a3 100644 --- a/protocol/chainlib/chain_fetcher.go +++ b/protocol/chainlib/chain_fetcher.go @@ -126,7 +126,7 @@ func (cf *ChainFetcher) Verify(ctx context.Context, verification VerificationCon collectionType := verification.ConnectionType path := parsing.ApiName - data := []byte(fmt.Sprintf(parsing.FunctionTemplate)) + data := []byte(parsing.FunctionTemplate) if !verification.IsActive() { utils.LavaFormatDebug("skipping disabled verification", []utils.Attribute{ diff --git a/protocol/chainlib/chain_message.go b/protocol/chainlib/chain_message.go index ff0784b899..9df468f55c 100644 --- a/protocol/chainlib/chain_message.go +++ b/protocol/chainlib/chain_message.go @@ -48,7 +48,7 @@ func (bcnc *baseChainMessageContainer) GetParseDirective() *spectypes.ParseDirec } func (pm *baseChainMessageContainer) GetRawRequestHash() ([]byte, error) { - if pm.inputHashCache != nil && len(pm.inputHashCache) > 0 { + if len(pm.inputHashCache) > 0 { // Get the cached value return pm.inputHashCache, nil } diff --git a/protocol/chainlib/chainproxy/rpcclient/http.go b/protocol/chainlib/chainproxy/rpcclient/http.go index 5e6fde9dad..b4cf981f55 100755 --- a/protocol/chainlib/chainproxy/rpcclient/http.go +++ b/protocol/chainlib/chainproxy/rpcclient/http.go @@ -147,7 +147,7 @@ func DialHTTP(endpoint string) (*Client, error) { func (c *Client) sendHTTP(ctx context.Context, op *requestOp, msg interface{}, isJsonRPC bool, strict bool) error { hc, ok := c.writeConn.(*httpConn) if !ok { - return fmt.Errorf("sendHTTP - c.writeConn.(*httpConn) - type assertion failed" + fmt.Sprintf("%s", c.writeConn)) + return fmt.Errorf("sendHTTP - c.writeConn.(*httpConn) - type assertion failed %s", c.writeConn) } respBody, err := hc.doRequest(ctx, msg, isJsonRPC, strict) if err != nil { @@ -166,7 +166,7 @@ func (c *Client) sendHTTP(ctx context.Context, op *requestOp, msg interface{}, i func (c *Client) sendBatchHTTP(ctx context.Context, op *requestOp, msgs []*JsonrpcMessage, strict bool) error { hc, ok := c.writeConn.(*httpConn) if !ok { - return fmt.Errorf("sendBatchHTTP - c.writeConn.(*httpConn) - type assertion failed, type:" + fmt.Sprintf("%s", c.writeConn)) + return fmt.Errorf("sendBatchHTTP - c.writeConn.(*httpConn) - type assertion failed, type: %s", c.writeConn) } respBody, err := hc.doRequest(ctx, msgs, true, strict) if err != nil { diff --git a/protocol/chainlib/chainproxy/rpcclient/service.go b/protocol/chainlib/chainproxy/rpcclient/service.go index fee6a1d238..78754feb64 100755 --- a/protocol/chainlib/chainproxy/rpcclient/service.go +++ b/protocol/chainlib/chainproxy/rpcclient/service.go @@ -214,7 +214,7 @@ func (c *callback) call(ctx context.Context, method string, args []reflect.Value var ok bool errRet, ok := err.(error) if !ok { - return reflect.Value{}, fmt.Errorf("(c *callback) call - errRet, ok := err.(error) - type assertion failed" + fmt.Sprintf("%s", err)) + return reflect.Value{}, fmt.Errorf("(c *callback) call - errRet, ok := err.(error) - type assertion failed %s", err) } return reflect.Value{}, errRet } diff --git a/protocol/chainlib/chainproxy/rpcclient/subscription.go b/protocol/chainlib/chainproxy/rpcclient/subscription.go index 6835ee09a3..af9beb8236 100755 --- a/protocol/chainlib/chainproxy/rpcclient/subscription.go +++ b/protocol/chainlib/chainproxy/rpcclient/subscription.go @@ -340,7 +340,7 @@ func (sub *ClientSubscription) forward() (unsubscribeServer bool, err error) { var ok bool err, ok = recv.Interface().(error) if !ok { - return false, fmt.Errorf("(sub *ClientSubscription) forward() - recv.Interface().(error) - type assertion failed" + fmt.Sprintf("%s", recv.Interface())) + return false, fmt.Errorf("(sub *ClientSubscription) forward() - recv.Interface().(error) - type assertion failed %s", recv.Interface()) } } if err == errUnsubscribed { @@ -352,7 +352,7 @@ func (sub *ClientSubscription) forward() (unsubscribeServer bool, err error) { case 1: // <-sub.in msg, ok := recv.Interface().(*JsonrpcMessage) if !ok { - return false, fmt.Errorf("(sub *ClientSubscription) forward() - recv.Interface().(*JsonrpcMessage) - type assertion failed" + fmt.Sprintf("%s", recv.Interface())) + return false, fmt.Errorf("(sub *ClientSubscription) forward() - recv.Interface().(*JsonrpcMessage) - type assertion failed %s", recv.Interface()) } if msg.Error != nil { return true, err diff --git a/protocol/chainlib/grpc.go b/protocol/chainlib/grpc.go index 25208a7fc7..40aa78178f 100644 --- a/protocol/chainlib/grpc.go +++ b/protocol/chainlib/grpc.go @@ -329,7 +329,7 @@ func (apil *GrpcChainListener) Serve(ctx context.Context, cmdFlags common.Consum if err != nil { errMasking := apil.logger.GetUniqueGuidResponseForError(err, msgSeed) apil.logger.LogRequestAndResponse("grpc in/out", true, method, string(reqBody), "", errMasking, msgSeed, time.Since(startTime), err) - return nil, nil, utils.LavaFormatError("Failed to SendRelay", fmt.Errorf(errMasking)) + return nil, nil, utils.LavaFormatError("Failed to SendRelay", fmt.Errorf("%s", errMasking)) } apil.logger.LogRequestAndResponse("grpc in/out", false, method, string(reqBody), "", "", msgSeed, time.Since(startTime), nil) apil.logger.AddMetricForProcessingLatencyAfterProvider(metricsData, apil.endpoint.ChainID, apiInterface) diff --git a/protocol/chainlib/node_error_handler.go b/protocol/chainlib/node_error_handler.go index e800fe3c46..683839b8d3 100644 --- a/protocol/chainlib/node_error_handler.go +++ b/protocol/chainlib/node_error_handler.go @@ -87,11 +87,11 @@ func (geh *genericErrorHandler) HandleJSONFormatError(replyData []byte) error { func (geh *genericErrorHandler) ValidateRequestAndResponseIds(nodeMessageID json.RawMessage, replyMsgID json.RawMessage) error { reqId, idErr := rpcInterfaceMessages.IdFromRawMessage(nodeMessageID) if idErr != nil { - return fmt.Errorf("Failed parsing ID " + idErr.Error()) + return fmt.Errorf("failed parsing ID %s", idErr.Error()) } respId, idErr := rpcInterfaceMessages.IdFromRawMessage(replyMsgID) if idErr != nil { - return fmt.Errorf("Failed parsing ID " + idErr.Error()) + return fmt.Errorf("failed parsing ID %s", idErr.Error()) } if reqId != respId { return fmt.Errorf("ID mismatch error") diff --git a/protocol/chaintracker/wanted_block_data.go b/protocol/chaintracker/wanted_block_data.go index 66f6e2c74b..082a3b2d2c 100644 --- a/protocol/chaintracker/wanted_block_data.go +++ b/protocol/chaintracker/wanted_block_data.go @@ -48,7 +48,7 @@ func (wbd *WantedBlocksData) New(fromBlock, toBlock, specificBlock, latestBlock, toBlockArg := fromBlockArg // [from,to] with only one block wbd.specificBlock, err = NewBlockRange(fromBlockArg, toBlockArg, earliestBlockSaved, latestBlock) if err != nil { - return InvalidRequestedSpecificBlock.Wrapf("specific " + err.Error()) + return InvalidRequestedSpecificBlock.Wrapf("specific %s", err.Error()) } } } else { diff --git a/protocol/rpcconsumer/relay_errors.go b/protocol/rpcconsumer/relay_errors.go index caa877c446..174b01bba5 100644 --- a/protocol/rpcconsumer/relay_errors.go +++ b/protocol/rpcconsumer/relay_errors.go @@ -114,7 +114,7 @@ func (r *RelayErrors) mergeAllErrors() error { mergedMessage += ", " } } - return fmt.Errorf(mergedMessage) + return fmt.Errorf("%s", mergedMessage) } // TODO: there's no need to save error twice and provider info twice, this can just be a relayResponse diff --git a/protocol/rpcconsumer/relay_errors_test.go b/protocol/rpcconsumer/relay_errors_test.go index 66b0f60389..0f26ee3857 100644 --- a/protocol/rpcconsumer/relay_errors_test.go +++ b/protocol/rpcconsumer/relay_errors_test.go @@ -49,7 +49,7 @@ func TestRelayError(t *testing.T) { }, }, { - err: fmt.Errorf(expectedValue), + err: fmt.Errorf("%s", expectedValue), ProviderInfo: common.ProviderInfo{ ProviderQoSExcellenceSummery: sdk.OneDec(), ProviderStake: sdk.NewInt64Coin("ulava", 50), @@ -106,7 +106,7 @@ func TestRelayError(t *testing.T) { }, }, { - err: fmt.Errorf(expectedValue), + err: fmt.Errorf("%s", expectedValue), ProviderInfo: common.ProviderInfo{ ProviderQoSExcellenceSummery: sdk.MustNewDecFromStr("0.8"), ProviderStake: sdk.NewInt64Coin("ulava", 10), @@ -135,21 +135,21 @@ func TestRelayError(t *testing.T) { }, }, { - err: fmt.Errorf(expectedValue), + err: fmt.Errorf("%s", expectedValue), ProviderInfo: common.ProviderInfo{ ProviderQoSExcellenceSummery: sdk.ZeroDec(), ProviderStake: sdk.NewInt64Coin("ulava", 0), }, }, { - err: fmt.Errorf(expectedValue), + err: fmt.Errorf("%s", expectedValue), ProviderInfo: common.ProviderInfo{ ProviderQoSExcellenceSummery: sdk.ZeroDec(), ProviderStake: sdk.NewInt64Coin("ulava", 0), }, }, { - err: fmt.Errorf(expectedValue), + err: fmt.Errorf("%s", expectedValue), ProviderInfo: common.ProviderInfo{ ProviderQoSExcellenceSummery: sdk.ZeroDec(), ProviderStake: sdk.NewInt64Coin("ulava", 0), @@ -164,14 +164,14 @@ func TestRelayError(t *testing.T) { onFailureMergeAll: true, relayErrors: []RelayError{ { - err: fmt.Errorf(expectedValue), + err: fmt.Errorf("%s", expectedValue), ProviderInfo: common.ProviderInfo{ ProviderQoSExcellenceSummery: sdk.OneDec(), ProviderStake: sdk.NewInt64Coin("ulava", 10), }, }, { - err: fmt.Errorf(expectedValue), + err: fmt.Errorf("%s", expectedValue), ProviderInfo: common.ProviderInfo{ ProviderQoSExcellenceSummery: sdk.OneDec(), ProviderStake: sdk.NewInt64Coin("ulava", 20), @@ -192,7 +192,7 @@ func TestRelayError(t *testing.T) { }, }, { - err: fmt.Errorf(expectedValue), + err: fmt.Errorf("%s", expectedValue), ProviderInfo: common.ProviderInfo{ ProviderQoSExcellenceSummery: sdk.OneDec(), ProviderStake: sdk.NewInt64Coin("ulava", 10), @@ -207,14 +207,14 @@ func TestRelayError(t *testing.T) { onFailureMergeAll: true, relayErrors: []RelayError{ { - err: fmt.Errorf(expectedValue), + err: fmt.Errorf("%s", expectedValue), ProviderInfo: common.ProviderInfo{ ProviderQoSExcellenceSummery: sdk.OneDec(), ProviderStake: sdk.NewInt64Coin("ulava", 10), }, }, { - err: fmt.Errorf(expectedValue), + err: fmt.Errorf("%s", expectedValue), ProviderInfo: common.ProviderInfo{ ProviderQoSExcellenceSummery: sdk.OneDec(), ProviderStake: sdk.NewInt64Coin("ulava", 20), @@ -235,7 +235,7 @@ func TestRelayError(t *testing.T) { }, }, { - err: fmt.Errorf(expectedValue), + err: fmt.Errorf("%s", expectedValue), ProviderInfo: common.ProviderInfo{ ProviderQoSExcellenceSummery: sdk.OneDec(), ProviderStake: sdk.NewInt64Coin("ulava", 10), diff --git a/protocol/rpcconsumer/relay_processor.go b/protocol/rpcconsumer/relay_processor.go index 4c83ac2c72..f18b276663 100644 --- a/protocol/rpcconsumer/relay_processor.go +++ b/protocol/rpcconsumer/relay_processor.go @@ -248,7 +248,7 @@ func (rp *RelayProcessor) setValidResponse(response *relayResponse) { // this is a node error, meaning we still didn't get a good response. // we may choose to wait until there will be a response or timeout happens // if we decide to wait and timeout happens we will take the majority of response messages - err := fmt.Errorf(errorMessage) + err := fmt.Errorf("%s", errorMessage) rp.nodeResponseErrors.relayErrors = append(rp.nodeResponseErrors.relayErrors, RelayError{err: err, ProviderInfo: response.relayResult.ProviderInfo, response: response}) // send relay error metrics only on non stateful queries, as stateful queries always return X-1/X errors. if rp.selection != BestResult { diff --git a/protocol/rpcprovider/rewardserver/reward_server_test.go b/protocol/rpcprovider/rewardserver/reward_server_test.go index 0e4db6dbc0..b495d368b1 100644 --- a/protocol/rpcprovider/rewardserver/reward_server_test.go +++ b/protocol/rpcprovider/rewardserver/reward_server_test.go @@ -46,7 +46,7 @@ func stubPaymentEvents(num int, specId string, sessionId uint64) (tos []map[stri QoS, _ := relay.QosReport.ComputeQoS() rewardCoins, _ := sdk.ParseCoinNormalized("50ulava") burnAmount, _ := sdk.ParseCoinNormalized("40ulava") - from := map[string]string{"chainID": fmt.Sprintf(relay.SpecId), "client": clientAddr.String(), "provider": providerAddr.String(), "CU": strconv.FormatUint(relay.CuSum, 10), "BasePay": rewardCoins.String(), "totalCUInEpoch": strconv.FormatUint(700, 10), "uniqueIdentifier": strconv.FormatUint(relay.SessionId, 10), "descriptionString": "banana"} + from := map[string]string{"chainID": relay.SpecId, "client": clientAddr.String(), "provider": providerAddr.String(), "CU": strconv.FormatUint(relay.CuSum, 10), "BasePay": rewardCoins.String(), "totalCUInEpoch": strconv.FormatUint(700, 10), "uniqueIdentifier": strconv.FormatUint(relay.SessionId, 10), "descriptionString": "banana"} from["QoSReport"] = "Latency: " + relay.QosReport.Latency.String() + ", Availability: " + relay.QosReport.Availability.String() + ", Sync: " + relay.QosReport.Sync.String() from["QoSLatency"] = relay.QosReport.Latency.String() from["QoSAvailability"] = relay.QosReport.Availability.String() diff --git a/protocol/rpcprovider/rpcprovider_server.go b/protocol/rpcprovider/rpcprovider_server.go index f4ca5049b4..0190050906 100644 --- a/protocol/rpcprovider/rpcprovider_server.go +++ b/protocol/rpcprovider/rpcprovider_server.go @@ -228,7 +228,7 @@ func (rpcps *RPCProviderServer) Relay(ctx context.Context, request *pairingtypes if err != nil { extraInfo = err.Error() } - err = sdkerrors.Wrapf(relayFailureError, "On relay failure: "+extraInfo) + err = sdkerrors.Wrapf(relayFailureError, "On relay failure: %s", extraInfo) } err = utils.LavaFormatError("TryRelay Failed", err, utils.Attribute{Key: "request.SessionId", Value: request.RelaySession.SessionId}, diff --git a/protocol/statetracker/tx_sender.go b/protocol/statetracker/tx_sender.go index 51f8d54c95..ba411a3674 100644 --- a/protocol/statetracker/tx_sender.go +++ b/protocol/statetracker/tx_sender.go @@ -162,7 +162,7 @@ func (ts *TxSender) parseTxErrorsAndTryGettingANewFactory(txResultString string, } else if strings.Contains(txResultString, "insufficient fees; got:") { // handle a case where node minimum gas fees is misconfigured return ts.txFactory, parseInsufficientFeesError(txResultString, gasUsed) } - return txfactory, fmt.Errorf(txResultString) + return txfactory, fmt.Errorf("%s", txResultString) } func (ts *TxSender) simulateTxWithRetry(clientCtx client.Context, txfactory tx.Factory, msg sdk.Msg) (tx.Factory, uint64, error) { diff --git a/scripts/protocgen.sh b/scripts/protocgen.sh index 62ebc8f613..3ad976e766 100755 --- a/scripts/protocgen.sh +++ b/scripts/protocgen.sh @@ -1,4 +1,5 @@ #!/bin/bash + __dir=$(dirname "$0") . $__dir/useful_commands.sh diff --git a/scripts/test/inich_100_providers.sh b/scripts/test/inich_100_providers.sh index 46c96b23c0..367f87df2d 100755 --- a/scripts/test/inich_100_providers.sh +++ b/scripts/test/inich_100_providers.sh @@ -116,7 +116,7 @@ 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)" -lavad tx gov submit-legacy-proposal set-iprpc-data 1000000000ulava --min-cost 100ulava --add-subscriptions $(lavad keys show -a user1) --from alice -y +lavad tx gov submit-legacy-proposal set-iprpc-data 1000000000ulava --min-cost 100ulava --add-subscriptions "$(lavad keys show -a user1)" --from alice -y wait_count_blocks 1 lavad tx gov vote "$(latest_vote)" yes -y --from alice --gas-adjustment "1.5" --gas "auto" --gas-prices $GASPRICE diff --git a/scripts/test/unstake_100_providers.sh b/scripts/test/unstake_100_providers.sh index ff27bb7f33..6f629dc9ed 100755 --- a/scripts/test/unstake_100_providers.sh +++ b/scripts/test/unstake_100_providers.sh @@ -14,4 +14,5 @@ done for user in "${users[@]}"; do lavad tx pairing unstake-provider ETH1 "$(operator_address)" --from $user -y --gas-adjustment "1.5" --gas "auto" --gas-prices "$GASPRICE" + echo "Unstake failed for user: $user" >&2 done \ No newline at end of file diff --git a/testutil/e2e/protocolE2E.go b/testutil/e2e/protocolE2E.go index 7c32fe0c40..d4cc6f00b5 100644 --- a/testutil/e2e/protocolE2E.go +++ b/testutil/e2e/protocolE2E.go @@ -524,7 +524,7 @@ func jsonrpcTests(rpcURL string, testDuration time.Duration) error { } if len(errors) > 0 { - return fmt.Errorf(strings.Join(errors, ",\n")) + return fmt.Errorf("%s", strings.Join(errors, ",\n")) } return nil @@ -611,7 +611,7 @@ func tendermintTests(rpcURL string, testDuration time.Duration) error { } } if len(errors) > 0 { - return fmt.Errorf(strings.Join(errors, ",\n")) + return fmt.Errorf("%s", strings.Join(errors, ",\n")) } return nil } @@ -638,7 +638,7 @@ func tendermintURITests(rpcURL string, testDuration time.Duration) error { } if len(errors) > 0 { - return fmt.Errorf(strings.Join(errors, ",\n")) + return fmt.Errorf("%s", strings.Join(errors, ",\n")) } return nil } @@ -694,7 +694,7 @@ func restTests(rpcURL string, testDuration time.Duration) error { } if len(errors) > 0 { - return fmt.Errorf(strings.Join(errors, ",\n")) + return fmt.Errorf("%s", strings.Join(errors, ",\n")) } return nil } @@ -711,7 +711,7 @@ func restRelayTest(rpcURL string) error { } if len(errors) > 0 { - return fmt.Errorf(strings.Join(errors, ",\n")) + return fmt.Errorf("%s", strings.Join(errors, ",\n")) } return nil } @@ -777,7 +777,7 @@ func grpcTests(rpcURL string, testDuration time.Duration) error { } } if len(errors) > 0 { - return fmt.Errorf(strings.Join(errors, ",\n")) + return fmt.Errorf("%s", strings.Join(errors, ",\n")) } return nil } @@ -983,7 +983,7 @@ func (lt *lavaTest) checkQoS() error { utils.LavaFormatInfo("QOS CHECK OK") if len(errors) > 0 { - return fmt.Errorf(strings.Join(errors, ",\n")) + return fmt.Errorf("%s", strings.Join(errors, ",\n")) } return nil } @@ -1191,7 +1191,7 @@ func (lt *lavaTest) checkResponse(tendermintConsumerURL string, restConsumerURL } if len(errors) > 0 { - return fmt.Errorf(strings.Join(errors, ",\n")) + return fmt.Errorf("%s", strings.Join(errors, ",\n")) } return nil } diff --git a/testutil/e2e/proxy/helper.go b/testutil/e2e/proxy/helper.go index 1537783a30..071945786d 100644 --- a/testutil/e2e/proxy/helper.go +++ b/testutil/e2e/proxy/helper.go @@ -39,11 +39,11 @@ func createProxyRequest(req *http.Request, hostURL, body string) (proxyRequest * } reqUrlStr, err := url.QueryUnescape(reqUrl.String()) if err != nil { - return nil, fmt.Errorf(" ::: XXX ::: Could not QueryUnescape new request ::: " + reqUrl.Host + dotsStr + err.Error()) + return nil, fmt.Errorf(" ::: XXX ::: Could not QueryUnescape new request ::: %s%s%s", reqUrl.Host, dotsStr, err.Error()) } proxyReq, err := http.NewRequest(req.Method, scheme+":"+reqUrlStr, strings.NewReader(body)) if err != nil { - return nil, fmt.Errorf(" ::: XXX ::: Could not reproduce new request ::: " + reqUrl.Host + dotsStr + err.Error()) + return nil, fmt.Errorf(" ::: XXX ::: Could not reproduce new request ::: %s%s%s", reqUrl.Host, dotsStr, err.Error()) } proxyReq.Header.Set("Host", req.Host) proxyReq.Header.Set("X-Forwarded-For", req.RemoteAddr) diff --git a/utils/lavalog.go b/utils/lavalog.go index 837ede3c4c..5e7908d185 100644 --- a/utils/lavalog.go +++ b/utils/lavalog.go @@ -286,7 +286,7 @@ func LavaFormatLog(description string, err error, attributes []Attribute, severi // here we return the same type of the original error message, this handles nil case as well errRet := sdkerrors.Wrap(err, output) if errRet == nil { // we always want to return an error if lavaFormatError was called - return fmt.Errorf(output) + return fmt.Errorf("%s", output) } return errRet } diff --git a/x/epochstorage/keeper/fixated_params.go b/x/epochstorage/keeper/fixated_params.go index 09657f6e13..7c904a0253 100644 --- a/x/epochstorage/keeper/fixated_params.go +++ b/x/epochstorage/keeper/fixated_params.go @@ -174,7 +174,7 @@ func (k Keeper) GetFixatedParamsForBlock(ctx sdk.Context, fixationKey string, bl utils.Attribute{Key: "earliest", Value: earliestEpochStart}, ) } else { - err = utils.LavaFormatError("block not found", fmt.Errorf("tried to read index: "+thisIdxKey+" but wasn't found"), + err = utils.LavaFormatError("block not found", fmt.Errorf("tried to read index: %s but wasn't found", thisIdxKey), utils.Attribute{Key: "block", Value: block}, ) } diff --git a/x/pairing/keeper/keeper.go b/x/pairing/keeper/keeper.go index 0ba76fcd42..81d96d5492 100644 --- a/x/pairing/keeper/keeper.go +++ b/x/pairing/keeper/keeper.go @@ -4,6 +4,7 @@ import ( "fmt" storetypes "github.com/cosmos/cosmos-sdk/store/types" + epochstoragetypes "github.com/lavanet/lava/v2/x/epochstorage/types" timerstoretypes "github.com/lavanet/lava/v2/x/timerstore/types" "github.com/cometbft/cometbft/libs/log" @@ -34,6 +35,8 @@ type ( downtimeKeeper types.DowntimeKeeper dualstakingKeeper types.DualstakingKeeper stakingKeeper types.StakingKeeper + + pairingQueryCache *map[string][]epochstoragetypes.StakeEntry } ) @@ -71,6 +74,8 @@ func NewKeeper( ps = ps.WithKeyTable(types.ParamKeyTable()) } + emptypairingQueryCache := map[string][]epochstoragetypes.StakeEntry{} + keeper := &Keeper{ cdc: cdc, storeKey: storeKey, @@ -86,6 +91,7 @@ func NewKeeper( downtimeKeeper: downtimeKeeper, dualstakingKeeper: dualstakingKeeper, stakingKeeper: stakingKeeper, + pairingQueryCache: &emptypairingQueryCache, } // note that the timer and badgeUsedCu keys are the same (so we can use only the second arg) @@ -107,6 +113,8 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { func (k Keeper) BeginBlock(ctx sdk.Context) { if k.epochStorageKeeper.IsEpochStart(ctx) { + // reset pairing query cache every epoch + *k.pairingQueryCache = map[string][]epochstoragetypes.StakeEntry{} // remove old session payments k.RemoveOldEpochPayments(ctx) // unstake/jail unresponsive providers @@ -116,6 +124,11 @@ func (k Keeper) BeginBlock(ctx sdk.Context) { } } +func (k Keeper) EndBlock(ctx sdk.Context) { + // reset pairing relay cache every block + k.ResetPairingRelayCache(ctx) +} + func (k Keeper) InitProviderQoS(ctx sdk.Context, gs fixationtypes.GenesisState) { k.providerQosFS.Init(ctx, gs) } diff --git a/x/pairing/keeper/msg_server_relay_payment.go b/x/pairing/keeper/msg_server_relay_payment.go index 017057c1f2..c3f7c75212 100644 --- a/x/pairing/keeper/msg_server_relay_payment.go +++ b/x/pairing/keeper/msg_server_relay_payment.go @@ -14,7 +14,6 @@ import ( epochstoragetypes "github.com/lavanet/lava/v2/x/epochstorage/types" "github.com/lavanet/lava/v2/x/pairing/types" projectstypes "github.com/lavanet/lava/v2/x/projects/types" - subscriptiontypes "github.com/lavanet/lava/v2/x/subscription/types" ) type BadgeData struct { @@ -72,7 +71,6 @@ func (k msgServer) RelayPayment(goCtx context.Context, msg *types.MsgRelayPaymen var rejectedCu uint64 // aggregated rejected CU (due to badge CU overuse or provider double spending) rejected_relays_num := len(msg.Relays) - validatePairingCache := map[string][]epochstoragetypes.StakeEntry{} for relayIdx, relay := range msg.Relays { rejectedCu += relay.CuSum providerAddr, err := sdk.AccAddressFromBech32(relay.Provider) @@ -180,44 +178,28 @@ func (k msgServer) RelayPayment(goCtx context.Context, msg *types.MsgRelayPaymen ) } - // generate validate pairing cache key with CuTrackerKey() to reuse code (doesn't relate to CU tracking at all) - validatePairingKey := subscriptiontypes.CuTrackerKey(clientAddr.String(), relay.Provider, relay.SpecId) var providers []epochstoragetypes.StakeEntry allowedCU := uint64(0) - val, ok := validatePairingCache[validatePairingKey] - if ok { - providers = val - strictestPolicy, _, err := k.GetProjectStrictestPolicy(ctx, project, relay.SpecId, epochStart) - if err != nil { - return nil, utils.LavaFormatError("strictest policy calculation for pairing validation cache failed", err, - utils.LogAttr("project", project.Index), - utils.LogAttr("chainID", relay.SpecId), - utils.LogAttr("block", strconv.FormatUint(epochStart, 10)), - ) - } - allowedCU = strictestPolicy.EpochCuLimit - } else { - isValidPairing := false - isValidPairing, allowedCU, providers, err = k.Keeper.ValidatePairingForClient( - ctx, - relay.SpecId, - providerAddr, - uint64(relay.Epoch), - project, + + isValidPairing := false + isValidPairing, allowedCU, providers, err = k.Keeper.ValidatePairingForClient( + ctx, + relay.SpecId, + providerAddr, + uint64(relay.Epoch), + project, + ) + if err != nil { + return nil, utils.LavaFormatWarning("invalid pairing on proof of relay", err, + utils.Attribute{Key: "client", Value: clientAddr.String()}, + utils.Attribute{Key: "provider", Value: providerAddr.String()}, + ) + } + if !isValidPairing { + return nil, utils.LavaFormatWarning("invalid pairing on proof of relay", fmt.Errorf("pairing result doesn't include provider"), + utils.Attribute{Key: "client", Value: clientAddr.String()}, + utils.Attribute{Key: "provider", Value: providerAddr.String()}, ) - if err != nil { - return nil, utils.LavaFormatWarning("invalid pairing on proof of relay", err, - utils.Attribute{Key: "client", Value: clientAddr.String()}, - utils.Attribute{Key: "provider", Value: providerAddr.String()}, - ) - } - if !isValidPairing { - return nil, utils.LavaFormatWarning("invalid pairing on proof of relay", fmt.Errorf("pairing result doesn't include provider"), - utils.Attribute{Key: "client", Value: clientAddr.String()}, - utils.Attribute{Key: "provider", Value: providerAddr.String()}, - ) - } - validatePairingCache[validatePairingKey] = providers } rewardedCU, err := k.Keeper.EnforceClientCUsUsageInEpoch(ctx, relay.CuSum, allowedCU, totalCUInEpochForUserProvider, clientAddr, relay.SpecId, uint64(relay.Epoch)) @@ -239,7 +221,16 @@ func (k msgServer) RelayPayment(goCtx context.Context, msg *types.MsgRelayPaymen if len(msg.DescriptionString) > 20 { msg.DescriptionString = msg.DescriptionString[:20] } - details := map[string]string{"chainID": fmt.Sprintf(relay.SpecId), "epoch": strconv.FormatInt(relay.Epoch, 10), "client": clientAddr.String(), "provider": providerAddr.String(), "CU": strconv.FormatUint(relay.CuSum, 10), "totalCUInEpoch": strconv.FormatUint(totalCUInEpochForUserProvider, 10), "uniqueIdentifier": strconv.FormatUint(relay.SessionId, 10), "descriptionString": msg.DescriptionString} + details := map[string]string{ + "chainID": relay.SpecId, + "epoch": strconv.FormatInt(relay.Epoch, 10), + "client": clientAddr.String(), + "provider": providerAddr.String(), + "CU": strconv.FormatUint(relay.CuSum, 10), + "totalCUInEpoch": strconv.FormatUint(totalCUInEpochForUserProvider, 10), + "uniqueIdentifier": strconv.FormatUint(relay.SessionId, 10), + "descriptionString": msg.DescriptionString, + } details["rewardedCU"] = strconv.FormatUint(relay.CuSum, 10) if relay.QosReport != nil { diff --git a/x/pairing/keeper/pairing.go b/x/pairing/keeper/pairing.go index 9d1732d98f..62c91d477f 100644 --- a/x/pairing/keeper/pairing.go +++ b/x/pairing/keeper/pairing.go @@ -80,7 +80,8 @@ func (k Keeper) GetPairingForClient(ctx sdk.Context, chainID string, clientAddre return nil, fmt.Errorf("invalid user for pairing: %s", err.Error()) } - providers, _, _, err = k.getPairingForClient(ctx, chainID, block, strictestPolicy, cluster, project.Index, false) + providers, _, _, err = k.getPairingForClient(ctx, chainID, block, strictestPolicy, cluster, project.Index, false, true) + return providers, err } @@ -89,7 +90,7 @@ func (k Keeper) CalculatePairingChance(ctx sdk.Context, provider string, chainID totalScore := cosmosmath.ZeroUint() providerScore := cosmosmath.ZeroUint() - _, _, scores, err := k.getPairingForClient(ctx, chainID, uint64(ctx.BlockHeight()), policy, cluster, "dummy", true) + _, _, scores, err := k.getPairingForClient(ctx, chainID, uint64(ctx.BlockHeight()), policy, cluster, "dummy", true, false) if err != nil { return cosmosmath.LegacyZeroDec(), err } @@ -116,11 +117,22 @@ func (k Keeper) CalculatePairingChance(ctx sdk.Context, provider string, chainID // function used to get a new pairing from provider and client // first argument has all metadata, second argument is only the addresses -func (k Keeper) getPairingForClient(ctx sdk.Context, chainID string, block uint64, policy *planstypes.Policy, cluster string, projectIndex string, calcChance bool) (providers []epochstoragetypes.StakeEntry, allowedCU uint64, providerScores []*pairingscores.PairingScore, errorRet error) { +// useCache is a boolean argument that is used to determine whether pairing cache should be used +// Note: useCache should only be true for queries! functions that write to the state and use this function should never put useCache=true +func (k Keeper) getPairingForClient(ctx sdk.Context, chainID string, block uint64, policy *planstypes.Policy, cluster string, projectIndex string, calcChance bool, useCache bool) (providers []epochstoragetypes.StakeEntry, allowedCU uint64, providerScores []*pairingscores.PairingScore, errorRet error) { epoch, providersType, err := k.VerifyPairingData(ctx, chainID, block) if err != nil { return nil, 0, nil, fmt.Errorf("invalid pairing data: %s", err) } + + // to be used only in queries as this changes gas calculations, and therefore must not be part of consensus + if useCache { + providers, found := k.GetPairingQueryCache(projectIndex, chainID, epoch) + if found { + return providers, policy.EpochCuLimit, nil, nil + } + } + stakeEntries := k.epochStorageKeeper.GetAllStakeEntriesForEpochChainId(ctx, epoch, chainID) if len(stakeEntries) == 0 { return nil, 0, nil, fmt.Errorf("did not find providers for pairing: epoch:%d, chainID: %s", block, chainID) @@ -137,6 +149,9 @@ func (k Keeper) getPairingForClient(ctx sdk.Context, chainID string, block uint6 stakeEntriesFiltered = append(stakeEntriesFiltered, stakeEntries[i]) } } + if useCache { + k.SetPairingQueryCache(projectIndex, chainID, epoch, stakeEntriesFiltered) + } return stakeEntriesFiltered, policy.EpochCuLimit, nil, nil } @@ -156,6 +171,9 @@ func (k Keeper) getPairingForClient(ctx sdk.Context, chainID string, block uint6 for _, score := range providerScores { filteredEntries = append(filteredEntries, *score.Provider) } + if useCache { + k.SetPairingQueryCache(projectIndex, chainID, epoch, filteredEntries) + } return filteredEntries, policy.EpochCuLimit, nil, nil } @@ -176,7 +194,11 @@ func (k Keeper) getPairingForClient(ctx sdk.Context, chainID string, block uint6 prevGroupSlot = group } - return providers, policy.EpochCuLimit, providerScores, err + if useCache { + k.SetPairingQueryCache(projectIndex, chainID, epoch, providers) + } + + return providers, policy.EpochCuLimit, providerScores, nil } func (k Keeper) GetProjectStrictestPolicy(ctx sdk.Context, project projectstypes.Project, chainID string, block uint64) (*planstypes.Policy, string, error) { @@ -315,19 +337,23 @@ func (k Keeper) ValidatePairingForClient(ctx sdk.Context, chainID string, provid if epoch != reqEpoch { return false, allowedCU, []epochstoragetypes.StakeEntry{}, utils.LavaFormatError("requested block is not an epoch start", nil, utils.Attribute{Key: "epoch", Value: epoch}, utils.Attribute{Key: "requested", Value: reqEpoch}) } - clientAddr, err := sdk.AccAddressFromBech32(project.Subscription) - if err != nil { - return false, allowedCU, []epochstoragetypes.StakeEntry{}, err - } - strictestPolicy, cluster, err := k.GetProjectStrictestPolicy(ctx, project, chainID, reqEpoch) - if err != nil { - return false, allowedCU, []epochstoragetypes.StakeEntry{}, fmt.Errorf("invalid user for pairing: %s", err.Error()) - } + validAddresses, allowedCU, ok := k.GetPairingRelayCache(ctx, project.Index, chainID, epoch) + if !ok { + _, err := sdk.AccAddressFromBech32(project.Subscription) + if err != nil { + return false, allowedCU, []epochstoragetypes.StakeEntry{}, err + } - validAddresses, allowedCU, _, err := k.getPairingForClient(ctx, chainID, epoch, strictestPolicy, cluster, project.Index, false) - if err != nil { - return false, allowedCU, []epochstoragetypes.StakeEntry{}, err + strictestPolicy, cluster, err := k.GetProjectStrictestPolicy(ctx, project, chainID, reqEpoch) + if err != nil { + return false, allowedCU, []epochstoragetypes.StakeEntry{}, fmt.Errorf("invalid user for pairing: %s", err.Error()) + } + + validAddresses, allowedCU, _, err = k.getPairingForClient(ctx, chainID, epoch, strictestPolicy, cluster, project.Index, false, false) + if err != nil { + return false, allowedCU, []epochstoragetypes.StakeEntry{}, err + } } for _, possibleAddr := range validAddresses { @@ -336,13 +362,17 @@ func (k Keeper) ValidatePairingForClient(ctx sdk.Context, chainID string, provid // panic:ok: provider address saved on chain must be valid utils.LavaFormatPanic("critical: invalid provider address for payment", err, utils.Attribute{Key: "chainID", Value: chainID}, - utils.Attribute{Key: "client", Value: clientAddr.String()}, + utils.Attribute{Key: "client", Value: project.Subscription}, utils.Attribute{Key: "provider", Value: providerAccAddr.String()}, utils.Attribute{Key: "epochBlock", Value: strconv.FormatUint(epoch, 10)}, ) } if providerAccAddr.Equals(providerAddress) { + if !ok { + // if we had a cache miss, set cache + k.SetPairingRelayCache(ctx, project.Index, chainID, epoch, validAddresses, allowedCU) + } return true, allowedCU, validAddresses, nil } } diff --git a/x/pairing/keeper/pairing_cache.go b/x/pairing/keeper/pairing_cache.go new file mode 100644 index 0000000000..c0fed2c608 --- /dev/null +++ b/x/pairing/keeper/pairing_cache.go @@ -0,0 +1,64 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + epochstoragetypes "github.com/lavanet/lava/v2/x/epochstorage/types" + "github.com/lavanet/lava/v2/x/pairing/types" +) + +func (k Keeper) SetPairingRelayCache(ctx sdk.Context, project string, chainID string, epoch uint64, pairedProviders []epochstoragetypes.StakeEntry, allowedCu uint64) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.PairingRelayCachePrefix) + cache := types.PairingRelayCache{Entries: pairedProviders, AllowedCu: allowedCu} + b := k.cdc.MustMarshal(&cache) + store.Set([]byte(types.NewPairingCacheKey(project, chainID, epoch)), b) +} + +func (k Keeper) GetPairingRelayCache(ctx sdk.Context, project string, chainID string, epoch uint64) ([]epochstoragetypes.StakeEntry, uint64, bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.PairingRelayCachePrefix) + b := store.Get([]byte(types.NewPairingCacheKey(project, chainID, epoch))) + if b == nil { + return []epochstoragetypes.StakeEntry{}, 0, false + } + var cache types.PairingRelayCache + k.cdc.MustUnmarshal(b, &cache) + return cache.Entries, cache.AllowedCu, true +} + +// ResetPairingRelayCache is used to remove all entries from the PairingRelayCache KV store +// this function is called in the module's EndBlock so the data written in the KV store +// will be deleted before it's written to the state +func (k Keeper) ResetPairingRelayCache(ctx sdk.Context) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.PairingRelayCachePrefix) + iterator := sdk.KVStorePrefixIterator(store, []byte{}) + + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + store.Delete(iterator.Key()) + } +} + +// the cache used for the query, does not write into state +func (k Keeper) SetPairingQueryCache(project string, chainID string, epoch uint64, pairedProviders []epochstoragetypes.StakeEntry) { + if k.pairingQueryCache == nil { + // pairing cache is not initialized, will be in next epoch so simply skip + return + } + key := types.NewPairingCacheKey(project, chainID, epoch) + + (*k.pairingQueryCache)[key] = pairedProviders +} + +func (k Keeper) GetPairingQueryCache(project string, chainID string, epoch uint64) ([]epochstoragetypes.StakeEntry, bool) { + if k.pairingQueryCache == nil { + // pairing cache is not initialized, will be in next epoch so simply skip + return nil, false + } + key := types.NewPairingCacheKey(project, chainID, epoch) + if providers, ok := (*k.pairingQueryCache)[key]; ok { + return providers, true + } + + return nil, false +} diff --git a/x/pairing/keeper/pairing_cache_test.go b/x/pairing/keeper/pairing_cache_test.go new file mode 100644 index 0000000000..4e2758e3b0 --- /dev/null +++ b/x/pairing/keeper/pairing_cache_test.go @@ -0,0 +1,121 @@ +package keeper_test + +import ( + "testing" + + "github.com/lavanet/lava/v2/testutil/common" + "github.com/stretchr/testify/require" +) + +// TestPairingQueryCache tests the following: +// 1. The pairing query cache is reset every epoch +// 2. Getting pairing with a query using an existent cache entry consumes fewer gas than without one +func TestPairingQueryCache(t *testing.T) { + ts := newTester(t) + ts.setupForPayments(1, 1, 0) // 1 provider, 1 client, default providers-to-pair + + _, consumer := ts.GetAccount(common.CONSUMER, 0) + + getPairingGas := func(ts *tester) uint64 { + gm := ts.Ctx.GasMeter() + before := gm.GasConsumed() + _, err := ts.QueryPairingGetPairing(ts.spec.Index, consumer) + require.NoError(t, err) + return gm.GasConsumed() - before + } + + // query for pairing for the first time - empty cache + emptyCacheGas := getPairingGas(ts) + + // query for pairing for the second time - non-empty cache + filledCacheGas := getPairingGas(ts) + + // second time gas should be smaller than first time + require.Less(t, filledCacheGas, emptyCacheGas) + + // advance block to test it stays the same (should still be less than empty cache gas) + ts.AdvanceBlock() + filledAfterBlockCacheGas := getPairingGas(ts) + require.Less(t, filledAfterBlockCacheGas, emptyCacheGas) + + // advance epoch to reset the cache + ts.AdvanceEpoch() + emptyCacheAgainGas := getPairingGas(ts) + require.Equal(t, emptyCacheGas, emptyCacheAgainGas) +} + +// TestPairingQueryCache tests the following: +// 1. The pairing relay cache is reset every block +// 2. Getting pairing in relay payment using an existent cache entry consumes fewer gas than without one +func TestPairingRelayCache(t *testing.T) { + ts := newTester(t) + ts.setupForPayments(1, 1, 0) // 1 provider, 1 client, default providers-to-pair + + consumer, _ := ts.GetAccount(common.CONSUMER, 0) + provider, _ := ts.GetAccount(common.PROVIDER, 0) + + getRelayPairingGas := func(ts *tester) uint64 { + gm := ts.Ctx.GasMeter() + before := gm.GasConsumed() + relayPayment := sendRelay(ts, provider.Addr.String(), consumer, []string{ts.spec.Index}) + _, err := ts.TxPairingRelayPayment(relayPayment.Creator, relayPayment.Relays[0]) + require.NoError(t, err) + return gm.GasConsumed() - before + } + + // query for pairing for the first time - empty cache + emptyCacheGas := getRelayPairingGas(ts) + + // query for pairing for the second time - non-empty cache + filledCacheGas := getRelayPairingGas(ts) + + // second time gas should be smaller than first time + require.Less(t, filledCacheGas, emptyCacheGas) + + // advance block to to reset the cache + ts.AdvanceBlock() + emptyCacheAgainGas := getRelayPairingGas(ts) + require.InEpsilon(t, emptyCacheGas, emptyCacheAgainGas, 0.05) +} + +// TestPairingRelayCacheReset tests that the pairing relay cache reset truly returns the state to its previous +// empty cache state by verifying the gas is exactly the same when running the same test with different testers +func TestPairingRelayCacheReset(t *testing.T) { + firstEmptyCache, firstNonEmptyCache, secondEmptyCache, secondNonEmptyCache := uint64(0), uint64(0), uint64(0), uint64(0) + for i := 0; i < 2; i++ { + ts := newTester(t) + ts.setupForPayments(1, 1, 0) // 1 provider, 1 client, default providers-to-pair + + consumer, _ := ts.GetAccount(common.CONSUMER, 0) + provider, _ := ts.GetAccount(common.PROVIDER, 0) + + getRelayPairingGas := func(ts *tester) uint64 { + gm := ts.Ctx.GasMeter() + before := gm.GasConsumed() + relayPayment := sendRelay(ts, provider.Addr.String(), consumer, []string{ts.spec.Index}) + _, err := ts.TxPairingRelayPayment(relayPayment.Creator, relayPayment.Relays[0]) + require.NoError(t, err) + return gm.GasConsumed() - before + } + + // query for pairing for the first time - empty cache + emptyCacheGas := getRelayPairingGas(ts) + + // query for pairing for the second time - non-empty cache + filledCacheGas := getRelayPairingGas(ts) + + // second time gas should be smaller than first time + require.Less(t, filledCacheGas, emptyCacheGas) + + if i == 0 { + firstEmptyCache = emptyCacheGas + firstNonEmptyCache = filledCacheGas + } else { + secondEmptyCache = emptyCacheGas + secondNonEmptyCache = filledCacheGas + } + } + + require.Equal(t, firstEmptyCache, secondEmptyCache) + require.Equal(t, firstNonEmptyCache, secondNonEmptyCache) +} diff --git a/x/pairing/module.go b/x/pairing/module.go index f8cd964cfe..ba70ae06bc 100644 --- a/x/pairing/module.go +++ b/x/pairing/module.go @@ -166,6 +166,7 @@ func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { // EndBlock executes all ABCI EndBlock logic respective to the capability module. It // returns no validator updates. -func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { +func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + am.keeper.EndBlock(ctx) return []abci.ValidatorUpdate{} } diff --git a/x/pairing/types/pairing_cache.go b/x/pairing/types/pairing_cache.go new file mode 100644 index 0000000000..0ddfc473f8 --- /dev/null +++ b/x/pairing/types/pairing_cache.go @@ -0,0 +1,10 @@ +package types + +import "strconv" + +var PairingRelayCachePrefix = []byte("PairingRelayCache") + +func NewPairingCacheKey(project string, chainID string, epoch uint64) string { + epochStr := strconv.FormatUint(epoch, 10) + return project + " " + chainID + " " + epochStr +} diff --git a/x/pairing/types/relay.pb.go b/x/pairing/types/relay.pb.go index a5b9c357bc..8df281a273 100644 --- a/x/pairing/types/relay.pb.go +++ b/x/pairing/types/relay.pb.go @@ -10,6 +10,7 @@ import ( _ "github.com/cosmos/gogoproto/gogoproto" grpc1 "github.com/cosmos/gogoproto/grpc" proto "github.com/cosmos/gogoproto/proto" + types "github.com/lavanet/lava/v2/x/epochstorage/types" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" @@ -802,6 +803,58 @@ func (m *QualityOfServiceReport) XXX_DiscardUnknown() { var xxx_messageInfo_QualityOfServiceReport proto.InternalMessageInfo +type PairingRelayCache struct { + Entries []types.StakeEntry `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries"` + AllowedCu uint64 `protobuf:"varint,2,opt,name=allowed_cu,json=allowedCu,proto3" json:"allowed_cu,omitempty"` +} + +func (m *PairingRelayCache) Reset() { *m = PairingRelayCache{} } +func (m *PairingRelayCache) String() string { return proto.CompactTextString(m) } +func (*PairingRelayCache) ProtoMessage() {} +func (*PairingRelayCache) Descriptor() ([]byte, []int) { + return fileDescriptor_a61d253b10eeeb9e, []int{10} +} +func (m *PairingRelayCache) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PairingRelayCache) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PairingRelayCache.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 *PairingRelayCache) XXX_Merge(src proto.Message) { + xxx_messageInfo_PairingRelayCache.Merge(m, src) +} +func (m *PairingRelayCache) XXX_Size() int { + return m.Size() +} +func (m *PairingRelayCache) XXX_DiscardUnknown() { + xxx_messageInfo_PairingRelayCache.DiscardUnknown(m) +} + +var xxx_messageInfo_PairingRelayCache proto.InternalMessageInfo + +func (m *PairingRelayCache) GetEntries() []types.StakeEntry { + if m != nil { + return m.Entries + } + return nil +} + +func (m *PairingRelayCache) GetAllowedCu() uint64 { + if m != nil { + return m.AllowedCu + } + return 0 +} + func init() { proto.RegisterType((*ProbeRequest)(nil), "lavanet.lava.pairing.ProbeRequest") proto.RegisterType((*ProbeReply)(nil), "lavanet.lava.pairing.ProbeReply") @@ -813,88 +866,94 @@ func init() { proto.RegisterType((*RelayRequest)(nil), "lavanet.lava.pairing.RelayRequest") proto.RegisterType((*RelayReply)(nil), "lavanet.lava.pairing.RelayReply") proto.RegisterType((*QualityOfServiceReport)(nil), "lavanet.lava.pairing.QualityOfServiceReport") + proto.RegisterType((*PairingRelayCache)(nil), "lavanet.lava.pairing.PairingRelayCache") } func init() { proto.RegisterFile("lavanet/lava/pairing/relay.proto", fileDescriptor_a61d253b10eeeb9e) } var fileDescriptor_a61d253b10eeeb9e = []byte{ - // 1210 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xdd, 0x6e, 0x1b, 0xc5, - 0x17, 0xf7, 0xfa, 0x23, 0xb6, 0x8f, 0xb7, 0x69, 0xff, 0xd3, 0xa6, 0xb5, 0x52, 0xfd, 0x1d, 0x77, - 0x91, 0x42, 0x54, 0x81, 0x0d, 0x01, 0x71, 0x81, 0x84, 0x54, 0x4c, 0x22, 0x08, 0x14, 0x9a, 0x6e, - 0xe0, 0x26, 0x12, 0xda, 0x8e, 0x77, 0x27, 0x9b, 0xa1, 0xeb, 0x9d, 0xcd, 0xcc, 0xac, 0x89, 0x79, - 0x01, 0xae, 0x90, 0x78, 0x08, 0x9e, 0x80, 0x87, 0xa8, 0x7a, 0xd9, 0x4b, 0x84, 0x44, 0x84, 0x92, - 0x37, 0x40, 0x3c, 0x00, 0x9a, 0x0f, 0x7f, 0x25, 0x4e, 0x50, 0x80, 0xab, 0x9d, 0xf9, 0xcd, 0xd9, - 0x73, 0xce, 0xfc, 0xce, 0x39, 0xbf, 0x5d, 0x68, 0x27, 0x78, 0x88, 0x53, 0x22, 0xbb, 0xea, 0xd9, - 0xcd, 0x30, 0xe5, 0x34, 0x8d, 0xbb, 0x9c, 0x24, 0x78, 0xd4, 0xc9, 0x38, 0x93, 0x0c, 0xdd, 0xb1, - 0x16, 0x1d, 0xf5, 0xec, 0x58, 0x8b, 0xd5, 0x3b, 0x31, 0x8b, 0x99, 0x36, 0xe8, 0xaa, 0x95, 0xb1, - 0x5d, 0x6d, 0xc5, 0x8c, 0xc5, 0x09, 0xe9, 0xea, 0x5d, 0x3f, 0x3f, 0xe8, 0x7e, 0xcb, 0x71, 0x96, - 0x11, 0x2e, 0xec, 0xf9, 0xda, 0xf9, 0x73, 0x49, 0x07, 0x44, 0x48, 0x3c, 0xc8, 0x8c, 0x81, 0xf7, - 0x0c, 0xdc, 0x5d, 0xce, 0xfa, 0xc4, 0x27, 0x47, 0x39, 0x11, 0x12, 0x21, 0x28, 0xc7, 0x39, 0x8d, - 0x9a, 0x4e, 0xdb, 0xd9, 0x28, 0xfb, 0x7a, 0x8d, 0xee, 0x41, 0x55, 0x64, 0x24, 0x0c, 0x68, 0xd4, - 0x2c, 0xb6, 0x9d, 0x8d, 0xba, 0xbf, 0xa4, 0xb6, 0x3b, 0x11, 0x7a, 0x0d, 0x6e, 0xe0, 0x8c, 0x06, - 0x34, 0x95, 0x84, 0x1f, 0xe0, 0x90, 0x34, 0x4b, 0xfa, 0xd8, 0xc5, 0x19, 0xdd, 0x19, 0x63, 0xde, - 0x0b, 0x07, 0xc0, 0x86, 0xc8, 0x92, 0xd1, 0xc2, 0x00, 0x0f, 0xc0, 0x4d, 0xb0, 0x24, 0x42, 0x06, - 0xfd, 0x84, 0x85, 0xcf, 0x75, 0x94, 0x92, 0xdf, 0x30, 0x58, 0x4f, 0x41, 0xe8, 0x3d, 0xb8, 0x77, - 0x40, 0x53, 0x9c, 0xd0, 0xef, 0x48, 0x64, 0xac, 0x44, 0x70, 0x88, 0xc5, 0x21, 0x11, 0x3a, 0xa8, - 0xeb, 0xaf, 0x4c, 0x8e, 0xf5, 0x0b, 0xe2, 0x13, 0x7d, 0x88, 0xfe, 0x0f, 0xa0, 0x68, 0x0c, 0x48, - 0xc6, 0xc2, 0xc3, 0x66, 0x59, 0x07, 0xad, 0x2b, 0x64, 0x5b, 0x01, 0xe8, 0x21, 0xfc, 0x4f, 0x1f, - 0xcf, 0x85, 0xaf, 0x68, 0xab, 0x9b, 0xea, 0xe0, 0xf1, 0x34, 0x05, 0xef, 0x45, 0x19, 0x5c, 0x5f, - 0xd5, 0x69, 0x8f, 0x08, 0x41, 0x59, 0x3a, 0xcb, 0x8b, 0x33, 0xc7, 0xcb, 0x03, 0x70, 0x43, 0x96, - 0x4a, 0x92, 0x4a, 0x9d, 0xa3, 0xbe, 0x8f, 0xeb, 0x37, 0x2c, 0xa6, 0x32, 0x53, 0x79, 0x09, 0xe3, - 0x46, 0xbd, 0x5e, 0x32, 0x79, 0x59, 0x64, 0x27, 0x42, 0x2b, 0xb0, 0x14, 0xe6, 0x81, 0xc8, 0x07, - 0x36, 0xe5, 0x4a, 0x98, 0xef, 0xe5, 0x03, 0xb4, 0x0a, 0xb5, 0x8c, 0xb3, 0x21, 0x8d, 0x08, 0xd7, - 0x59, 0xd6, 0xfd, 0xc9, 0x1e, 0xdd, 0x87, 0xba, 0xee, 0xa2, 0x20, 0xcd, 0x07, 0xcd, 0x25, 0xfd, - 0x56, 0x4d, 0x03, 0x5f, 0xe4, 0x03, 0xf4, 0x19, 0xc0, 0x11, 0x13, 0x01, 0x27, 0x19, 0xe3, 0xb2, - 0x59, 0x6d, 0x3b, 0x1b, 0x8d, 0xcd, 0x37, 0x3a, 0x8b, 0x1a, 0xad, 0xf3, 0x34, 0xc7, 0x09, 0x95, - 0xa3, 0x27, 0x07, 0x7b, 0x84, 0x0f, 0x69, 0xa8, 0xca, 0xc6, 0xb8, 0xf4, 0xeb, 0x47, 0x4c, 0x98, - 0x25, 0xba, 0x03, 0x15, 0x43, 0x67, 0x4d, 0xd7, 0xc9, 0x6c, 0xd0, 0xd7, 0x70, 0x37, 0x4f, 0x39, - 0x11, 0x19, 0x4b, 0x05, 0x1d, 0x92, 0x60, 0x9c, 0x98, 0x68, 0xd6, 0xdb, 0xa5, 0x8d, 0xc6, 0xe6, - 0xfa, 0xe2, 0x70, 0xc6, 0x27, 0x89, 0x76, 0xad, 0xb9, 0xbf, 0x32, 0xeb, 0x65, 0x8c, 0x0a, 0xe4, - 0xc1, 0x0d, 0x5d, 0xa9, 0xf0, 0x10, 0x53, 0xcd, 0x19, 0xe8, 0xfb, 0x37, 0x14, 0xf8, 0x91, 0xc2, - 0x76, 0x22, 0x74, 0x0b, 0x4a, 0x82, 0xc6, 0xcd, 0x86, 0xa6, 0x5b, 0x2d, 0xd1, 0xdb, 0x50, 0xe9, - 0xe3, 0x28, 0x26, 0x4d, 0x57, 0x5f, 0xf9, 0xfe, 0xe2, 0x1c, 0x7a, 0xca, 0xc4, 0x37, 0x96, 0xe8, - 0x19, 0xac, 0x28, 0xaa, 0xc8, 0x71, 0x48, 0x92, 0x84, 0xa4, 0x21, 0x19, 0xb3, 0x76, 0xe3, 0x1f, - 0xb0, 0x76, 0xfb, 0x88, 0x89, 0xed, 0x89, 0x27, 0x03, 0xaa, 0x89, 0xa8, 0xe8, 0x90, 0x6a, 0x80, - 0xc2, 0x3c, 0xc0, 0x49, 0xc2, 0x42, 0x2c, 0x29, 0x4b, 0xed, 0x54, 0xb8, 0x61, 0xfe, 0xe1, 0x04, - 0x9b, 0xd2, 0x5d, 0x34, 0xad, 0x60, 0xe8, 0x6e, 0x42, 0x15, 0x47, 0x11, 0x27, 0x42, 0xd8, 0xa9, - 0x1b, 0x6f, 0x2f, 0x32, 0x55, 0xbe, 0xc8, 0xd4, 0x1a, 0x34, 0x32, 0xce, 0xbe, 0x21, 0xa1, 0x0c, - 0x14, 0x63, 0x15, 0xcd, 0x18, 0x58, 0x68, 0x8f, 0xc6, 0x2a, 0xb3, 0x21, 0xe5, 0x32, 0xc7, 0x89, - 0x1d, 0x1d, 0xd3, 0x51, 0xae, 0x05, 0xf5, 0xf4, 0x78, 0xbf, 0x15, 0xe1, 0x96, 0x9e, 0x88, 0x5d, - 0x4e, 0x87, 0x58, 0x92, 0x2d, 0x2c, 0x31, 0x7a, 0x1d, 0x6e, 0x86, 0x2c, 0x4d, 0x49, 0xa8, 0x92, - 0x0f, 0xe4, 0x28, 0x23, 0x76, 0x3a, 0x96, 0xa7, 0xf0, 0x97, 0xa3, 0x8c, 0xa8, 0xf1, 0x51, 0xea, - 0x91, 0xf3, 0x64, 0x2c, 0x2b, 0x38, 0xa3, 0x5f, 0xf1, 0x44, 0x49, 0x44, 0x84, 0x25, 0xb6, 0x83, - 0xad, 0xd7, 0x2a, 0x1f, 0x6e, 0x24, 0xca, 0x0e, 0x69, 0x59, 0xf7, 0x9e, 0x6b, 0x41, 0x23, 0x12, - 0x17, 0xf4, 0xa8, 0x72, 0x51, 0x8f, 0x94, 0x77, 0x81, 0x13, 0xa9, 0x2f, 0xe4, 0xfa, 0x7a, 0x8d, - 0x1e, 0x41, 0x6d, 0x40, 0x24, 0xd6, 0x51, 0xab, 0xba, 0x5b, 0x5b, 0x8b, 0xcb, 0xfc, 0xb9, 0xb5, - 0xea, 0x95, 0x5f, 0x9e, 0xac, 0x15, 0xfc, 0xc9, 0x5b, 0xaa, 0x48, 0x38, 0x8a, 0x58, 0xaa, 0x67, - 0xa2, 0xee, 0x9b, 0x0d, 0x6a, 0x01, 0x90, 0x63, 0x49, 0x52, 0x35, 0xd5, 0x66, 0x0e, 0xea, 0xfe, - 0x0c, 0x62, 0x54, 0x80, 0xa4, 0xf6, 0x4a, 0xa0, 0xaf, 0x54, 0x57, 0x88, 0x51, 0x9c, 0x1f, 0x1c, - 0xc5, 0xef, 0xfc, 0x7c, 0xcc, 0x16, 0xde, 0x99, 0x2f, 0xfc, 0x3a, 0x2c, 0x47, 0x54, 0x4c, 0x59, - 0x16, 0xb6, 0x63, 0xce, 0xa1, 0xe8, 0x2e, 0x2c, 0x11, 0xce, 0x19, 0x17, 0x56, 0x77, 0xec, 0x4e, - 0x35, 0xc5, 0xe4, 0xf3, 0x10, 0x08, 0xcb, 0x30, 0x4c, 0xa0, 0x3d, 0xef, 0x5d, 0xa8, 0x8d, 0x09, - 0x50, 0x34, 0xa6, 0x78, 0x30, 0xae, 0xad, 0x5e, 0x2b, 0x12, 0x86, 0x38, 0xc9, 0x89, 0xad, 0xa7, - 0xd9, 0x78, 0x3f, 0x39, 0x56, 0x37, 0xc7, 0xdf, 0x98, 0x8f, 0x55, 0x2d, 0x95, 0x52, 0x59, 0xbd, - 0xd3, 0x3e, 0x1a, 0x9b, 0xde, 0x65, 0x02, 0x31, 0x95, 0x5c, 0x55, 0xef, 0x19, 0x01, 0xde, 0x06, - 0x30, 0x8e, 0x74, 0xe1, 0x8a, 0xda, 0xcb, 0xfa, 0x15, 0x5e, 0x66, 0xda, 0xd4, 0x37, 0x62, 0xa9, - 0x96, 0x9f, 0x96, 0x6b, 0xa5, 0x5b, 0x65, 0xef, 0x4f, 0x07, 0xc0, 0xa6, 0x69, 0xbf, 0x53, 0xda, - 0xab, 0x33, 0xd3, 0x84, 0x56, 0x5f, 0x8a, 0x53, 0x7d, 0x39, 0xff, 0xe5, 0x2a, 0x5f, 0xeb, 0xcb, - 0x55, 0xf9, 0x9b, 0x2f, 0x97, 0xa0, 0xb1, 0x7d, 0xc3, 0x76, 0x6b, 0x5d, 0xd0, 0xd8, 0x18, 0xfd, - 0xfb, 0x96, 0xb5, 0xd7, 0xfe, 0xb9, 0x08, 0x77, 0x17, 0x8b, 0x17, 0xda, 0x87, 0xaa, 0xba, 0x48, - 0x1a, 0x8e, 0x4c, 0x95, 0x7b, 0x8f, 0x94, 0x87, 0x5f, 0x4f, 0xd6, 0xd6, 0x63, 0x2a, 0x0f, 0xf3, - 0x7e, 0x27, 0x64, 0x83, 0x6e, 0xc8, 0xc4, 0x80, 0x09, 0xfb, 0x78, 0x53, 0x44, 0xcf, 0xbb, 0x6a, - 0xe4, 0x45, 0x67, 0x8b, 0x84, 0x7f, 0x9c, 0xac, 0x2d, 0x8f, 0xf0, 0x20, 0x79, 0xdf, 0x7b, 0x6c, - 0xdc, 0x78, 0xfe, 0xd8, 0x21, 0xa2, 0xe0, 0xe2, 0x21, 0xa6, 0x09, 0xee, 0x53, 0x15, 0xda, 0x74, - 0x4c, 0x6f, 0xfb, 0xda, 0x01, 0x6e, 0x9b, 0x00, 0xb3, 0xbe, 0x3c, 0x7f, 0xce, 0x35, 0x7a, 0x0a, - 0x65, 0x31, 0x4a, 0x43, 0x23, 0x93, 0xbd, 0x0f, 0xae, 0x1d, 0xa2, 0x61, 0x42, 0x28, 0x1f, 0x9e, - 0xaf, 0x5d, 0x6d, 0x7e, 0x5f, 0x84, 0xaa, 0xee, 0x15, 0xc2, 0xd1, 0x13, 0xa8, 0xe8, 0x25, 0xba, - 0xaa, 0x7f, 0x6d, 0xeb, 0xaf, 0xb6, 0xaf, 0xb4, 0xc9, 0x92, 0x91, 0x57, 0x40, 0xfb, 0xb0, 0x6c, - 0x7a, 0x3e, 0xef, 0x8b, 0x90, 0xd3, 0x3e, 0xf9, 0xaf, 0x3c, 0xbf, 0xe5, 0xa8, 0x64, 0xf5, 0xbf, - 0xd8, 0x65, 0x2e, 0x67, 0xff, 0x05, 0x2f, 0x73, 0x39, 0xfd, 0x99, 0xf3, 0x0a, 0xbd, 0xad, 0x97, - 0xa7, 0x2d, 0xe7, 0xd5, 0x69, 0xcb, 0xf9, 0xfd, 0xb4, 0xe5, 0xfc, 0x78, 0xd6, 0x2a, 0xbc, 0x3a, - 0x6b, 0x15, 0x7e, 0x39, 0x6b, 0x15, 0xf6, 0x1f, 0xce, 0x10, 0x3c, 0xf7, 0xcf, 0x3b, 0xdc, 0xec, - 0x1e, 0x4f, 0x7e, 0x7c, 0x35, 0xd1, 0xfd, 0x25, 0xfd, 0x33, 0xfa, 0xce, 0x5f, 0x01, 0x00, 0x00, - 0xff, 0xff, 0xf1, 0x57, 0x7e, 0x0a, 0x1d, 0x0b, 0x00, 0x00, + // 1285 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xdd, 0x6e, 0x1b, 0x45, + 0x14, 0xce, 0x3a, 0x76, 0x1c, 0x1f, 0x6f, 0xd3, 0x76, 0xda, 0xb4, 0x56, 0x2a, 0x9c, 0x74, 0x11, + 0x21, 0x2a, 0x60, 0x43, 0x40, 0x5c, 0x20, 0x21, 0x15, 0xb7, 0x11, 0x04, 0x0a, 0x4d, 0x37, 0x70, + 0x53, 0x09, 0x6d, 0xc7, 0xbb, 0x93, 0xcd, 0xd0, 0xf5, 0xce, 0x66, 0x66, 0xd6, 0xad, 0x79, 0x01, + 0xae, 0x90, 0x78, 0x08, 0x9e, 0x80, 0x87, 0xa8, 0x7a, 0xd9, 0x4b, 0x84, 0x44, 0x85, 0xda, 0x37, + 0x40, 0x3c, 0x00, 0x3a, 0x33, 0xe3, 0xbf, 0x26, 0x2d, 0x0a, 0x70, 0xb5, 0x33, 0xdf, 0x9c, 0x3d, + 0xe7, 0xcc, 0x77, 0x7e, 0xe6, 0xc0, 0x46, 0x46, 0x87, 0x34, 0x67, 0xba, 0x8b, 0xdf, 0x6e, 0x41, + 0xb9, 0xe4, 0x79, 0xda, 0x95, 0x2c, 0xa3, 0xa3, 0x4e, 0x21, 0x85, 0x16, 0xe4, 0xa2, 0x93, 0xe8, + 0xe0, 0xb7, 0xe3, 0x24, 0xd6, 0x2e, 0xa6, 0x22, 0x15, 0x46, 0xa0, 0x8b, 0x2b, 0x2b, 0xbb, 0xd6, + 0x4e, 0x85, 0x48, 0x33, 0xd6, 0x35, 0xbb, 0x7e, 0x79, 0xd0, 0x7d, 0x20, 0x69, 0x51, 0x30, 0xa9, + 0xdc, 0xf9, 0xfa, 0x8b, 0xe7, 0x9a, 0x0f, 0x98, 0xd2, 0x74, 0x50, 0x38, 0x81, 0xb7, 0xe6, 0xdc, + 0x61, 0x85, 0x88, 0x0f, 0x95, 0x16, 0x92, 0xa6, 0xac, 0xab, 0x34, 0xbd, 0xcf, 0x22, 0x96, 0x6b, + 0xe9, 0x3c, 0x0b, 0xee, 0x81, 0xbf, 0x27, 0x45, 0x9f, 0x85, 0xec, 0xa8, 0x64, 0x4a, 0x13, 0x02, + 0xd5, 0xb4, 0xe4, 0x49, 0xcb, 0xdb, 0xf0, 0xb6, 0xaa, 0xa1, 0x59, 0x93, 0xcb, 0x50, 0x57, 0x05, + 0x8b, 0x23, 0x9e, 0xb4, 0x2a, 0x1b, 0xde, 0x56, 0x23, 0x5c, 0xc2, 0xed, 0x6e, 0x42, 0x5e, 0x87, + 0x33, 0xb4, 0xe0, 0x11, 0xcf, 0x35, 0x93, 0x07, 0x34, 0x66, 0xad, 0x45, 0x73, 0xec, 0xd3, 0x82, + 0xef, 0x8e, 0xb1, 0xe0, 0x91, 0x07, 0xe0, 0x4c, 0x14, 0xd9, 0xe8, 0x44, 0x03, 0x57, 0xc1, 0xcf, + 0xa8, 0x66, 0x4a, 0x47, 0xfd, 0x4c, 0xc4, 0xf7, 0x8d, 0x95, 0xc5, 0xb0, 0x69, 0xb1, 0x1e, 0x42, + 0xe4, 0x43, 0xb8, 0x7c, 0xc0, 0x73, 0x9a, 0xf1, 0xef, 0x59, 0x62, 0xa5, 0x54, 0x74, 0x48, 0xd5, + 0x21, 0x53, 0xc6, 0xa8, 0x1f, 0xae, 0x4e, 0x8e, 0xcd, 0x0f, 0xea, 0x33, 0x73, 0x48, 0x5e, 0x03, + 0x40, 0x1a, 0x22, 0x43, 0x43, 0xab, 0x6a, 0x8c, 0x36, 0x10, 0xd9, 0x41, 0x80, 0x5c, 0x83, 0xf3, + 0xe6, 0x78, 0xce, 0x7c, 0xcd, 0x48, 0x9d, 0xc5, 0x83, 0x5b, 0x53, 0x17, 0x82, 0x47, 0x55, 0xf0, + 0x43, 0x0c, 0xea, 0x3e, 0x53, 0x8a, 0x8b, 0x7c, 0x96, 0x17, 0x6f, 0x8e, 0x97, 0xab, 0xe0, 0xc7, + 0x22, 0xd7, 0x2c, 0xd7, 0xc6, 0x47, 0x73, 0x1f, 0x3f, 0x6c, 0x3a, 0x0c, 0x3d, 0x43, 0xbf, 0x94, + 0x55, 0x83, 0xbf, 0x2f, 0x5a, 0xbf, 0x1c, 0xb2, 0x9b, 0x90, 0x55, 0x58, 0x8a, 0xcb, 0x48, 0x95, + 0x03, 0xe7, 0x72, 0x2d, 0x2e, 0xf7, 0xcb, 0x01, 0x59, 0x83, 0xe5, 0x42, 0x8a, 0x21, 0x4f, 0x98, + 0x34, 0x5e, 0x36, 0xc2, 0xc9, 0x9e, 0x5c, 0x81, 0x86, 0x49, 0xb9, 0x28, 0x2f, 0x07, 0xad, 0x25, + 0xf3, 0xd7, 0xb2, 0x01, 0xbe, 0x2a, 0x07, 0xe4, 0x0b, 0x80, 0x23, 0xa1, 0x22, 0xc9, 0x0a, 0x21, + 0x75, 0xab, 0xbe, 0xe1, 0x6d, 0x35, 0xb7, 0xdf, 0xee, 0x9c, 0x94, 0x95, 0x9d, 0x3b, 0x25, 0xcd, + 0xb8, 0x1e, 0xdd, 0x3e, 0xd8, 0x67, 0x72, 0xc8, 0x63, 0x0c, 0x9b, 0x90, 0x3a, 0x6c, 0x1c, 0x09, + 0x65, 0x97, 0xe4, 0x22, 0xd4, 0x2c, 0x9d, 0xcb, 0x26, 0x4e, 0x76, 0x43, 0xbe, 0x85, 0x4b, 0x65, + 0x2e, 0x99, 0x2a, 0x44, 0xae, 0xf8, 0x90, 0x45, 0x63, 0xc7, 0x54, 0xab, 0xb1, 0xb1, 0xb8, 0xd5, + 0xdc, 0xde, 0x3c, 0xd9, 0x9c, 0xd5, 0xc9, 0x92, 0x3d, 0x27, 0x1e, 0xae, 0xce, 0x6a, 0x19, 0xa3, + 0x8a, 0x04, 0x70, 0xc6, 0x44, 0x2a, 0x3e, 0xa4, 0xdc, 0x70, 0x06, 0xe6, 0xfe, 0x4d, 0x04, 0x6f, + 0x20, 0xb6, 0x9b, 0x90, 0x73, 0xb0, 0xa8, 0x78, 0xda, 0x6a, 0x1a, 0xba, 0x71, 0x49, 0xde, 0x83, + 0x5a, 0x9f, 0x26, 0x29, 0x6b, 0xf9, 0xe6, 0xca, 0x57, 0x4e, 0xf6, 0xa1, 0x87, 0x22, 0xa1, 0x95, + 0x24, 0xf7, 0x60, 0x15, 0xa9, 0x62, 0x0f, 0x63, 0x96, 0x65, 0x2c, 0x8f, 0xd9, 0x98, 0xb5, 0x33, + 0xff, 0x82, 0xb5, 0x0b, 0x47, 0x42, 0xed, 0x4c, 0x34, 0x59, 0x10, 0x2b, 0xa2, 0x66, 0x4c, 0x62, + 0x01, 0xc5, 0x65, 0x44, 0xb3, 0x4c, 0xc4, 0x54, 0x73, 0x91, 0xbb, 0xaa, 0xf0, 0xe3, 0xf2, 0x93, + 0x09, 0x36, 0xa5, 0xbb, 0x62, 0x53, 0xc1, 0xd2, 0xdd, 0x82, 0x3a, 0x4d, 0x12, 0xc9, 0x94, 0x72, + 0x55, 0x37, 0xde, 0x1e, 0x67, 0xaa, 0x7a, 0x9c, 0xa9, 0x75, 0x68, 0x16, 0x52, 0x7c, 0xc7, 0x62, + 0x1d, 0x21, 0x63, 0x35, 0xc3, 0x18, 0x38, 0x68, 0x9f, 0xa7, 0xe8, 0xd9, 0x90, 0x4b, 0x5d, 0xd2, + 0xcc, 0x95, 0x8e, 0xcd, 0x28, 0xdf, 0x81, 0xa6, 0x7a, 0x82, 0xdf, 0x2b, 0x70, 0xce, 0x54, 0xc4, + 0x9e, 0xe4, 0x43, 0xaa, 0xd9, 0x4d, 0xaa, 0x29, 0x79, 0x13, 0xce, 0xc6, 0x22, 0xcf, 0x59, 0x8c, + 0xce, 0x47, 0x7a, 0x54, 0x30, 0x57, 0x1d, 0x2b, 0x53, 0xf8, 0xeb, 0x51, 0xc1, 0xb0, 0x7c, 0xb0, + 0x7b, 0x94, 0x32, 0x1b, 0xb7, 0x15, 0x5a, 0xf0, 0x6f, 0x64, 0x86, 0x2d, 0x22, 0xa1, 0x9a, 0xba, + 0xc2, 0x36, 0x6b, 0xf4, 0x47, 0xda, 0x16, 0xe5, 0x8a, 0xb4, 0x6a, 0x72, 0xcf, 0x77, 0xa0, 0x6d, + 0x12, 0xc7, 0xfa, 0x51, 0xed, 0x78, 0x3f, 0x42, 0xed, 0x8a, 0x66, 0xda, 0x5c, 0xc8, 0x0f, 0xcd, + 0x9a, 0x5c, 0x87, 0xe5, 0x01, 0xd3, 0xd4, 0x58, 0xad, 0x9b, 0x6c, 0x6d, 0x9f, 0x1c, 0xe6, 0x2f, + 0x9d, 0x54, 0xaf, 0xfa, 0xf8, 0xe9, 0xfa, 0x42, 0x38, 0xf9, 0x0b, 0x83, 0x44, 0x93, 0x44, 0xe4, + 0xa6, 0x26, 0x1a, 0xa1, 0xdd, 0x90, 0x36, 0x00, 0x7b, 0xa8, 0x59, 0x8e, 0x55, 0x6d, 0xeb, 0xa0, + 0x11, 0xce, 0x20, 0xb6, 0x0b, 0xb0, 0xdc, 0x5d, 0x09, 0xcc, 0x95, 0x1a, 0x88, 0xd8, 0x8e, 0xf3, + 0xa3, 0x87, 0xfc, 0xce, 0xd7, 0xc7, 0x6c, 0xe0, 0xbd, 0xf9, 0xc0, 0x6f, 0xc2, 0x4a, 0xc2, 0xd5, + 0x94, 0x65, 0xe5, 0x32, 0xe6, 0x05, 0x94, 0x5c, 0x82, 0x25, 0x26, 0xa5, 0x90, 0xca, 0xf5, 0x1d, + 0xb7, 0xc3, 0xa4, 0x98, 0xbc, 0x25, 0x91, 0x72, 0x0c, 0xc3, 0x04, 0xda, 0x0f, 0x3e, 0x80, 0xe5, + 0x31, 0x01, 0x48, 0x63, 0x4e, 0x07, 0xe3, 0xd8, 0x9a, 0x35, 0x92, 0x30, 0xa4, 0x59, 0xc9, 0x5c, + 0x3c, 0xed, 0x26, 0xf8, 0xd9, 0x73, 0x7d, 0x73, 0xfc, 0xc6, 0x7c, 0x8a, 0xb1, 0xc4, 0x4e, 0xe5, + 0xfa, 0x9d, 0xd1, 0xd1, 0xdc, 0x0e, 0x5e, 0xd6, 0x20, 0xa6, 0x2d, 0x17, 0xe3, 0x3d, 0xd3, 0x80, + 0x77, 0x00, 0xac, 0x22, 0x13, 0xb8, 0x8a, 0xd1, 0xb2, 0xf9, 0x0a, 0x2d, 0x33, 0x69, 0x1a, 0xda, + 0x66, 0x89, 0xcb, 0xcf, 0xab, 0xcb, 0x8b, 0xe7, 0xaa, 0xc1, 0x5f, 0x1e, 0x80, 0x73, 0xd3, 0xbd, + 0x53, 0x46, 0xab, 0x37, 0x93, 0x84, 0xae, 0xbf, 0x54, 0xa6, 0xfd, 0xe5, 0xc5, 0x97, 0xab, 0x7a, + 0xaa, 0x97, 0xab, 0xf6, 0x0f, 0x2f, 0x97, 0xe2, 0xa9, 0xfb, 0xc3, 0x65, 0x6b, 0x43, 0xf1, 0xd4, + 0x0a, 0xfd, 0xf7, 0x94, 0x75, 0xd7, 0xfe, 0xa5, 0x02, 0x97, 0x4e, 0x6e, 0x5e, 0xe4, 0x2e, 0xd4, + 0xf1, 0x22, 0x79, 0x3c, 0xb2, 0x51, 0xee, 0x5d, 0x47, 0x0d, 0xbf, 0x3d, 0x5d, 0xdf, 0x4c, 0xb9, + 0x3e, 0x2c, 0xfb, 0x9d, 0x58, 0x0c, 0xba, 0xb1, 0x50, 0x03, 0xa1, 0xdc, 0xe7, 0x1d, 0x95, 0xdc, + 0xef, 0x62, 0xc9, 0xab, 0xce, 0x4d, 0x16, 0xff, 0xf9, 0x74, 0x7d, 0x65, 0x44, 0x07, 0xd9, 0x47, + 0xc1, 0x2d, 0xab, 0x26, 0x08, 0xc7, 0x0a, 0x09, 0x07, 0x9f, 0x0e, 0x29, 0xcf, 0x68, 0x9f, 0xa3, + 0x69, 0x9b, 0x31, 0xbd, 0x9d, 0x53, 0x1b, 0xb8, 0x60, 0x0d, 0xcc, 0xea, 0x0a, 0xc2, 0x39, 0xd5, + 0xe4, 0x0e, 0x54, 0xd5, 0x28, 0x8f, 0x6d, 0x9b, 0xec, 0x7d, 0x7c, 0x6a, 0x13, 0x4d, 0x6b, 0x02, + 0x75, 0x04, 0xa1, 0x51, 0x15, 0x8c, 0xe0, 0xfc, 0x9e, 0xa5, 0xd7, 0x64, 0xcc, 0x0d, 0x1a, 0x1f, + 0x32, 0xb2, 0x03, 0x75, 0x9c, 0xac, 0x38, 0xc3, 0xc2, 0xc4, 0x80, 0xbc, 0x31, 0x1f, 0x90, 0xd9, + 0x49, 0xac, 0xb3, 0x8f, 0x93, 0xd8, 0x0e, 0x0e, 0x62, 0x2e, 0x2e, 0xe3, 0x7f, 0x31, 0xee, 0xf8, + 0x20, 0x3c, 0x60, 0x49, 0x14, 0x97, 0xae, 0x82, 0x1b, 0x0e, 0xb9, 0x51, 0x6e, 0xff, 0x50, 0x81, + 0xba, 0x31, 0xca, 0x24, 0xb9, 0x0d, 0x35, 0xb3, 0x24, 0xaf, 0x2a, 0x1d, 0x57, 0x75, 0x6b, 0x1b, + 0xaf, 0x94, 0x29, 0xb2, 0x51, 0xb0, 0x40, 0xee, 0xc2, 0x8a, 0x2d, 0xb7, 0xb2, 0xaf, 0x62, 0xc9, + 0xfb, 0xec, 0xff, 0xd2, 0xfc, 0xae, 0x87, 0xce, 0x9a, 0x31, 0xf0, 0x65, 0x2a, 0x67, 0xc7, 0xd0, + 0x97, 0xa9, 0x9c, 0xce, 0x91, 0xc1, 0x42, 0xef, 0xe6, 0xe3, 0x67, 0x6d, 0xef, 0xc9, 0xb3, 0xb6, + 0xf7, 0xc7, 0xb3, 0xb6, 0xf7, 0xd3, 0xf3, 0xf6, 0xc2, 0x93, 0xe7, 0xed, 0x85, 0x5f, 0x9f, 0xb7, + 0x17, 0xee, 0x5e, 0x9b, 0x89, 0xed, 0xdc, 0x30, 0x3c, 0xdc, 0xee, 0x3e, 0x9c, 0x0c, 0xe8, 0x26, + 0xc6, 0xfd, 0x25, 0x33, 0x07, 0xbf, 0xff, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x41, 0x7a, 0x06, + 0xb3, 0xc5, 0x0b, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1706,6 +1765,48 @@ func (m *QualityOfServiceReport) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } +func (m *PairingRelayCache) 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 *PairingRelayCache) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PairingRelayCache) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.AllowedCu != 0 { + i = encodeVarintRelay(dAtA, i, uint64(m.AllowedCu)) + i-- + dAtA[i] = 0x10 + } + if len(m.Entries) > 0 { + for iNdEx := len(m.Entries) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Entries[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRelay(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func encodeVarintRelay(dAtA []byte, offset int, v uint64) int { offset -= sovRelay(v) base := offset @@ -2007,6 +2108,24 @@ func (m *QualityOfServiceReport) Size() (n int) { return n } +func (m *PairingRelayCache) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Entries) > 0 { + for _, e := range m.Entries { + l = e.Size() + n += 1 + l + sovRelay(uint64(l)) + } + } + if m.AllowedCu != 0 { + n += 1 + sovRelay(uint64(m.AllowedCu)) + } + return n +} + func sovRelay(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -4059,6 +4178,109 @@ func (m *QualityOfServiceReport) Unmarshal(dAtA []byte) error { } return nil } +func (m *PairingRelayCache) 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 ErrIntOverflowRelay + } + 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: PairingRelayCache: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PairingRelayCache: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Entries", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRelay + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRelay + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRelay + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Entries = append(m.Entries, types.StakeEntry{}) + if err := m.Entries[len(m.Entries)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AllowedCu", wireType) + } + m.AllowedCu = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRelay + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.AllowedCu |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipRelay(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRelay + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipRelay(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/spec/proposal_handler.go b/x/spec/proposal_handler.go index a280434d35..735aa4d206 100644 --- a/x/spec/proposal_handler.go +++ b/x/spec/proposal_handler.go @@ -45,7 +45,7 @@ func HandleParameterChangeProposal(ctx sdk.Context, k paramkeeper.Keeper, p *par {Key: "value", Value: c.Value}, } if c.Key == string(epochstoragetypes.KeyLatestParamChange) { - return utils.LavaFormatWarning("Gov Proposal Param Change Error", fmt.Errorf("tried to modify "+string(epochstoragetypes.KeyLatestParamChange)), + return utils.LavaFormatWarning("Gov Proposal Param Change Error", fmt.Errorf("tried to modify %s", string(epochstoragetypes.KeyLatestParamChange)), details..., ) }