diff --git a/cookbook/specs/evmos.json b/cookbook/specs/evmos.json index 81b7f332eb..c0324f3cae 100644 --- a/cookbook/specs/evmos.json +++ b/cookbook/specs/evmos.json @@ -1590,6 +1590,43 @@ "type": "POST", "add_on": "debug" }, + "apis": [ + { + "name": "debug_getBadBlocks", + "compute_units": 1, + "enabled": false + }, + { + "name": "debug_getRawBlock", + "compute_units": 1, + "enabled": false + }, + { + "name": "debug_getRawHeader", + "compute_units": 1, + "enabled": false + }, + { + "name": "debug_getRawReceipts", + "compute_units": 1, + "enabled": false + }, + { + "name": "debug_getRawTransaction", + "compute_units": 1, + "enabled": false + }, + { + "name": "debug_storageRangeAt", + "compute_units": 1, + "enabled": false + }, + { + "name": "debug_traceCall", + "compute_units": 1, + "enabled": false + } + ], "verifications": [ { "name": "enabled", diff --git a/proto/lavanet/lava/spec/api_collection.proto b/proto/lavanet/lava/spec/api_collection.proto index 4f9c7434e1..27750346b6 100644 --- a/proto/lavanet/lava/spec/api_collection.proto +++ b/proto/lavanet/lava/spec/api_collection.proto @@ -83,6 +83,7 @@ message ParseDirective { string function_template = 2; BlockParser result_parsing = 3 [(gogoproto.nullable) = false]; string api_name = 4; + repeated GenericParser parsers = 5 [(gogoproto.nullable) = false]; } message BlockParser { diff --git a/protocol/chainlib/chain_fetcher.go b/protocol/chainlib/chain_fetcher.go index 565ace6948..9a5d6c421b 100644 --- a/protocol/chainlib/chain_fetcher.go +++ b/protocol/chainlib/chain_fetcher.go @@ -188,68 +188,71 @@ func (cf *ChainFetcher) Verify(ctx context.Context, verification VerificationCon ) } - parsedResult, err := parser.ParseFromReply(parserInput, parsing.ResultParsing) - if err != nil { - return utils.LavaFormatWarning("[-] verify failed to parse result", err, []utils.Attribute{ - {Key: "chainId", Value: chainId}, - {Key: "nodeUrl", Value: proxyUrl.Url}, - {Key: "Method", Value: parsing.GetApiName()}, - {Key: "Response", Value: string(reply.RelayReply.Data)}, - }...) + parsedInput := parser.ParseBlockFromReply(parserInput, parsing.ResultParsing, parsing.Parsers) + if parsedInput.GetRawParsedData() == "" { + return utils.LavaFormatWarning("[-] verify failed to parse result", err, + utils.LogAttr("chainId", chainId), + utils.LogAttr("nodeUrl", proxyUrl.Url), + utils.LogAttr("Method", parsing.GetApiName()), + utils.LogAttr("Response", string(reply.RelayReply.Data)), + ) } if verification.LatestDistance != 0 && latestBlock != 0 && verification.ParseDirective.FunctionTag != spectypes.FUNCTION_TAG_GET_BLOCK_BY_NUM { - parsedResultAsNumber, err := strconv.ParseUint(parsedResult, 0, 64) - if err != nil { - return utils.LavaFormatWarning("[-] verify failed to parse result as number", err, []utils.Attribute{ - {Key: "chainId", Value: chainId}, - {Key: "nodeUrl", Value: proxyUrl.Url}, - {Key: "Method", Value: parsing.GetApiName()}, - {Key: "Response", Value: string(reply.RelayReply.Data)}, - {Key: "parsedResult", Value: parsedResult}, - }...) + parsedResultAsNumber := parsedInput.GetBlock() + if parsedResultAsNumber == spectypes.NOT_APPLICABLE { + return utils.LavaFormatWarning("[-] verify failed to parse result as number", err, + utils.LogAttr("chainId", chainId), + utils.LogAttr("nodeUrl", proxyUrl.Url), + utils.LogAttr("Method", parsing.GetApiName()), + utils.LogAttr("Response", string(reply.RelayReply.Data)), + utils.LogAttr("rawParsedData", parsedInput.GetRawParsedData()), + ) } - if parsedResultAsNumber > latestBlock { - return utils.LavaFormatWarning("[-] verify failed parsed result is greater than latestBlock", err, []utils.Attribute{ - {Key: "chainId", Value: chainId}, - {Key: "nodeUrl", Value: proxyUrl.Url}, - {Key: "Method", Value: parsing.GetApiName()}, - {Key: "latestBlock", Value: latestBlock}, - {Key: "parsedResult", Value: parsedResultAsNumber}, - }...) + uint64ParsedResultAsNumber := uint64(parsedResultAsNumber) + if uint64ParsedResultAsNumber > latestBlock { + return utils.LavaFormatWarning("[-] verify failed parsed result is greater than latestBlock", err, + utils.LogAttr("chainId", chainId), + utils.LogAttr("nodeUrl", proxyUrl.Url), + utils.LogAttr("Method", parsing.GetApiName()), + utils.LogAttr("latestBlock", latestBlock), + utils.LogAttr("parsedResult", uint64ParsedResultAsNumber), + ) } - if latestBlock-parsedResultAsNumber < verification.LatestDistance { - return utils.LavaFormatWarning("[-] verify failed expected block distance is not sufficient", err, []utils.Attribute{ - {Key: "chainId", Value: chainId}, - {Key: "nodeUrl", Value: proxyUrl.Url}, - {Key: "Method", Value: parsing.GetApiName()}, - {Key: "latestBlock", Value: latestBlock}, - {Key: "parsedResult", Value: parsedResultAsNumber}, - {Key: "expected", Value: verification.LatestDistance}, - }...) + if latestBlock-uint64ParsedResultAsNumber < verification.LatestDistance { + return utils.LavaFormatWarning("[-] verify failed expected block distance is not sufficient", err, + utils.LogAttr("chainId", chainId), + utils.LogAttr("nodeUrl", proxyUrl.Url), + utils.LogAttr("Method", parsing.GetApiName()), + utils.LogAttr("latestBlock", latestBlock), + utils.LogAttr("parsedResult", uint64ParsedResultAsNumber), + utils.LogAttr("expected", verification.LatestDistance), + ) } } // some verifications only want the response to be valid, and don't care about the value if verification.Value != "*" && verification.Value != "" && verification.ParseDirective.FunctionTag != spectypes.FUNCTION_TAG_GET_BLOCK_BY_NUM { - if parsedResult != verification.Value { - return utils.LavaFormatWarning("[-] verify failed expected and received are different", err, []utils.Attribute{ - {Key: "chainId", Value: chainId}, - {Key: "nodeUrl", Value: proxyUrl.Url}, - {Key: "parsedResult", Value: parsedResult}, - {Key: "verification.Value", Value: verification.Value}, - {Key: "Method", Value: parsing.GetApiName()}, - {Key: "Extension", Value: verification.Extension}, - {Key: "Addon", Value: verification.Addon}, - {Key: "Verification", Value: verification.Name}, - }...) + rawData := parsedInput.GetRawParsedData() + if rawData != verification.Value { + return utils.LavaFormatWarning("[-] verify failed expected and received are different", err, + utils.LogAttr("chainId", chainId), + utils.LogAttr("nodeUrl", proxyUrl.Url), + utils.LogAttr("rawParsedBlock", rawData), + utils.LogAttr("verification.Value", verification.Value), + utils.LogAttr("Method", parsing.GetApiName()), + utils.LogAttr("Extension", verification.Extension), + utils.LogAttr("Addon", verification.Addon), + utils.LogAttr("Verification", verification.Name), + ) } } utils.LavaFormatInfo("[+] verified successfully", - utils.Attribute{Key: "chainId", Value: chainId}, - utils.Attribute{Key: "nodeUrl", Value: proxyUrl.Url}, - utils.Attribute{Key: "verification", Value: verification.Name}, - utils.Attribute{Key: "value", Value: parser.CapStringLen(parsedResult)}, - utils.Attribute{Key: "verificationKey", Value: verification.VerificationKey}, - utils.Attribute{Key: "apiInterface", Value: cf.endpoint.ApiInterface}, + utils.LogAttr("chainId", chainId), + utils.LogAttr("nodeUrl", proxyUrl.Url), + utils.LogAttr("verification", verification.Name), + utils.LogAttr("block", parsedInput.GetBlock()), + utils.LogAttr("rawData", parsedInput.GetRawParsedData()), + utils.LogAttr("verificationKey", verification.VerificationKey), + utils.LogAttr("apiInterface", cf.endpoint.ApiInterface), ) return nil } @@ -292,8 +295,9 @@ func (cf *ChainFetcher) FetchLatestBlockNum(ctx context.Context) (int64, error) {Key: "error", Value: err}, }...) } - blockNum, err := parser.ParseBlockFromReply(parserInput, parsing.ResultParsing) - if err != nil { + parsedInput := parser.ParseBlockFromReply(parserInput, parsing.ResultParsing, parsing.Parsers) + blockNum := parsedInput.GetBlock() + if blockNum == spectypes.NOT_APPLICABLE { return spectypes.NOT_APPLICABLE, utils.LavaFormatDebug(tagName+" Failed to parse Response", []utils.Attribute{ {Key: "chainId", Value: chainId}, {Key: "nodeUrl", Value: proxyUrl.Url}, @@ -355,7 +359,7 @@ func (cf *ChainFetcher) FetchBlockHashByNum(ctx context.Context, blockNum int64) }...) } - res, err := parser.ParseFromReplyAndDecode(parserInput, parsing.ResultParsing) + res, err := parser.ParseBlockHashFromReplyAndDecode(parserInput, parsing.ResultParsing, parsing.Parsers) if err != nil { return "", utils.LavaFormatDebug(tagName+" Failed ParseMessageResponse", []utils.Attribute{ {Key: "error", Value: err}, diff --git a/protocol/chainlib/consumer_websocket_manager.go b/protocol/chainlib/consumer_websocket_manager.go index 748fd7e5b3..5f47180489 100644 --- a/protocol/chainlib/consumer_websocket_manager.go +++ b/protocol/chainlib/consumer_websocket_manager.go @@ -96,6 +96,10 @@ func (cwm *ConsumerWebsocketManager) handleRateLimitReached(inpData []byte) ([]b } func (cwm *ConsumerWebsocketManager) ListenToMessages() { + // adding metrics for how many active connections we have. + cwm.rpcConsumerLogs.SetWebSocketConnectionActive(cwm.chainId, cwm.apiInterface, true) + defer cwm.rpcConsumerLogs.SetWebSocketConnectionActive(cwm.chainId, cwm.apiInterface, false) + var ( messageType int msg []byte diff --git a/protocol/chainlib/grpc_test.go b/protocol/chainlib/grpc_test.go index 8c51ab9ca1..68e5d2ece5 100644 --- a/protocol/chainlib/grpc_test.go +++ b/protocol/chainlib/grpc_test.go @@ -217,9 +217,8 @@ func TestParsingRequestedBlocksHeadersGrpc(t *testing.T) { require.NoError(t, err) parserInput, err := FormatResponseForParsing(reply.RelayReply, chainMessage) require.NoError(t, err) - blockNum, err := parser.ParseBlockFromReply(parserInput, parsingForCrafting.ResultParsing) - require.NoError(t, err) - require.Equal(t, test.block, blockNum) + parsedInput := parser.ParseBlockFromReply(parserInput, parsingForCrafting.ResultParsing, nil) + require.Equal(t, test.block, parsedInput.GetBlock()) }) } } @@ -287,9 +286,8 @@ func TestSettingBlocksHeadersGrpc(t *testing.T) { require.NoError(t, err) parserInput, err := FormatResponseForParsing(reply.RelayReply, chainMessage) require.NoError(t, err) - blockNum, err := parser.ParseBlockFromReply(parserInput, parsingForCrafting.ResultParsing) - require.NoError(t, err) - require.Equal(t, test.block, blockNum) + parsedInput := parser.ParseBlockFromReply(parserInput, parsingForCrafting.ResultParsing, nil) + require.Equal(t, test.block, parsedInput.GetBlock()) }) } } diff --git a/protocol/chainlib/grpcproxy/grpcproxy.go b/protocol/chainlib/grpcproxy/grpcproxy.go index 3eee098cfb..d9e86fa48b 100644 --- a/protocol/chainlib/grpcproxy/grpcproxy.go +++ b/protocol/chainlib/grpcproxy/grpcproxy.go @@ -112,7 +112,7 @@ func (RawBytesCodec) Marshal(v interface{}) ([]byte, error) { func (RawBytesCodec) Unmarshal(data []byte, v interface{}) error { bufferPtr, ok := v.(*[]byte) if !ok { - return utils.LavaFormatError("cannot decode into type", nil, utils.LogAttr("v", v), utils.LogAttr("data", data)) + return utils.LavaFormatDebug("cannot decode into type", utils.LogAttr("v", v), utils.LogAttr("data", data)) } *bufferPtr = data return nil diff --git a/protocol/chainlib/jsonRPC_test.go b/protocol/chainlib/jsonRPC_test.go index f32ec51683..7158e98704 100644 --- a/protocol/chainlib/jsonRPC_test.go +++ b/protocol/chainlib/jsonRPC_test.go @@ -187,8 +187,9 @@ func TestJsonRpcChainProxy(t *testing.T) { require.NoError(t, err) _, err = chainFetcher.FetchBlockHashByNum(ctx, block) - errMsg := "GET_BLOCK_BY_NUM Failed ParseMessageResponse {error:invalid parser input format" - require.True(t, err.Error()[:len(errMsg)] == errMsg, err.Error()) + actualErrMsg := "GET_BLOCK_BY_NUM Failed ParseMessageResponse {error:blockParsing - parse failed {error:invalid parser input format," + expectedErrMsg := err.Error()[:len(actualErrMsg)] + require.Equal(t, actualErrMsg, expectedErrMsg, err.Error()) } func TestAddonAndVerifications(t *testing.T) { diff --git a/protocol/chainlib/rest_test.go b/protocol/chainlib/rest_test.go index 6ce0922113..918888bf1a 100644 --- a/protocol/chainlib/rest_test.go +++ b/protocol/chainlib/rest_test.go @@ -214,9 +214,8 @@ func TestParsingRequestedBlocksHeadersRest(t *testing.T) { require.NoError(t, err) parserInput, err := FormatResponseForParsing(reply.RelayReply, chainMessage) require.NoError(t, err) - blockNum, err := parser.ParseBlockFromReply(parserInput, parsingForCrafting.ResultParsing) - require.NoError(t, err) - require.Equal(t, test.block, blockNum) + parsedInput := parser.ParseBlockFromReply(parserInput, parsingForCrafting.ResultParsing, nil) + require.Equal(t, test.block, parsedInput.GetBlock()) }) } } @@ -289,9 +288,8 @@ func TestSettingRequestedBlocksHeadersRest(t *testing.T) { require.NoError(t, err) parserInput, err := FormatResponseForParsing(reply.RelayReply, chainMessage) require.NoError(t, err) - blockNum, err := parser.ParseBlockFromReply(parserInput, parsingForCrafting.ResultParsing) - require.NoError(t, err) - require.Equal(t, test.block, blockNum) + parsedInput := parser.ParseBlockFromReply(parserInput, parsingForCrafting.ResultParsing, nil) + require.Equal(t, test.block, parsedInput.GetBlock()) }) } } diff --git a/protocol/metrics/metrics_consumer_manager.go b/protocol/metrics/metrics_consumer_manager.go index 83cd72d025..ce88f2145b 100644 --- a/protocol/metrics/metrics_consumer_manager.go +++ b/protocol/metrics/metrics_consumer_manager.go @@ -44,6 +44,7 @@ type ConsumerMetricsManager struct { totalFailedWsSubscriptionRequestsMetric *prometheus.CounterVec totalWsSubscriptionDissconnectMetric *prometheus.CounterVec totalDuplicatedWsSubscriptionRequestsMetric *prometheus.CounterVec + totalWebSocketConnectionsActive *prometheus.GaugeVec blockMetric *prometheus.GaugeVec latencyMetric *prometheus.GaugeVec qosMetric *prometheus.GaugeVec @@ -113,6 +114,11 @@ func NewConsumerMetricsManager(options ConsumerMetricsManagerOptions) *ConsumerM Help: "The total number of duplicated webscket subscription requests over time per chain id per api interface.", }, []string{"spec", "apiInterface"}) + totalWebSocketConnectionsActive := prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "lava_consumer_total_websocket_connections_active", + Help: "The total number of currently active websocket connections with users", + }, []string{"spec", "apiInterface"}) + totalWsSubscriptionDissconnectMetric := prometheus.NewCounterVec(prometheus.CounterOpts{ Name: "lava_consumer_total_ws_subscription_disconnect", Help: "The total number of websocket subscription disconnects over time per chain id per api interface per dissconnect reason.", @@ -218,6 +224,7 @@ func NewConsumerMetricsManager(options ConsumerMetricsManagerOptions) *ConsumerM prometheus.MustRegister(endpointsHealthChecksOkMetric) prometheus.MustRegister(protocolVersionMetric) prometheus.MustRegister(totalRelaysSentByNewBatchTickerMetric) + prometheus.MustRegister(totalWebSocketConnectionsActive) prometheus.MustRegister(apiSpecificsMetric) prometheus.MustRegister(averageLatencyMetric) prometheus.MustRegister(totalRelaysSentToProvidersMetric) @@ -238,6 +245,7 @@ func NewConsumerMetricsManager(options ConsumerMetricsManagerOptions) *ConsumerM totalFailedWsSubscriptionRequestsMetric: totalFailedWsSubscriptionRequestsMetric, totalDuplicatedWsSubscriptionRequestsMetric: totalDuplicatedWsSubscriptionRequestsMetric, totalWsSubscriptionDissconnectMetric: totalWsSubscriptionDissconnectMetric, + totalWebSocketConnectionsActive: totalWebSocketConnectionsActive, totalErroredMetric: totalErroredMetric, blockMetric: blockMetric, latencyMetric: latencyMetric, @@ -297,6 +305,17 @@ func (pme *ConsumerMetricsManager) SetRelaySentToProviderMetric(chainId string, pme.totalRelaysSentToProvidersMetric.WithLabelValues(chainId, apiInterface).Inc() } +func (pme *ConsumerMetricsManager) SetWebSocketConnectionActive(chainId string, apiInterface string, add bool) { + if pme == nil { + return + } + if add { + pme.totalWebSocketConnectionsActive.WithLabelValues(chainId, apiInterface).Add(1) + } else { + pme.totalWebSocketConnectionsActive.WithLabelValues(chainId, apiInterface).Sub(1) + } +} + func (pme *ConsumerMetricsManager) SetRelayNodeErrorMetric(chainId string, apiInterface string) { if pme == nil { return diff --git a/protocol/metrics/rpcconsumerlogs.go b/protocol/metrics/rpcconsumerlogs.go index 5171faa1bb..dd5c36a3fd 100644 --- a/protocol/metrics/rpcconsumerlogs.go +++ b/protocol/metrics/rpcconsumerlogs.go @@ -87,6 +87,10 @@ func NewRPCConsumerLogs(consumerMetricsManager *ConsumerMetricsManager, consumer return rpcConsumerLogs, err } +func (rpccl *RPCConsumerLogs) SetWebSocketConnectionActive(chainId string, apiInterface string, add bool) { + rpccl.consumerMetricsManager.SetWebSocketConnectionActive(chainId, apiInterface, add) +} + func (rpccl *RPCConsumerLogs) SetRelaySentToProviderMetric(chainId string, apiInterface string) { rpccl.consumerMetricsManager.SetRelaySentToProviderMetric(chainId, apiInterface) } diff --git a/protocol/parser/parser.go b/protocol/parser/parser.go index 19cff573f5..0eb958704f 100644 --- a/protocol/parser/parser.go +++ b/protocol/parser/parser.go @@ -50,6 +50,7 @@ func ParseDefaultBlockParameter(block string) (int64, error) { // try to parse a number } + block = unquoteString(block) hashNoPrefix, found := strings.CutPrefix(block, "0x") if len(block) >= 64 && found { if len(hashNoPrefix)%64 == 0 { @@ -96,131 +97,161 @@ func filterGenericParsersByType(genericParsers []spectypes.GenericParser, filter return retGenericParsers } -func parseInputFromParamsWithGenericParsers(rpcInput RPCInput, genericParsers []spectypes.GenericParser) (*ParsedInput, bool) { - parsedSuccessfully := false +func parseInputWithGenericParsers(rpcInput RPCInput, genericParsers []spectypes.GenericParser) (*ParsedInput, bool) { + managedToParseRawBlock := false if len(genericParsers) == 0 { - return nil, parsedSuccessfully + return nil, managedToParseRawBlock } genericParserResult, genericParserErr := ParseWithGenericParsers(rpcInput, filterGenericParsersByType(genericParsers, getParserTypeMap(PARSE_PARAMS))) if genericParserErr != nil { - return nil, parsedSuccessfully + return nil, managedToParseRawBlock } parsed := NewParsedInput() - parsedBlock := genericParserResult.GetBlock() - if parsedBlock != spectypes.NOT_APPLICABLE { - parsedSuccessfully = true - parsed.parsedBlock = parsedBlock + rawParsedData := genericParserResult.GetRawParsedData() + if rawParsedData != "" { + managedToParseRawBlock = true + parsed.parsedDataRaw = rawParsedData } parsedBlockHashes, err := genericParserResult.GetBlockHashes() if err == nil { + managedToParseRawBlock = true parsed.parsedHashes = parsedBlockHashes } - return parsed, parsedSuccessfully + return parsed, managedToParseRawBlock } -func ParseBlockFromParams(rpcInput RPCInput, blockParser spectypes.BlockParser, genericParsers []spectypes.GenericParser) *ParsedInput { - parsedBlockInfo, parsedSuccessfully := parseInputFromParamsWithGenericParsers(rpcInput, genericParsers) - if parsedSuccessfully { - return parsedBlockInfo - } - if parsedBlockInfo == nil { - parsedBlockInfo = NewParsedInput() - } - - parsedBlockInfo.parsedBlock = func() int64 { - // first we try to parse the value with the block parser - result, err := parse(rpcInput, blockParser, PARSE_PARAMS) - if err != nil || result == nil { - utils.LavaFormatDebug("ParseBlockFromParams - parse failed", - utils.LogAttr("error", err), - utils.LogAttr("result", result), - utils.LogAttr("blockParser", blockParser), - utils.LogAttr("rpcInput", rpcInput), +// ParseRawBlock attempts to parse a block from rpcInput and store it in parsedInput. +// If parsing fails or rawBlock is empty, it uses defaultValue if provided. +// If parsing the defaultValue also fails, it sets the block to NOT_APPLICABLE. +func ParseRawBlock(rpcInput RPCInput, parsedInput *ParsedInput, defaultValue string) { + rawBlock := parsedInput.GetRawParsedData() + var parsedBlock int64 + var err error + if rawBlock != "" { + parsedBlock, err = rpcInput.ParseBlock(rawBlock) + } + if rawBlock == "" || err != nil { + if defaultValue != "" { + utils.LavaFormatDebug("Failed parsing block from string, assuming default value", + utils.LogAttr("params", rpcInput.GetParams()), + utils.LogAttr("failed_parsed_value", rawBlock), + utils.LogAttr("default_value", defaultValue), ) - return spectypes.NOT_APPLICABLE - } - - resString, ok := result[0].(string) - if !ok { - utils.LavaFormatDebug("ParseBlockFromParams - result[0].(string) - type assertion failed", utils.LogAttr("result[0]", result[0])) - return spectypes.NOT_APPLICABLE - } - parsedBlock, err := rpcInput.ParseBlock(resString) - if err != nil { - if blockParser.DefaultValue != "" { - utils.LavaFormatDebug("Failed parsing block from string, assuming default value", - utils.LogAttr("params", rpcInput.GetParams()), - utils.LogAttr("failed_parsed_value", resString), - utils.LogAttr("default_value", blockParser.DefaultValue), + parsedBlock, err = rpcInput.ParseBlock(defaultValue) + if err != nil { + utils.LavaFormatError("Failed parsing default value, setting to NOT_APPLICABLE", err, + utils.LogAttr("default_value", defaultValue), ) - parsedBlock, err = rpcInput.ParseBlock(blockParser.DefaultValue) - if err != nil { - utils.LavaFormatError("Failed parsing default value, setting to NOT_APPLICABLE", err, - utils.LogAttr("default_value", blockParser.DefaultValue), - ) - return spectypes.NOT_APPLICABLE - } - } else { - return spectypes.NOT_APPLICABLE + parsedBlock = spectypes.NOT_APPLICABLE } + } else { + parsedBlock = spectypes.NOT_APPLICABLE } - return parsedBlock - }() - - return parsedBlockInfo + } + parsedInput.SetBlock(parsedBlock) } -// This returns the parsed response without decoding -func ParseFromReply(rpcInput RPCInput, blockParser spectypes.BlockParser) (string, error) { - result, err := parse(rpcInput, blockParser, PARSE_RESULT) +func parseInputWithLegacyBlockParser(rpcInput RPCInput, blockParser spectypes.BlockParser, source int) (string, error) { + result, err := legacyParse(rpcInput, blockParser, source) if err != nil || result == nil { - utils.LavaFormatDebug("ParseBlockFromParams - parse failed", + return "", utils.LavaFormatDebug("blockParsing - parse failed", utils.LogAttr("error", err), utils.LogAttr("result", result), utils.LogAttr("blockParser", blockParser), utils.LogAttr("rpcInput", rpcInput), ) - return "", err } - response, ok := result[spectypes.DEFAULT_PARSED_RESULT_INDEX].(string) + resString, ok := result[spectypes.DEFAULT_PARSED_RESULT_INDEX].(string) if !ok { - return "", utils.LavaFormatError("Failed to Convert blockData[spectypes.DEFAULT_PARSED_RESULT_INDEX].(string)", nil, utils.Attribute{Key: "blockData", Value: response[spectypes.DEFAULT_PARSED_RESULT_INDEX]}) + return "", utils.LavaFormatDebug("blockParsing - result[0].(string) - type assertion failed", utils.LogAttr("result[0]", result[0])) } - if strings.Contains(response, "\"") { - responseUnquoted, err := strconv.Unquote(response) - if err != nil { - return response, nil + return resString, nil +} + +// parseBlock processes the given RPC input using either generic parsers or a legacy block parser. +// It first attempts to parse the input with the provided generic parsers. If successful, it returns +// the parsed information after unquoting the raw parsed data. If the generic parsing fails, it falls +// back to using a legacy block parser. +// +// Parameters: +// - rpcInput: The input data to be parsed. +// - blockParser: The legacy block parser to use if generic parsing fails. +// - genericParsers: A slice of generic parsers to attempt first. +// - source: An integer representing the source of the input: either PARSE_PARAMS or PARSE_RESULT. +// +// Returns: +// - A pointer to a ParsedInput struct containing the parsed data. +func parseBlock(rpcInput RPCInput, blockParser spectypes.BlockParser, genericParsers []spectypes.GenericParser, source int) *ParsedInput { + parsedBlockInfo, _ := parseInputWithGenericParsers(rpcInput, genericParsers) + if parsedBlockInfo == nil { + parsedBlockInfo = NewParsedInput() + } else { + rawBlockFromGenericParser := parsedBlockInfo.parsedDataRaw + if rawBlockFromGenericParser != "" { + parsedBlockInfo.parsedDataRaw = unquoteString(rawBlockFromGenericParser) + return parsedBlockInfo } - return responseUnquoted, nil } - return response, nil + parsedRawBlock, _ := parseInputWithLegacyBlockParser(rpcInput, blockParser, source) + parsedBlockInfo.parsedDataRaw = unquoteString(parsedRawBlock) + return parsedBlockInfo +} + +func ParseBlockFromParams(rpcInput RPCInput, blockParser spectypes.BlockParser, genericParsers []spectypes.GenericParser) *ParsedInput { + parsedInput := parseBlock(rpcInput, blockParser, genericParsers, PARSE_PARAMS) + ParseRawBlock(rpcInput, parsedInput, blockParser.DefaultValue) + return parsedInput } -func ParseBlockFromReply(rpcInput RPCInput, blockParser spectypes.BlockParser) (int64, error) { - result, err := ParseFromReply(rpcInput, blockParser) +func ParseBlockFromReply(rpcInput RPCInput, blockParser spectypes.BlockParser, genericParsers []spectypes.GenericParser) *ParsedInput { + parsedInput := parseBlock(rpcInput, blockParser, genericParsers, PARSE_RESULT) + ParseRawBlock(rpcInput, parsedInput, blockParser.DefaultValue) + return parsedInput +} + +func unquoteString(str string) string { + if !strings.Contains(str, "\"") { + return str + } + + unquoted, err := strconv.Unquote(str) if err != nil { - return spectypes.NOT_APPLICABLE, err + return str } - return rpcInput.ParseBlock(result) + return unquoted } // This returns the parsed response after decoding -func ParseFromReplyAndDecode(rpcInput RPCInput, resultParser spectypes.BlockParser) (string, error) { - response, err := ParseFromReply(rpcInput, resultParser) +func ParseBlockHashFromReplyAndDecode(rpcInput RPCInput, resultParser spectypes.BlockParser, genericParsers []spectypes.GenericParser) (string, error) { + parsedInput, _ := parseInputWithGenericParsers(rpcInput, genericParsers) + if parsedInput == nil { + parsedBlockHashFromBlockParser, err := parseInputWithLegacyBlockParser(rpcInput, resultParser, PARSE_RESULT) + if err != nil { + return "", err + } + return parseResponseByEncoding([]byte(parsedBlockHashFromBlockParser), resultParser.Encoding) + } + + parsedBlockHashes, err := parsedInput.GetBlockHashes() if err != nil { return "", err } - return parseResponseByEncoding([]byte(response), resultParser.Encoding) + + numberOfParsedHashes := len(parsedBlockHashes) + if numberOfParsedHashes != 1 { + return "", utils.LavaFormatError("[ParseBlockHashFromReplyAndDecode] expected parsed hashes length 1", nil, utils.LogAttr("rpcInput.GetResult()", rpcInput.GetResult()), utils.LogAttr("hashes_length", numberOfParsedHashes)) + } + return parseResponseByEncoding([]byte(parsedBlockHashes[0]), resultParser.Encoding) } -func parse(rpcInput RPCInput, blockParser spectypes.BlockParser, dataSource int) ([]interface{}, error) { +func legacyParse(rpcInput RPCInput, blockParser spectypes.BlockParser, dataSource int) ([]interface{}, error) { var retval []interface{} var err error @@ -254,14 +285,18 @@ func parse(rpcInput RPCInput, blockParser spectypes.BlockParser, dataSource int) } type ParsedInput struct { - parsedBlock int64 - parsedHashes []string + parsedDataRaw string + parsedBlock int64 + parsedHashes []string } +const RAW_NOT_APPLICABLE = "-1" + func NewParsedInput() *ParsedInput { return &ParsedInput{ - parsedBlock: spectypes.NOT_APPLICABLE, - parsedHashes: make([]string, 0), + parsedDataRaw: RAW_NOT_APPLICABLE, + parsedBlock: spectypes.NOT_APPLICABLE, + parsedHashes: make([]string, 0), } } @@ -269,6 +304,10 @@ func (p *ParsedInput) SetBlock(block int64) { p.parsedBlock = block } +func (p *ParsedInput) GetRawParsedData() string { + return p.parsedDataRaw +} + func (p *ParsedInput) GetBlock() int64 { return p.parsedBlock } @@ -281,7 +320,12 @@ func (p *ParsedInput) GetBlockHashes() ([]string, error) { } func getMapForParse(rpcInput RPCInput) map[string]interface{} { - return map[string]interface{}{"params": rpcInput.GetParams(), "result": rpcInput.GetResult()} + var result map[string]interface{} + rpcInputResult := rpcInput.GetResult() + if rpcInputResult != nil { + json.Unmarshal(rpcInputResult, &result) + } + return map[string]interface{}{"params": rpcInput.GetParams(), "result": result} } func ParseWithGenericParsers(rpcInput RPCInput, genericParsers []spectypes.GenericParser) (*ParsedInput, error) { @@ -364,22 +408,14 @@ func parseGeneric(input interface{}, genericParser spectypes.GenericParser) (*Pa // regardless of the value provided by the user. for example .finality: final case spectypes.PARSER_TYPE_DEFAULT_VALUE: parsed := NewParsedInput() - block, err := ParseDefaultBlockParameter(genericParser.Value) - if err != nil { - return nil, utils.LavaFormatError("Failed converting default value to requested block", err, utils.LogAttr("genericParser.Value", genericParser.Value)) - } - parsed.parsedBlock = block + parsed.parsedDataRaw = genericParser.Value return parsed, nil // Case Block Latest, setting the value set by the user given a json path hit. // Example: block_id: 100, will result in requested block 100. case spectypes.PARSER_TYPE_BLOCK_LATEST: parsed := NewParsedInput() - valueString := blockInterfaceToString(value) - block, err := ParseDefaultBlockParameter(valueString) - if err != nil { - return nil, utils.LavaFormatWarning("Failed converting valueString to block number", err, utils.LogAttr("value", valueString)) - } - parsed.parsedBlock = block + block := blockInterfaceToString(value) + parsed.parsedDataRaw = block return parsed, nil case spectypes.PARSER_TYPE_BLOCK_HASH: return parseGenericParserBlockHash(value) diff --git a/protocol/parser/parser_test.go b/protocol/parser/parser_test.go index b90e2cd226..c005804850 100644 --- a/protocol/parser/parser_test.go +++ b/protocol/parser/parser_test.go @@ -346,8 +346,8 @@ func TestParseBlockFromParamsHappyFlow(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - block := ParseBlockFromParams(&testCase.message, testCase.blockParser, nil) - require.Equal(t, testCase.expectedBlock, block.parsedBlock) + parsedInput := ParseBlockFromParams(&testCase.message, testCase.blockParser, nil) + require.Equal(t, testCase.expectedBlock, parsedInput.GetBlock()) }) } } @@ -405,9 +405,8 @@ func TestParseBlockFromReplyHappyFlow(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - block, err := ParseBlockFromReply(&testCase.message, testCase.blockParser) - require.NoError(t, err, fmt.Sprintf("Test case name: %s", testCase.name)) - require.Equal(t, testCase.expectedBlock, block) + parsedInput := ParseBlockFromReply(&testCase.message, testCase.blockParser, nil) + require.Equal(t, testCase.expectedBlock, parsedInput.GetBlock()) }) } } @@ -585,7 +584,143 @@ func TestParseBlockFromParams(t *testing.T) { t.Run(test.name, func(t *testing.T) { t.Parallel() result := ParseBlockFromParams(test.rpcInput, test.blockParser, test.genericParsers) - require.Equal(t, test.expected, result.parsedBlock) + require.Equal(t, test.expected, result.GetBlock()) + }) + } +} + +func TestParseBlockFromReply(t *testing.T) { + tests := []struct { + name string + rpcInput RPCInput + blockParser spectypes.BlockParser + genericParsers []spectypes.GenericParser + expected int64 + }{ + { + name: "generic_parser_happy_flow_default_value", + rpcInput: &RPCInputTest{ + Result: []byte(` + { + "foo": { + "bar": [ + { + "baz": 123 + } + ] + } + } + `), + }, + genericParsers: []spectypes.GenericParser{ + { + ParsePath: ".result.foo.bar.[0].baz", + Rule: "=123", + Value: "latest", + ParseType: spectypes.PARSER_TYPE_DEFAULT_VALUE, + }, + }, + expected: spectypes.LATEST_BLOCK, + }, + { + name: "generic_parser_happy_flow_value", + rpcInput: &RPCInputTest{ + Result: []byte(` + { + "foo": { + "bar": [ + { + "baz": 123 + } + ] + } + } + `), + }, + genericParsers: []spectypes.GenericParser{ + { + ParsePath: ".result.foo.bar.[0].baz", + ParseType: spectypes.PARSER_TYPE_BLOCK_LATEST, + }, + }, + expected: 123, + }, + { + name: "generic_parser_nil_params", + rpcInput: &RPCInputTest{}, + genericParsers: []spectypes.GenericParser{ + { + ParsePath: ".result.foo", + Value: "latest", + ParseType: spectypes.PARSER_TYPE_DEFAULT_VALUE, + }, + }, + expected: spectypes.NOT_APPLICABLE, + }, + { + name: "generic_parser_fail_with_nil_var", + rpcInput: &RPCInputTest{ + Result: []byte(` + { + "bar": 123 + } + `), + }, + genericParsers: []spectypes.GenericParser{ + { + ParsePath: ".result.foo", + Value: "latest", + ParseType: spectypes.PARSER_TYPE_DEFAULT_VALUE, + }, + }, + expected: spectypes.NOT_APPLICABLE, + }, + { + name: "generic_parser_fail_with_iter_error", + rpcInput: &RPCInputTest{ + Result: []byte(` + { + "bar": 123 + } + `), + }, + genericParsers: []spectypes.GenericParser{ + { + ParsePath: ".result.bar.foo", + Value: "latest", + ParseType: spectypes.PARSER_TYPE_DEFAULT_VALUE, + }, + }, + expected: spectypes.NOT_APPLICABLE, + }, + { + name: "generic_parser_wrong_jq_path_with_parser_func_default", + rpcInput: &RPCInputTest{ + Params: map[string]interface{}{ + "bar": 123, + }, + }, + genericParsers: []spectypes.GenericParser{ + { + ParsePath: "!@#$%^&*()", + Value: "latest", + ParseType: spectypes.PARSER_TYPE_DEFAULT_VALUE, + }, + }, + blockParser: spectypes.BlockParser{ + ParserFunc: spectypes.PARSER_FUNC_DEFAULT, + ParserArg: []string{"latest"}, + }, + expected: spectypes.LATEST_BLOCK, + }, + } + + for _, test := range tests { + test := test + t.Run(test.name, func(t *testing.T) { + t.Parallel() + parsedInput := ParseBlockFromReply(test.rpcInput, test.blockParser, test.genericParsers) + require.Equal(t, test.expected, parsedInput.GetBlock()) }) } } @@ -642,14 +777,17 @@ func TestParseBlockFromParamsHash(t *testing.T) { for _, test := range tests { test := test t.Run(test.name, func(t *testing.T) { - t.Parallel() - result := ParseBlockFromParams(test.rpcInput, test.blockParser, test.genericParsers) + // t.Parallel() + parsedInput := ParseBlockFromParams(test.rpcInput, test.blockParser, test.genericParsers) + parsedHashes, err := parsedInput.GetBlockHashes() if test.expectedHash == "" { - require.Len(t, result.parsedHashes, 0) + require.Error(t, err) + require.Len(t, parsedHashes, 0) } else { - require.Equal(t, test.expectedHash, result.parsedHashes[0]) + require.NoError(t, err) + require.Equal(t, test.expectedHash, parsedHashes[0]) } - require.Equal(t, test.expected, result.parsedBlock) + require.Equal(t, test.expected, parsedInput.GetBlock()) }) } } @@ -686,14 +824,14 @@ func TestParseGeneric(t *testing.T) { "finality": "final", }, } - res, err := parseGeneric(jsonMap, spectypes.GenericParser{ + parsedInput, err := parseGeneric(jsonMap, spectypes.GenericParser{ ParsePath: ".params.finality", Value: "latest", ParseType: spectypes.PARSER_TYPE_DEFAULT_VALUE, Rule: "=final || =optimistic", }) require.NoError(t, err) - require.Equal(t, spectypes.LATEST_BLOCK, res.parsedBlock) + require.Equal(t, "latest", parsedInput.GetRawParsedData()) } func TestHashLengthValidation(t *testing.T) { @@ -702,3 +840,68 @@ func TestHashLengthValidation(t *testing.T) { _, err = parseGenericParserBlockHash("123456789,123456789,123456789,12") require.NoError(t, err) } + +func TestParseRawBlock(t *testing.T) { + defaultValue := "defaultValue" + defaultBlock := int64(1) + rawBlock := "123" + expectedBlock := int64(123) + + t.Run("with raw block parsed", func(t *testing.T) { + parsedInput := &ParsedInput{ + parsedDataRaw: rawBlock, + } + + rpcInput := RPCInputTest{ + ParseBlockFunc: func(block string) (int64, error) { + require.Equal(t, parsedInput.parsedDataRaw, block) + return expectedBlock, nil + }, + } + + ParseRawBlock(&rpcInput, parsedInput, defaultValue) + require.Equal(t, expectedBlock, parsedInput.GetBlock()) + }) + + t.Run("without raw block parsed, with default value", func(t *testing.T) { + parsedInput := &ParsedInput{} + + rpcInput := RPCInputTest{ + ParseBlockFunc: func(block string) (int64, error) { + require.Equal(t, defaultValue, block) + return defaultBlock, nil + }, + } + + ParseRawBlock(&rpcInput, parsedInput, defaultValue) + require.Equal(t, defaultBlock, parsedInput.GetBlock()) + }) + + t.Run("without raw block parsed, with default value parse error", func(t *testing.T) { + parsedInput := &ParsedInput{} + + rpcInput := RPCInputTest{ + ParseBlockFunc: func(block string) (int64, error) { + require.Equal(t, defaultValue, block) + return 0, fmt.Errorf("parse error") + }, + } + + ParseRawBlock(&rpcInput, parsedInput, defaultValue) + require.Equal(t, spectypes.NOT_APPLICABLE, parsedInput.GetBlock()) + }) + + t.Run("without raw block parsed, without default value", func(t *testing.T) { + parsedInput := &ParsedInput{} + + rpcInput := RPCInputTest{ + ParseBlockFunc: func(block string) (int64, error) { + require.Fail(t, "should not be called") + return 0, nil + }, + } + + ParseRawBlock(&rpcInput, parsedInput, "") + require.Equal(t, spectypes.NOT_APPLICABLE, parsedInput.GetBlock()) + }) +} diff --git a/protocol/rpcconsumer/rpcconsumer_server.go b/protocol/rpcconsumer/rpcconsumer_server.go index af11a2d952..698cb5b68c 100644 --- a/protocol/rpcconsumer/rpcconsumer_server.go +++ b/protocol/rpcconsumer/rpcconsumer_server.go @@ -689,6 +689,7 @@ func (rpccs *RPCConsumerServer) sendRelayToProvider( utils.LavaFormatError("Failed relaySubscriptionInner", errResponse, utils.LogAttr("Request", localRelayRequestData), utils.LogAttr("Request data", string(localRelayRequestData.Data)), + utils.LogAttr("Provider", providerPublicAddress), ) } diff --git a/x/dualstaking/keeper/delegator_reward.go b/x/dualstaking/keeper/delegator_reward.go index a1d428ee26..5decaf9a7e 100644 --- a/x/dualstaking/keeper/delegator_reward.go +++ b/x/dualstaking/keeper/delegator_reward.go @@ -1,6 +1,7 @@ package keeper import ( + "fmt" "strconv" "cosmossdk.io/math" @@ -158,47 +159,55 @@ func (k Keeper) ClaimRewards(ctx sdk.Context, delegator string, provider string) // RewardProvidersAndDelegators is the main function handling provider rewards with delegations // it returns the provider reward amount and updates the delegatorReward map with the reward portion for each delegator -func (k Keeper) RewardProvidersAndDelegators(ctx sdk.Context, provider string, chainID string, totalReward sdk.Coins, senderModule string, calcOnlyProvider bool, calcOnlyDelegators bool, calcOnlyContributor bool) (providerReward sdk.Coins, claimableRewards sdk.Coins, err error) { +// since this function does not actually send rewards to the providers and delegator (but only allocates rewards to be claimed) +func (k Keeper) RewardProvidersAndDelegators(ctx sdk.Context, provider string, chainID string, totalReward sdk.Coins, senderModule string, calcOnlyProvider bool, calcOnlyDelegators bool, calcOnlyContributor bool) (providerReward sdk.Coins, err error) { block := uint64(ctx.BlockHeight()) zeroCoins := sdk.NewCoins() epoch, _, err := k.epochstorageKeeper.GetEpochStartForBlock(ctx, block) if err != nil { - return zeroCoins, zeroCoins, utils.LavaFormatError(types.ErrCalculatingProviderReward.Error(), err, + return zeroCoins, utils.LavaFormatError(types.ErrCalculatingProviderReward.Error(), err, utils.Attribute{Key: "block", Value: block}, ) } stakeEntry, found := k.epochstorageKeeper.GetStakeEntry(ctx, epoch, chainID, provider) if !found { - return zeroCoins, zeroCoins, err + return zeroCoins, utils.LavaFormatWarning("RewardProvidersAndDelegators: cannot send rewards to provider and delegators", fmt.Errorf("provider stake entry not found, probably unstaked"), + utils.LogAttr("epoch", epoch), + utils.LogAttr("provider", provider), + utils.LogAttr("chain_id", chainID), + utils.LogAttr("sender_module", senderModule), + utils.LogAttr("reward", totalReward.String()), + ) } delegations, err := k.GetProviderDelegators(ctx, provider, epoch) if err != nil { - return zeroCoins, zeroCoins, utils.LavaFormatError("cannot get provider's delegators", err) + return zeroCoins, utils.LavaFormatError("cannot get provider's delegators", err) } - claimableRewards = totalReward // make sure this is post boost when rewards pool is introduced contributorAddresses, contributorPart := k.specKeeper.GetContributorReward(ctx, chainID) contributorsNum := sdk.NewInt(int64(len(contributorAddresses))) + contributorReward := zeroCoins if !contributorsNum.IsZero() && contributorPart.GT(math.LegacyZeroDec()) { - contributorReward := totalReward.MulInt(contributorPart.MulInt64(spectypes.ContributorPrecision).RoundInt()).QuoInt(sdk.NewInt(spectypes.ContributorPrecision)) + contributorReward = totalReward.MulInt(contributorPart.MulInt64(spectypes.ContributorPrecision).RoundInt()).QuoInt(sdk.NewInt(spectypes.ContributorPrecision)) // make sure to round it down for the integers division contributorReward = contributorReward.QuoInt(contributorsNum).MulInt(contributorsNum) - claimableRewards = totalReward.Sub(contributorReward...) if !calcOnlyContributor { err = k.PayContributors(ctx, senderModule, contributorAddresses, contributorReward, chainID) if err != nil { - return zeroCoins, zeroCoins, err + return zeroCoins, err } } } + // delegators eligible for rewards are delegators that their delegation is at least a week old relevantDelegations := lavaslices.Filter(delegations, func(d types.Delegation) bool { return d.ChainID == chainID && d.IsFirstWeekPassed(ctx.BlockTime().UTC().Unix()) && d.Delegator != stakeEntry.Vault }) - providerReward, delegatorsReward := k.CalcRewards(ctx, stakeEntry, claimableRewards, relevantDelegations) + // calculate the rewards for the providers and delegators (total reward - contributors reward) + providerReward, delegatorsReward := k.CalcRewards(ctx, stakeEntry, totalReward.Sub(contributorReward...), relevantDelegations) leftoverRewards := k.updateDelegatorsReward(ctx, stakeEntry.DelegateTotal.Amount, relevantDelegations, delegatorsReward, senderModule, calcOnlyDelegators) fullProviderReward := providerReward.Add(leftoverRewards...) @@ -208,7 +217,7 @@ func (k Keeper) RewardProvidersAndDelegators(ctx sdk.Context, provider string, c k.rewardDelegator(ctx, types.Delegation{Provider: stakeEntry.Address, ChainID: chainID, Delegator: stakeEntry.Vault}, fullProviderReward, senderModule) } - return fullProviderReward, claimableRewards, nil + return fullProviderReward, nil } // updateDelegatorsReward updates the delegator rewards map @@ -217,11 +226,9 @@ func (k Keeper) updateDelegatorsReward(ctx sdk.Context, totalDelegations math.In for _, delegation := range delegations { delegatorReward := k.CalcDelegatorReward(ctx, delegatorsReward, totalDelegations, delegation) - if !calcOnly { k.rewardDelegator(ctx, delegation, delegatorReward, senderModule) } - usedDelegatorRewards = usedDelegatorRewards.Add(delegatorReward...) } diff --git a/x/pairing/keeper/cu_tracker_test.go b/x/pairing/keeper/cu_tracker_test.go index eef6daccc7..cc5454d765 100644 --- a/x/pairing/keeper/cu_tracker_test.go +++ b/x/pairing/keeper/cu_tracker_test.go @@ -641,13 +641,16 @@ func TestProviderMonthlyPayoutQueryWithContributor(t *testing.T) { } ts.relayPaymentWithoutPay(relayPaymentMessage, true) - // check for expected balance: planPrice*100/200 (from spec1) + planPrice*(100/200)*(2/3) (from spec, considering delegations) - // for planPrice=100, expected monthly payout is 50 (spec1 with contributor) + 33 (normal spec no contributor) - expectedContributorPay := uint64(12) // half the plan payment for spec1:25 then divided between contributors half half rounded down - expectedTotalPayout := uint64(83) - expectedContributorPay*2 + // half the plan payment for spec1 is 25. Then it's divided between 2 contributors equally rounded down + expectedContributorPay := uint64(12) + + // for planPrice=100, and equal CU usage for both specs, the expected provider monthly payout is: + // spec (delegator is 33% of stake): planPrice * specUsedCu/totalUsedCu * providerStake/totalStake = 100*0.5*(2/3) = 33 + // spec1 (contributors with commission=50%): planPrice * specUsedCu/totalUsedCu - contributorsPart = 100*0.5 - 24 = 26 + expectedTotalPayout := uint64(59) expectedPayouts := []types.SubscriptionPayout{ {Subscription: clientAcc.Addr.String(), ChainId: ts.spec.Index, Amount: 33}, - {Subscription: clientAcc.Addr.String(), ChainId: spec1.Index, Amount: 26}, // 50 - 26 for contributors (each contributor gets 12) + {Subscription: clientAcc.Addr.String(), ChainId: spec1.Index, Amount: 26}, } res, err := ts.QueryPairingProviderMonthlyPayout(provider) require.NoError(t, err) diff --git a/x/pairing/keeper/delegator_rewards_test.go b/x/pairing/keeper/delegator_rewards_test.go index fd9ba80d3c..a8049e9811 100644 --- a/x/pairing/keeper/delegator_rewards_test.go +++ b/x/pairing/keeper/delegator_rewards_test.go @@ -541,7 +541,7 @@ func TestDelegationFirstMonthReward(t *testing.T) { // this, we'll call the reward calculation function directly with a fabricated reward just to // verify that the delegator gets nothing from the total reward fakeReward := sdk.NewCoins(sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(testStake))) - providerReward, _, err := ts.Keepers.Dualstaking.RewardProvidersAndDelegators(ts.Ctx, provider, ts.spec.Index, + providerReward, err := ts.Keepers.Dualstaking.RewardProvidersAndDelegators(ts.Ctx, provider, ts.spec.Index, fakeReward, subscriptiontypes.ModuleName, true, true, true) require.NoError(t, err) require.True(t, fakeReward.IsEqual(providerReward)) // if the delegator got anything, this would fail @@ -603,11 +603,11 @@ func TestRedelegationFirstMonthReward(t *testing.T) { // verify that the delegator gets nothing from the total reward from provider1 but does get // reward from provider fakeReward := sdk.NewCoins(sdk.NewCoin(ts.TokenDenom(), sdk.NewInt(testStake))) - provider1Reward, _, err := ts.Keepers.Dualstaking.RewardProvidersAndDelegators(ts.Ctx, provider1, ts.spec.Index, + provider1Reward, err := ts.Keepers.Dualstaking.RewardProvidersAndDelegators(ts.Ctx, provider1, ts.spec.Index, fakeReward, subscriptiontypes.ModuleName, true, false, true) require.NoError(t, err) require.True(t, fakeReward.IsEqual(provider1Reward)) // if the delegator got anything, this would fail - providerReward, _, err := ts.Keepers.Dualstaking.RewardProvidersAndDelegators(ts.Ctx, provider, ts.spec.Index, + providerReward, err := ts.Keepers.Dualstaking.RewardProvidersAndDelegators(ts.Ctx, provider, ts.spec.Index, fakeReward, subscriptiontypes.ModuleName, true, false, true) require.NoError(t, err) require.False(t, fakeReward.IsEqual(providerReward)) // the delegator should have rewards diff --git a/x/pairing/keeper/grpc_query_provider_monthly_payout.go b/x/pairing/keeper/grpc_query_provider_monthly_payout.go index 7d5759fffa..1268a2bd82 100644 --- a/x/pairing/keeper/grpc_query_provider_monthly_payout.go +++ b/x/pairing/keeper/grpc_query_provider_monthly_payout.go @@ -73,7 +73,7 @@ func (k Keeper) ProviderMonthlyPayout(goCtx context.Context, req *types.QueryPro providerRewardAfterFees := sdk.NewCoins(sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), totalMonthlyReward.Sub(validatorsFee.AmountOf(denom)).Sub(communityFee.AmountOf(denom)))) // calculate only the provider reward - providerReward, _, err := k.dualstakingKeeper.RewardProvidersAndDelegators(ctx, req.Provider, chainID, providerRewardAfterFees, subsciptiontypes.ModuleName, true, true, true) + providerReward, err := k.dualstakingKeeper.RewardProvidersAndDelegators(ctx, req.Provider, chainID, providerRewardAfterFees, subsciptiontypes.ModuleName, true, true, true) if err != nil { return nil, err } diff --git a/x/pairing/keeper/unstaking.go b/x/pairing/keeper/unstaking.go index ff4f6eafb0..87d64d5174 100644 --- a/x/pairing/keeper/unstaking.go +++ b/x/pairing/keeper/unstaking.go @@ -68,13 +68,6 @@ func (k Keeper) UnstakeEntry(ctx sdk.Context, validator, chainID, creator, unsta } func (k Keeper) UnstakeEntryForce(ctx sdk.Context, chainID, provider, unstakeDescription string) error { - providerAddr, err := sdk.AccAddressFromBech32(provider) - if err != nil { - return utils.LavaFormatWarning("invalid address", err, - utils.Attribute{Key: "provider", Value: provider}, - ) - } - existingEntry, entryExists := k.epochStorageKeeper.GetStakeEntryCurrent(ctx, chainID, provider) if !entryExists { return utils.LavaFormatWarning("can't unstake Entry, stake entry not found for address", fmt.Errorf("stake entry not found"), @@ -83,7 +76,15 @@ func (k Keeper) UnstakeEntryForce(ctx sdk.Context, chainID, provider, unstakeDes ) } totalAmount := existingEntry.Stake.Amount - delegations := k.stakingKeeper.GetAllDelegatorDelegations(ctx, providerAddr) + vaultAcc, err := sdk.AccAddressFromBech32(existingEntry.Vault) + if err != nil { + return utils.LavaFormatError("can't unstake entry, invalid vault address", err, + utils.LogAttr("provider", provider), + utils.LogAttr("chain", chainID), + utils.LogAttr("vault", existingEntry.Vault), + ) + } + delegations := k.stakingKeeper.GetAllDelegatorDelegations(ctx, vaultAcc) for _, delegation := range delegations { validator, found := k.stakingKeeper.GetValidator(ctx, delegation.GetValidatorAddr()) @@ -105,9 +106,6 @@ func (k Keeper) UnstakeEntryForce(ctx sdk.Context, chainID, provider, unstakeDes } if totalAmount.IsZero() { - existingEntry, _ := k.epochStorageKeeper.GetStakeEntryCurrent(ctx, chainID, provider) - k.epochStorageKeeper.RemoveStakeEntryCurrent(ctx, chainID, existingEntry.Address) - details := map[string]string{ "address": existingEntry.GetAddress(), "chainID": existingEntry.GetChain(), diff --git a/x/pairing/types/expected_keepers.go b/x/pairing/types/expected_keepers.go index 6a8fb13978..b9ba3bed29 100644 --- a/x/pairing/types/expected_keepers.go +++ b/x/pairing/types/expected_keepers.go @@ -102,7 +102,7 @@ type DowntimeKeeper interface { } type DualstakingKeeper interface { - RewardProvidersAndDelegators(ctx sdk.Context, providerAddr string, chainID string, totalReward sdk.Coins, senderModule string, calcOnlyProvider bool, calcOnlyDelegators bool, calcOnlyContributor bool) (providerReward sdk.Coins, totalRewards sdk.Coins, err error) + RewardProvidersAndDelegators(ctx sdk.Context, providerAddr string, chainID string, totalReward sdk.Coins, senderModule string, calcOnlyProvider bool, calcOnlyDelegators bool, calcOnlyContributor bool) (providerReward sdk.Coins, 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 GetProviderDelegators(ctx sdk.Context, provider string, epoch uint64) ([]dualstakingtypes.Delegation, error) diff --git a/x/rewards/keeper/iprpc.go b/x/rewards/keeper/iprpc.go index 8ac287e452..90d94380c9 100644 --- a/x/rewards/keeper/iprpc.go +++ b/x/rewards/keeper/iprpc.go @@ -132,7 +132,6 @@ func (k Keeper) distributeIprpcRewards(ctx sdk.Context, iprpcReward types.IprpcR k.handleNoIprpcRewardToProviders(ctx, iprpcReward.SpecFunds) return } - leftovers := sdk.NewCoins() for _, specFund := range iprpcReward.SpecFunds { details := map[string]string{} @@ -178,9 +177,10 @@ func (k Keeper) distributeIprpcRewards(ctx sdk.Context, iprpcReward types.IprpcR UsedReward = UsedRewardTemp // reward the provider - _, _, err := k.dualstakingKeeper.RewardProvidersAndDelegators(ctx, providerCU.Provider, specFund.Spec, providerIprpcReward, string(types.IprpcPoolName), false, false, false) + _, err := k.dualstakingKeeper.RewardProvidersAndDelegators(ctx, providerCU.Provider, specFund.Spec, providerIprpcReward, string(types.IprpcPoolName), false, false, false) if err != nil { - utils.LavaFormatError("failed to send iprpc rewards to provider", err, utils.LogAttr("provider", providerCU)) + // failed sending the rewards, add the claimable rewards to the leftovers that will be transferred to the community pool + utils.LavaFormatPanic("failed to send iprpc rewards to provider", err, utils.LogAttr("provider", providerCU)) } details[providerCU.Provider] = fmt.Sprintf("cu: %d reward: %s", providerCU.CU, providerIprpcReward.String()) } diff --git a/x/rewards/keeper/providers.go b/x/rewards/keeper/providers.go index e9a45ab093..43dc4b42f9 100644 --- a/x/rewards/keeper/providers.go +++ b/x/rewards/keeper/providers.go @@ -88,7 +88,7 @@ func (k Keeper) distributeMonthlyBonusRewards(ctx sdk.Context) { return } // now give the reward the provider contributor and delegators - _, _, err := k.dualstakingKeeper.RewardProvidersAndDelegators(ctx, basepay.Provider, basepay.ChainId, sdk.NewCoins(sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), reward)), string(types.ProviderRewardsDistributionPool), false, false, false) + _, err := k.dualstakingKeeper.RewardProvidersAndDelegators(ctx, basepay.Provider, basepay.ChainId, sdk.NewCoins(sdk.NewCoin(k.stakingKeeper.BondDenom(ctx), reward)), string(types.ProviderRewardsDistributionPool), false, false, false) if err != nil { utils.LavaFormatError("failed to send bonus rewards to provider", err, utils.LogAttr("provider", basepay.Provider)) } @@ -178,10 +178,14 @@ func (k Keeper) specProvidersBasePay(ctx sdk.Context, chainID string, pop bool) } totalBasePay := math.ZeroInt() + stakedBasePays := []types.BasePayWithIndex{} for _, basepay := range basepays { - totalBasePay = totalBasePay.Add(basepay.BasePay.Total) + if _, found := k.epochstorage.GetStakeEntryCurrent(ctx, basepay.ChainId, basepay.Provider); found { + totalBasePay = totalBasePay.Add(basepay.BasePay.Total) + stakedBasePays = append(stakedBasePays, basepay) + } } - return basepays, totalBasePay + return stakedBasePays, totalBasePay } // ContributeToValidatorsAndCommunityPool transfers some of the providers' rewards to the validators and community pool diff --git a/x/rewards/types/expected_keepers.go b/x/rewards/types/expected_keepers.go index a79582f6d4..989c7b78ea 100644 --- a/x/rewards/types/expected_keepers.go +++ b/x/rewards/types/expected_keepers.go @@ -53,7 +53,7 @@ type StakingKeeper interface { } type DualStakingKeeper interface { - RewardProvidersAndDelegators(ctx sdk.Context, providerAddr string, chainID string, totalReward sdk.Coins, senderModule string, calcOnlyProvider bool, calcOnlyDelegators bool, calcOnlyContributor bool) (providerReward sdk.Coins, totalRewards sdk.Coins, err error) + RewardProvidersAndDelegators(ctx sdk.Context, providerAddr string, chainID string, totalReward sdk.Coins, senderModule string, calcOnlyProvider bool, calcOnlyDelegators bool, calcOnlyContributor bool) (providerReward sdk.Coins, err error) // Methods imported from bank should be defined here } diff --git a/x/spec/types/api_collection.pb.go b/x/spec/types/api_collection.pb.go index 5591ce0b28..2cb76295ff 100644 --- a/x/spec/types/api_collection.pb.go +++ b/x/spec/types/api_collection.pb.go @@ -795,10 +795,11 @@ func (m *Api) GetParsers() []GenericParser { } type ParseDirective struct { - FunctionTag FUNCTION_TAG `protobuf:"varint,1,opt,name=function_tag,json=functionTag,proto3,enum=lavanet.lava.spec.FUNCTION_TAG" json:"function_tag,omitempty"` - FunctionTemplate string `protobuf:"bytes,2,opt,name=function_template,json=functionTemplate,proto3" json:"function_template,omitempty"` - ResultParsing BlockParser `protobuf:"bytes,3,opt,name=result_parsing,json=resultParsing,proto3" json:"result_parsing"` - ApiName string `protobuf:"bytes,4,opt,name=api_name,json=apiName,proto3" json:"api_name,omitempty"` + FunctionTag FUNCTION_TAG `protobuf:"varint,1,opt,name=function_tag,json=functionTag,proto3,enum=lavanet.lava.spec.FUNCTION_TAG" json:"function_tag,omitempty"` + FunctionTemplate string `protobuf:"bytes,2,opt,name=function_template,json=functionTemplate,proto3" json:"function_template,omitempty"` + ResultParsing BlockParser `protobuf:"bytes,3,opt,name=result_parsing,json=resultParsing,proto3" json:"result_parsing"` + ApiName string `protobuf:"bytes,4,opt,name=api_name,json=apiName,proto3" json:"api_name,omitempty"` + Parsers []GenericParser `protobuf:"bytes,5,rep,name=parsers,proto3" json:"parsers"` } func (m *ParseDirective) Reset() { *m = ParseDirective{} } @@ -862,6 +863,13 @@ func (m *ParseDirective) GetApiName() string { return "" } +func (m *ParseDirective) GetParsers() []GenericParser { + if m != nil { + return m.Parsers + } + return nil +} + type BlockParser struct { ParserArg []string `protobuf:"bytes,1,rep,name=parser_arg,json=parserArg,proto3" json:"parser_arg,omitempty"` ParserFunc PARSER_FUNC `protobuf:"varint,2,opt,name=parser_func,json=parserFunc,proto3,enum=lavanet.lava.spec.PARSER_FUNC" json:"parser_func,omitempty"` @@ -1100,108 +1108,108 @@ func init() { } var fileDescriptor_c9f7567a181f534f = []byte{ - // 1606 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x57, 0xcf, 0x6f, 0xdb, 0xc8, + // 1613 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x57, 0xcf, 0x6f, 0xdb, 0xc8, 0x15, 0x36, 0x25, 0xea, 0xd7, 0xb3, 0x24, 0x4f, 0x26, 0x6e, 0xaa, 0x4d, 0xb3, 0x96, 0xcb, 0xdd, 0x76, 0x03, 0x2f, 0x6a, 0xa3, 0x0e, 0x0a, 0x14, 0x8b, 0x16, 0x2d, 0x25, 0xd1, 0x89, 0x12, 0x59, 0x32, 0x46, 0xb4, 0x5b, 0xf7, 0x42, 0x8c, 0xa9, 0xb1, 0x3c, 0x58, 0x8a, 0x24, 0xc8, 0xa1, 0x1b, - 0x9f, 0xfb, 0x0f, 0xf4, 0x50, 0xa0, 0xff, 0x42, 0x81, 0x02, 0x05, 0xfa, 0x5f, 0xec, 0x71, 0x6f, - 0xed, 0xc9, 0x28, 0x92, 0x43, 0xd1, 0x1c, 0x73, 0x29, 0x7a, 0x28, 0x50, 0xcc, 0x90, 0xfa, 0xc1, - 0x44, 0x71, 0x91, 0x93, 0x34, 0xdf, 0x7c, 0xf3, 0xcd, 0x9b, 0xf7, 0xde, 0x7c, 0x23, 0xc1, 0x0f, - 0x3d, 0x7a, 0x4d, 0x7d, 0x26, 0x0e, 0xe4, 0xe7, 0x41, 0x1c, 0x32, 0xf7, 0x80, 0x86, 0xdc, 0x71, - 0x03, 0xcf, 0x63, 0xae, 0xe0, 0x81, 0xbf, 0x1f, 0x46, 0x81, 0x08, 0xf0, 0xbd, 0x8c, 0xb7, 0x2f, - 0x3f, 0xf7, 0x25, 0xef, 0xe1, 0xf6, 0x34, 0x98, 0x06, 0x6a, 0xf6, 0x40, 0x7e, 0x4b, 0x89, 0xc6, - 0x7f, 0x8b, 0xd0, 0x30, 0x43, 0xde, 0x5d, 0x08, 0xe0, 0x16, 0x54, 0x98, 0x4f, 0x2f, 0x3c, 0x36, - 0x69, 0x69, 0xbb, 0xda, 0xe3, 0x2a, 0x99, 0x0f, 0xf1, 0x09, 0x6c, 0x2d, 0x37, 0x72, 0x26, 0x54, - 0xd0, 0x56, 0x61, 0x57, 0x7b, 0xbc, 0x79, 0xf8, 0xfd, 0xfd, 0xf7, 0xb6, 0xdb, 0x5f, 0x2a, 0xf6, - 0xa8, 0xa0, 0x1d, 0xfd, 0x9b, 0xdb, 0xf6, 0x06, 0x69, 0xba, 0x39, 0x14, 0xef, 0x81, 0x4e, 0x43, - 0x1e, 0xb7, 0x8a, 0xbb, 0xc5, 0xc7, 0x9b, 0x87, 0x0f, 0xd6, 0xc8, 0x98, 0x21, 0x27, 0x8a, 0x83, - 0x9f, 0x40, 0xe5, 0x8a, 0xd1, 0x09, 0x8b, 0xe2, 0x96, 0xae, 0xe8, 0x9f, 0xac, 0xa1, 0x3f, 0x53, - 0x0c, 0x32, 0x67, 0xe2, 0x01, 0x20, 0xee, 0x5f, 0xb1, 0x88, 0x0b, 0xea, 0xbb, 0xcc, 0x51, 0x9b, - 0x95, 0xd4, 0xea, 0xff, 0x1f, 0x33, 0xd9, 0x5a, 0x59, 0x6a, 0xca, 0x10, 0x06, 0x80, 0x42, 0x1a, - 0xc5, 0xcc, 0x99, 0xf0, 0x48, 0xf2, 0xae, 0x59, 0xdc, 0x2a, 0x7f, 0x50, 0xed, 0x44, 0x52, 0x7b, - 0x73, 0x26, 0xd9, 0x0a, 0x73, 0xe3, 0x18, 0xff, 0x0c, 0x80, 0xbd, 0x14, 0xcc, 0x8f, 0x79, 0xe0, - 0xc7, 0xad, 0x8a, 0xd2, 0x79, 0xb4, 0x46, 0xc7, 0x9a, 0x93, 0xc8, 0x0a, 0x1f, 0x5b, 0xd0, 0xb8, - 0x66, 0x11, 0xbf, 0xe4, 0x2e, 0x15, 0x4a, 0xa0, 0xaa, 0x04, 0xda, 0x6b, 0x04, 0xce, 0x56, 0x78, - 0x24, 0xbf, 0xca, 0xf8, 0x2d, 0xd4, 0x16, 0xfa, 0x18, 0x83, 0xee, 0xd3, 0x19, 0x53, 0x75, 0xaf, - 0x11, 0xf5, 0x1d, 0x7f, 0x09, 0x7a, 0x94, 0x78, 0xac, 0x55, 0x54, 0x95, 0xfe, 0xee, 0x1a, 0x79, - 0x92, 0x78, 0x8c, 0x28, 0x12, 0xfe, 0x0c, 0x1a, 0x6e, 0xe2, 0xcc, 0x12, 0x4f, 0xf0, 0xd0, 0xe3, - 0x2c, 0x6a, 0xe9, 0xbb, 0xda, 0x63, 0x9d, 0xd4, 0xdd, 0xe4, 0x78, 0x81, 0x3d, 0xd7, 0xab, 0x05, - 0x54, 0x34, 0x1e, 0x81, 0x2e, 0x17, 0xe2, 0x6d, 0x28, 0x5d, 0x78, 0x81, 0xfb, 0xb5, 0xda, 0x54, - 0x27, 0xe9, 0xc0, 0xf8, 0xb3, 0x06, 0xf5, 0xd5, 0xb0, 0xd7, 0x86, 0xf6, 0x1c, 0xb6, 0xde, 0x29, - 0xc7, 0x1d, 0xfd, 0xf8, 0x4e, 0x35, 0x9a, 0xf9, 0x6a, 0xe0, 0x9f, 0x40, 0xf9, 0x9a, 0x7a, 0x09, - 0x9b, 0xf7, 0xe2, 0xa7, 0x1f, 0x92, 0x38, 0x93, 0x2c, 0x92, 0x91, 0x9f, 0xeb, 0x55, 0x1d, 0x95, - 0x8c, 0xff, 0x68, 0x00, 0xcb, 0x49, 0xfc, 0x08, 0x6a, 0x8b, 0x42, 0x65, 0x01, 0x2f, 0x01, 0xfc, - 0x03, 0x68, 0xb2, 0x97, 0x21, 0x73, 0x05, 0x9b, 0x38, 0x4a, 0x45, 0x05, 0x5d, 0x23, 0x8d, 0x39, - 0x9a, 0x8a, 0x7c, 0x01, 0x5b, 0x1e, 0x15, 0x2c, 0x16, 0xce, 0x84, 0xc7, 0xaa, 0x05, 0x55, 0x09, - 0x74, 0xd2, 0x4c, 0xe1, 0x5e, 0x86, 0xe2, 0x21, 0x54, 0x63, 0x26, 0x8b, 0x2a, 0x6e, 0x54, 0xba, - 0x9b, 0x87, 0x87, 0x77, 0xc6, 0x9e, 0x6b, 0x87, 0x71, 0xb6, 0x92, 0x2c, 0x34, 0x8c, 0x1f, 0xc1, - 0xf6, 0x3a, 0x06, 0xae, 0x82, 0x7e, 0x44, 0xb9, 0x87, 0x36, 0xf0, 0x26, 0x54, 0x7e, 0x45, 0x23, - 0x9f, 0xfb, 0x53, 0xa4, 0x19, 0x7f, 0x2d, 0x40, 0x33, 0x7f, 0x6f, 0xf0, 0x19, 0x34, 0xa4, 0x29, - 0x71, 0x5f, 0xb0, 0xe8, 0x92, 0xba, 0x59, 0xd1, 0x3a, 0x3f, 0x7e, 0x73, 0xdb, 0xce, 0x4f, 0xbc, - 0xbd, 0x6d, 0x3f, 0x9a, 0xd1, 0x30, 0x16, 0x51, 0xe2, 0x8a, 0x24, 0x62, 0x5f, 0x19, 0xb9, 0x69, - 0x83, 0xd4, 0x69, 0xc8, 0xfb, 0xf3, 0xa1, 0xd4, 0x55, 0x73, 0x3e, 0xf5, 0x9c, 0x90, 0x8a, 0xab, - 0x34, 0x71, 0xa9, 0x6e, 0x6e, 0xe2, 0x7d, 0xdd, 0xdc, 0xb4, 0x41, 0xea, 0xf3, 0xf1, 0x09, 0x15, - 0x57, 0xf8, 0x09, 0xe8, 0xe2, 0x26, 0x4c, 0xf3, 0x5b, 0xeb, 0xb4, 0xdf, 0xdc, 0xb6, 0xd5, 0xf8, - 0xed, 0x6d, 0xfb, 0x7e, 0x5e, 0x45, 0xa2, 0x06, 0x51, 0x93, 0xf8, 0x2b, 0x28, 0xd3, 0xc9, 0xc4, - 0x09, 0x7c, 0x95, 0xf4, 0x5a, 0xe7, 0xb3, 0x37, 0xb7, 0xed, 0x0c, 0x79, 0x7b, 0xdb, 0xfe, 0xce, - 0x3b, 0xc7, 0x52, 0xb8, 0x41, 0x4a, 0x74, 0x32, 0x19, 0xf9, 0xc6, 0x3f, 0x35, 0x28, 0xa7, 0x4e, - 0xb5, 0xb6, 0xaf, 0x7f, 0x0a, 0xfa, 0xd7, 0xdc, 0x9f, 0xa8, 0xe3, 0x35, 0x0f, 0x3f, 0xff, 0xa0, - 0xcd, 0x65, 0x1f, 0xf6, 0x4d, 0xc8, 0x88, 0x5a, 0x81, 0x3b, 0x50, 0xbf, 0x4c, 0xfc, 0xd4, 0x9f, - 0x05, 0x9d, 0xaa, 0x13, 0x35, 0xd7, 0x7a, 0xc2, 0xd1, 0xe9, 0xb0, 0x6b, 0xf7, 0x47, 0x43, 0xc7, - 0x36, 0x9f, 0x92, 0xcd, 0xf9, 0x22, 0x9b, 0x4e, 0x8d, 0x17, 0x00, 0x4b, 0x5d, 0xdc, 0x80, 0x5a, - 0x48, 0xe3, 0xd8, 0x89, 0x99, 0x3f, 0x41, 0x1b, 0xb8, 0x09, 0xa0, 0x86, 0x11, 0x0b, 0xbd, 0x1b, - 0xa4, 0x2d, 0xa6, 0x2f, 0x02, 0x71, 0x85, 0x0a, 0x78, 0x0b, 0x36, 0xd5, 0x90, 0x4f, 0xfd, 0x20, - 0x62, 0xa8, 0x68, 0xfc, 0xbb, 0x00, 0x45, 0x33, 0xe4, 0x77, 0x3c, 0x2a, 0xf3, 0x04, 0x14, 0x56, - 0x12, 0x20, 0x6d, 0x24, 0x98, 0x85, 0x89, 0x60, 0x4e, 0xe2, 0x73, 0x11, 0x67, 0x9d, 0x5f, 0xcf, - 0xc0, 0x53, 0x89, 0xe1, 0x7d, 0xb8, 0xcf, 0x5e, 0x8a, 0x88, 0x3a, 0x79, 0x6a, 0xea, 0x38, 0xf7, - 0xd4, 0x54, 0x77, 0x95, 0x6f, 0x42, 0xd5, 0xa5, 0x82, 0x4d, 0x83, 0xe8, 0xa6, 0x55, 0x56, 0x36, - 0xb1, 0x2e, 0x2f, 0xe3, 0x90, 0xb9, 0xdd, 0x8c, 0x96, 0x3d, 0x5a, 0x8b, 0x65, 0xb8, 0x0f, 0x0d, - 0x65, 0x4f, 0x8e, 0x34, 0x0f, 0xee, 0x4f, 0x5b, 0x15, 0xa5, 0xb3, 0xb3, 0x46, 0xa7, 0x23, 0x79, - 0xea, 0xd2, 0x45, 0x99, 0x4c, 0xfd, 0x62, 0x0e, 0x71, 0x7f, 0x8a, 0x3f, 0x05, 0x10, 0x7c, 0xc6, - 0x82, 0x44, 0x38, 0x33, 0xe9, 0xdd, 0x32, 0xe8, 0x5a, 0x86, 0x1c, 0xc7, 0xf8, 0x97, 0x50, 0x51, - 0x06, 0x15, 0xc5, 0xad, 0x9a, 0xf2, 0xa3, 0xdd, 0x35, 0x7b, 0x3c, 0x65, 0x3e, 0x8b, 0xb8, 0x9b, - 0xdb, 0x65, 0xbe, 0xcc, 0xf8, 0x97, 0x06, 0xcd, 0xbc, 0xe7, 0xbd, 0xd7, 0x1d, 0xda, 0xc7, 0x77, - 0x07, 0xfe, 0x12, 0xee, 0x2d, 0x35, 0xd8, 0x2c, 0x94, 0x66, 0x94, 0xd5, 0x0e, 0x2d, 0x78, 0x19, - 0x8e, 0x5f, 0x40, 0x33, 0x62, 0x71, 0xe2, 0x89, 0x45, 0xc2, 0x8a, 0x1f, 0x91, 0xb0, 0x46, 0xba, - 0x76, 0x9e, 0xb1, 0x4f, 0xa0, 0x2a, 0xdd, 0x41, 0x35, 0x8b, 0xba, 0x72, 0xa4, 0x42, 0x43, 0x3e, - 0xa4, 0x33, 0x66, 0xfc, 0x45, 0x83, 0xcd, 0x95, 0xf5, 0x32, 0xb9, 0x69, 0x1a, 0x1c, 0x1a, 0xc9, - 0x63, 0x16, 0xa5, 0x03, 0xa7, 0x88, 0x19, 0x4d, 0xf1, 0x2f, 0x64, 0x97, 0xaa, 0x69, 0x19, 0x71, - 0x76, 0xcd, 0xd6, 0xc5, 0x74, 0x62, 0x92, 0xb1, 0x45, 0x1c, 0x99, 0x0d, 0x92, 0x29, 0x1e, 0x25, - 0xbe, 0x2b, 0xfb, 0x73, 0xc2, 0x2e, 0xa9, 0x3c, 0x58, 0xea, 0xe0, 0xca, 0x39, 0x48, 0x3d, 0x03, - 0x53, 0x03, 0x7f, 0x08, 0x55, 0xe6, 0xbb, 0xc1, 0x44, 0x1e, 0x3b, 0x8d, 0x77, 0x31, 0x36, 0xfe, - 0xa8, 0x41, 0x23, 0x57, 0xbd, 0x45, 0xc8, 0xa9, 0xb1, 0x65, 0x8f, 0x86, 0x42, 0x94, 0x45, 0x6d, - 0x43, 0x69, 0xf5, 0xad, 0x48, 0x07, 0xf8, 0xe7, 0xf3, 0x45, 0x0b, 0xfb, 0xba, 0xf3, 0x1c, 0xf6, - 0xf9, 0x89, 0x95, 0x89, 0xaa, 0xbb, 0x8d, 0xb3, 0xa7, 0x3d, 0x8d, 0x4e, 0x7d, 0x57, 0x0f, 0xef, - 0xea, 0x1d, 0xc0, 0x9f, 0xcb, 0xb3, 0x0a, 0x16, 0xcd, 0xb8, 0xcf, 0x63, 0xc1, 0xdd, 0xec, 0xfe, - 0xe6, 0x41, 0x19, 0x9f, 0x17, 0xb8, 0xd4, 0x53, 0xf1, 0x55, 0x49, 0x3a, 0xc0, 0x06, 0xd4, 0xe3, - 0xe4, 0x22, 0x76, 0x23, 0x1e, 0xca, 0xbe, 0x50, 0x11, 0x56, 0x49, 0x0e, 0x93, 0x69, 0x8a, 0x05, - 0x15, 0xec, 0x32, 0xf1, 0x54, 0x20, 0x0d, 0xb2, 0x18, 0xe3, 0x36, 0x6c, 0x5e, 0x51, 0x7f, 0xca, - 0xfd, 0xa9, 0xfc, 0xe5, 0xd6, 0x2a, 0xa9, 0xe5, 0x90, 0x41, 0x66, 0xc8, 0xf7, 0x0c, 0xa8, 0x59, - 0xbf, 0xb6, 0xad, 0xe1, 0xb8, 0x3f, 0x1a, 0xca, 0x07, 0x6a, 0x38, 0x1a, 0x5a, 0xe9, 0x03, 0x65, - 0x92, 0xee, 0xb3, 0xfe, 0x99, 0x85, 0xb4, 0xbd, 0xbf, 0x69, 0x50, 0x5f, 0xed, 0x67, 0x5c, 0x87, - 0x6a, 0xaf, 0x3f, 0x36, 0x3b, 0x03, 0xab, 0x87, 0x36, 0x30, 0x82, 0xfa, 0x53, 0xcb, 0x76, 0x3a, - 0x83, 0x51, 0xf7, 0xc5, 0xf0, 0xf4, 0x18, 0x69, 0x78, 0x1b, 0xd0, 0x02, 0x71, 0x3a, 0xe7, 0x8e, - 0x44, 0x0b, 0xf8, 0x21, 0x3c, 0x18, 0x5b, 0xb6, 0x33, 0x30, 0x6d, 0x6b, 0x6c, 0x3b, 0xfd, 0xa1, - 0x73, 0x6c, 0xd9, 0x66, 0xcf, 0xb4, 0x4d, 0x54, 0xc4, 0x0f, 0x00, 0xe7, 0xe7, 0x3a, 0xa3, 0xde, - 0x39, 0xd2, 0xa5, 0xf6, 0x99, 0x45, 0xfa, 0x47, 0xfd, 0xae, 0x29, 0x77, 0x47, 0x25, 0xc9, 0x94, - 0xda, 0x96, 0x49, 0x06, 0x7d, 0xc9, 0x55, 0x9b, 0xa0, 0xb2, 0xf4, 0xd1, 0xf1, 0x69, 0x67, 0xdc, - 0x25, 0xfd, 0x8e, 0x85, 0x2a, 0xd2, 0x47, 0x4f, 0x87, 0x4b, 0xa0, 0x8a, 0xef, 0xc3, 0xd6, 0x0a, - 0xe0, 0x98, 0x83, 0x01, 0xaa, 0xed, 0xfd, 0x41, 0x83, 0xcd, 0x95, 0xd2, 0x4a, 0x91, 0xe1, 0xc8, - 0x49, 0x91, 0xf4, 0x64, 0xe9, 0x19, 0xd2, 0xb8, 0x90, 0x86, 0x31, 0x34, 0x53, 0x64, 0xbe, 0x3f, - 0x2a, 0x60, 0x80, 0x32, 0xb1, 0xc6, 0xa7, 0x03, 0x1b, 0x15, 0xf1, 0x3d, 0x68, 0x2c, 0xd2, 0xe9, - 0x98, 0xe4, 0x29, 0xd2, 0xa5, 0xe1, 0xf7, 0x7b, 0xd6, 0xd0, 0xee, 0x1f, 0xf5, 0x2d, 0x82, 0x4a, - 0x92, 0xd2, 0xb3, 0x8e, 0xcc, 0xd3, 0x81, 0xed, 0x9c, 0x99, 0x83, 0x53, 0x0b, 0x95, 0x25, 0x25, - 0x55, 0x7d, 0x66, 0x8e, 0x9f, 0xa1, 0xca, 0xde, 0xef, 0x96, 0x61, 0xc9, 0xbc, 0xe3, 0x1a, 0x94, - 0xac, 0xe3, 0x13, 0xfb, 0x3c, 0x0d, 0x49, 0xcd, 0xc8, 0xb4, 0x4a, 0x7d, 0x4d, 0x1e, 0x2c, 0x45, - 0xba, 0xe6, 0x70, 0x34, 0xec, 0x77, 0xcd, 0x01, 0x2a, 0xc8, 0x0a, 0xa4, 0x60, 0xaf, 0xaf, 0xca, - 0x66, 0x92, 0x73, 0x54, 0xc4, 0x6d, 0xf8, 0xde, 0xbb, 0xa8, 0x33, 0x22, 0xce, 0x88, 0xf4, 0x2c, - 0x62, 0xf5, 0x90, 0x2e, 0xcb, 0x9e, 0xc5, 0x86, 0xca, 0x1d, 0xeb, 0x4f, 0xaf, 0x76, 0xb4, 0x6f, - 0x5e, 0xed, 0x68, 0xdf, 0xbe, 0xda, 0xd1, 0xfe, 0xf1, 0x6a, 0x47, 0xfb, 0xfd, 0xeb, 0x9d, 0x8d, - 0x6f, 0x5f, 0xef, 0x6c, 0xfc, 0xfd, 0xf5, 0xce, 0xc6, 0x6f, 0xbe, 0x98, 0x72, 0x71, 0x95, 0x5c, - 0xec, 0xbb, 0xc1, 0xec, 0x20, 0xf7, 0x97, 0xea, 0xfa, 0xc9, 0xc1, 0xcb, 0xf4, 0x7f, 0x95, 0xbc, - 0x53, 0xf1, 0x45, 0x59, 0xfd, 0x4d, 0x7a, 0xf2, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xfb, 0x22, - 0x4b, 0xc8, 0x79, 0x0d, 0x00, 0x00, + 0x9f, 0xfb, 0x0f, 0xf4, 0x50, 0xa0, 0xff, 0x42, 0x81, 0x05, 0x0a, 0xf4, 0xbf, 0xd8, 0xe3, 0xde, + 0xda, 0x93, 0x51, 0x24, 0x87, 0x02, 0x39, 0xe6, 0x52, 0xf4, 0x50, 0xa0, 0x98, 0x21, 0xf5, 0x83, + 0x89, 0xe2, 0x62, 0xf7, 0x24, 0xcd, 0xf7, 0xbe, 0xf9, 0xe6, 0xcd, 0x7b, 0x33, 0xdf, 0x48, 0xf0, + 0x63, 0x8f, 0x5e, 0x53, 0x9f, 0x89, 0x03, 0xf9, 0x79, 0x10, 0x87, 0xcc, 0x3d, 0xa0, 0x21, 0x77, + 0xdc, 0xc0, 0xf3, 0x98, 0x2b, 0x78, 0xe0, 0xef, 0x87, 0x51, 0x20, 0x02, 0x7c, 0x2f, 0xe3, 0xed, + 0xcb, 0xcf, 0x7d, 0xc9, 0x7b, 0xb8, 0x3d, 0x0d, 0xa6, 0x81, 0x8a, 0x1e, 0xc8, 0x6f, 0x29, 0xd1, + 0xf8, 0x6f, 0x11, 0x1a, 0x66, 0xc8, 0xbb, 0x0b, 0x01, 0xdc, 0x82, 0x0a, 0xf3, 0xe9, 0x85, 0xc7, + 0x26, 0x2d, 0x6d, 0x57, 0x7b, 0x5c, 0x25, 0xf3, 0x21, 0x3e, 0x81, 0xad, 0xe5, 0x42, 0xce, 0x84, + 0x0a, 0xda, 0x2a, 0xec, 0x6a, 0x8f, 0x37, 0x0f, 0x7f, 0xb8, 0xff, 0xde, 0x72, 0xfb, 0x4b, 0xc5, + 0x1e, 0x15, 0xb4, 0xa3, 0x7f, 0x7d, 0xdb, 0xde, 0x20, 0x4d, 0x37, 0x87, 0xe2, 0x3d, 0xd0, 0x69, + 0xc8, 0xe3, 0x56, 0x71, 0xb7, 0xf8, 0x78, 0xf3, 0xf0, 0xc1, 0x1a, 0x19, 0x33, 0xe4, 0x44, 0x71, + 0xf0, 0x13, 0xa8, 0x5c, 0x31, 0x3a, 0x61, 0x51, 0xdc, 0xd2, 0x15, 0xfd, 0xa3, 0x35, 0xf4, 0x67, + 0x8a, 0x41, 0xe6, 0x4c, 0x3c, 0x00, 0xc4, 0xfd, 0x2b, 0x16, 0x71, 0x41, 0x7d, 0x97, 0x39, 0x6a, + 0xb1, 0x92, 0x9a, 0xfd, 0xff, 0x73, 0x26, 0x5b, 0x2b, 0x53, 0x4d, 0x99, 0xc2, 0x00, 0x50, 0x48, + 0xa3, 0x98, 0x39, 0x13, 0x1e, 0x49, 0xde, 0x35, 0x8b, 0x5b, 0xe5, 0x0f, 0xaa, 0x9d, 0x48, 0x6a, + 0x6f, 0xce, 0x24, 0x5b, 0x61, 0x6e, 0x1c, 0xe3, 0x5f, 0x00, 0xb0, 0x97, 0x82, 0xf9, 0x31, 0x0f, + 0xfc, 0xb8, 0x55, 0x51, 0x3a, 0x8f, 0xd6, 0xe8, 0x58, 0x73, 0x12, 0x59, 0xe1, 0x63, 0x0b, 0x1a, + 0xd7, 0x2c, 0xe2, 0x97, 0xdc, 0xa5, 0x42, 0x09, 0x54, 0x95, 0x40, 0x7b, 0x8d, 0xc0, 0xd9, 0x0a, + 0x8f, 0xe4, 0x67, 0x19, 0xbf, 0x87, 0xda, 0x42, 0x1f, 0x63, 0xd0, 0x7d, 0x3a, 0x63, 0xaa, 0xef, + 0x35, 0xa2, 0xbe, 0xe3, 0xcf, 0x41, 0x8f, 0x12, 0x8f, 0xb5, 0x8a, 0xaa, 0xd3, 0xdf, 0x5f, 0x23, + 0x4f, 0x12, 0x8f, 0x11, 0x45, 0xc2, 0x9f, 0x40, 0xc3, 0x4d, 0x9c, 0x59, 0xe2, 0x09, 0x1e, 0x7a, + 0x9c, 0x45, 0x2d, 0x7d, 0x57, 0x7b, 0xac, 0x93, 0xba, 0x9b, 0x1c, 0x2f, 0xb0, 0xe7, 0x7a, 0xb5, + 0x80, 0x8a, 0xc6, 0x23, 0xd0, 0xe5, 0x44, 0xbc, 0x0d, 0xa5, 0x0b, 0x2f, 0x70, 0xbf, 0x54, 0x8b, + 0xea, 0x24, 0x1d, 0x18, 0x5f, 0x69, 0x50, 0x5f, 0x4d, 0x7b, 0x6d, 0x6a, 0xcf, 0x61, 0xeb, 0x9d, + 0x76, 0xdc, 0x71, 0x1e, 0xdf, 0xe9, 0x46, 0x33, 0xdf, 0x0d, 0xfc, 0x33, 0x28, 0x5f, 0x53, 0x2f, + 0x61, 0xf3, 0xb3, 0xf8, 0xf1, 0x87, 0x24, 0xce, 0x24, 0x8b, 0x64, 0xe4, 0xe7, 0x7a, 0x55, 0x47, + 0x25, 0xe3, 0x3f, 0x1a, 0xc0, 0x32, 0x88, 0x1f, 0x41, 0x6d, 0xd1, 0xa8, 0x2c, 0xe1, 0x25, 0x80, + 0x7f, 0x04, 0x4d, 0xf6, 0x32, 0x64, 0xae, 0x60, 0x13, 0x47, 0xa9, 0xa8, 0xa4, 0x6b, 0xa4, 0x31, + 0x47, 0x53, 0x91, 0xcf, 0x60, 0xcb, 0xa3, 0x82, 0xc5, 0xc2, 0x99, 0xf0, 0x58, 0x1d, 0x41, 0xd5, + 0x02, 0x9d, 0x34, 0x53, 0xb8, 0x97, 0xa1, 0x78, 0x08, 0xd5, 0x98, 0xc9, 0xa6, 0x8a, 0x1b, 0x55, + 0xee, 0xe6, 0xe1, 0xe1, 0x9d, 0xb9, 0xe7, 0x8e, 0xc3, 0x38, 0x9b, 0x49, 0x16, 0x1a, 0xc6, 0x4f, + 0x60, 0x7b, 0x1d, 0x03, 0x57, 0x41, 0x3f, 0xa2, 0xdc, 0x43, 0x1b, 0x78, 0x13, 0x2a, 0xbf, 0xa1, + 0x91, 0xcf, 0xfd, 0x29, 0xd2, 0x8c, 0xbf, 0x15, 0xa0, 0x99, 0xbf, 0x37, 0xf8, 0x0c, 0x1a, 0xd2, + 0x94, 0xb8, 0x2f, 0x58, 0x74, 0x49, 0xdd, 0xac, 0x69, 0x9d, 0x9f, 0xbe, 0xb9, 0x6d, 0xe7, 0x03, + 0x6f, 0x6f, 0xdb, 0x8f, 0x66, 0x34, 0x8c, 0x45, 0x94, 0xb8, 0x22, 0x89, 0xd8, 0x17, 0x46, 0x2e, + 0x6c, 0x90, 0x3a, 0x0d, 0x79, 0x7f, 0x3e, 0x94, 0xba, 0x2a, 0xe6, 0x53, 0xcf, 0x09, 0xa9, 0xb8, + 0x4a, 0x0b, 0x97, 0xea, 0xe6, 0x02, 0xef, 0xeb, 0xe6, 0xc2, 0x06, 0xa9, 0xcf, 0xc7, 0x27, 0x54, + 0x5c, 0xe1, 0x27, 0xa0, 0x8b, 0x9b, 0x30, 0xad, 0x6f, 0xad, 0xd3, 0x7e, 0x73, 0xdb, 0x56, 0xe3, + 0xb7, 0xb7, 0xed, 0xfb, 0x79, 0x15, 0x89, 0x1a, 0x44, 0x05, 0xf1, 0x17, 0x50, 0xa6, 0x93, 0x89, + 0x13, 0xf8, 0xaa, 0xe8, 0xb5, 0xce, 0x27, 0x6f, 0x6e, 0xdb, 0x19, 0xf2, 0xf6, 0xb6, 0xfd, 0xbd, + 0x77, 0xb6, 0xa5, 0x70, 0x83, 0x94, 0xe8, 0x64, 0x32, 0xf2, 0x8d, 0x7f, 0x69, 0x50, 0x4e, 0x9d, + 0x6a, 0xed, 0xb9, 0xfe, 0x39, 0xe8, 0x5f, 0x72, 0x7f, 0xa2, 0xb6, 0xd7, 0x3c, 0xfc, 0xf4, 0x83, + 0x36, 0x97, 0x7d, 0xd8, 0x37, 0x21, 0x23, 0x6a, 0x06, 0xee, 0x40, 0xfd, 0x32, 0xf1, 0x53, 0x7f, + 0x16, 0x74, 0xaa, 0x76, 0xd4, 0x5c, 0xeb, 0x09, 0x47, 0xa7, 0xc3, 0xae, 0xdd, 0x1f, 0x0d, 0x1d, + 0xdb, 0x7c, 0x4a, 0x36, 0xe7, 0x93, 0x6c, 0x3a, 0x35, 0x5e, 0x00, 0x2c, 0x75, 0x71, 0x03, 0x6a, + 0x21, 0x8d, 0x63, 0x27, 0x66, 0xfe, 0x04, 0x6d, 0xe0, 0x26, 0x80, 0x1a, 0x46, 0x2c, 0xf4, 0x6e, + 0x90, 0xb6, 0x08, 0x5f, 0x04, 0xe2, 0x0a, 0x15, 0xf0, 0x16, 0x6c, 0xaa, 0x21, 0x9f, 0xfa, 0x41, + 0xc4, 0x50, 0xd1, 0xf8, 0x77, 0x01, 0x8a, 0x66, 0xc8, 0xef, 0x78, 0x54, 0xe6, 0x05, 0x28, 0xac, + 0x14, 0x40, 0xda, 0x48, 0x30, 0x0b, 0x13, 0xc1, 0x9c, 0xc4, 0xe7, 0x22, 0xce, 0x4e, 0x7e, 0x3d, + 0x03, 0x4f, 0x25, 0x86, 0xf7, 0xe1, 0x3e, 0x7b, 0x29, 0x22, 0xea, 0xe4, 0xa9, 0xa9, 0xe3, 0xdc, + 0x53, 0xa1, 0xee, 0x2a, 0xdf, 0x84, 0xaa, 0x4b, 0x05, 0x9b, 0x06, 0xd1, 0x4d, 0xab, 0xac, 0x6c, + 0x62, 0x5d, 0x5d, 0xc6, 0x21, 0x73, 0xbb, 0x19, 0x2d, 0x7b, 0xb4, 0x16, 0xd3, 0x70, 0x1f, 0x1a, + 0xca, 0x9e, 0x1c, 0x69, 0x1e, 0xdc, 0x9f, 0xb6, 0x2a, 0x4a, 0x67, 0x67, 0x8d, 0x4e, 0x47, 0xf2, + 0xd4, 0xa5, 0x8b, 0x32, 0x99, 0xfa, 0xc5, 0x1c, 0xe2, 0xfe, 0x14, 0x7f, 0x0c, 0x20, 0xf8, 0x8c, + 0x05, 0x89, 0x70, 0x66, 0xd2, 0xbb, 0x65, 0xd2, 0xb5, 0x0c, 0x39, 0x8e, 0xf1, 0xaf, 0xa1, 0xa2, + 0x0c, 0x2a, 0x8a, 0x5b, 0x35, 0xe5, 0x47, 0xbb, 0x6b, 0xd6, 0x78, 0xca, 0x7c, 0x16, 0x71, 0x37, + 0xb7, 0xca, 0x7c, 0x9a, 0xf1, 0x55, 0x01, 0x9a, 0x79, 0xcf, 0x7b, 0xef, 0x74, 0x68, 0xdf, 0xfe, + 0x74, 0xe0, 0xcf, 0xe1, 0xde, 0x52, 0x83, 0xcd, 0x42, 0x69, 0x46, 0x59, 0xef, 0xd0, 0x82, 0x97, + 0xe1, 0xf8, 0x05, 0x34, 0x23, 0x16, 0x27, 0x9e, 0x58, 0x14, 0xac, 0xf8, 0x2d, 0x0a, 0xd6, 0x48, + 0xe7, 0xce, 0x2b, 0xf6, 0x11, 0x54, 0xa5, 0x3b, 0xa8, 0xc3, 0xa2, 0xae, 0x1c, 0xa9, 0xd0, 0x90, + 0x0f, 0xe5, 0x79, 0x59, 0xa9, 0x56, 0xe9, 0xbb, 0x55, 0xeb, 0xaf, 0x1a, 0x6c, 0xae, 0x64, 0x20, + 0xdb, 0x93, 0x86, 0x1c, 0x1a, 0xc9, 0x42, 0x15, 0xa5, 0x87, 0xa7, 0x88, 0x19, 0x4d, 0xf1, 0xaf, + 0xe4, 0x39, 0x57, 0x61, 0xb9, 0xe7, 0xec, 0xa2, 0xae, 0xdb, 0xd5, 0x89, 0x49, 0xc6, 0x16, 0x71, + 0x64, 0x3d, 0x49, 0xa6, 0x78, 0x94, 0xf8, 0xae, 0x3c, 0xe1, 0x13, 0x76, 0x49, 0x65, 0x69, 0xd2, + 0x37, 0x40, 0x79, 0x0f, 0xa9, 0x67, 0x60, 0xfa, 0x04, 0x3c, 0x84, 0x2a, 0xf3, 0xdd, 0x60, 0x22, + 0x0b, 0x97, 0xee, 0x78, 0x31, 0x36, 0xfe, 0xac, 0x41, 0x23, 0xb7, 0xa3, 0x45, 0xca, 0xa9, 0x35, + 0x66, 0xcf, 0x8e, 0x42, 0x94, 0xc9, 0x6d, 0x43, 0x69, 0xf5, 0xb5, 0x49, 0x07, 0xf8, 0x97, 0xf3, + 0x49, 0x0b, 0x03, 0xbc, 0x73, 0x1f, 0xf6, 0xf9, 0x89, 0x95, 0x89, 0x2a, 0x77, 0xc0, 0xd9, 0x8f, + 0x83, 0x34, 0x3b, 0xf5, 0x5d, 0x3d, 0xdd, 0xab, 0xb7, 0x08, 0x7f, 0x2a, 0xf7, 0x2a, 0x58, 0x34, + 0xe3, 0x3e, 0x8f, 0x05, 0x77, 0x33, 0x07, 0xc8, 0x83, 0x32, 0x3f, 0x2f, 0x70, 0xa9, 0xa7, 0xf2, + 0xab, 0x92, 0x74, 0x80, 0x0d, 0xa8, 0xc7, 0xc9, 0x45, 0xec, 0x46, 0x3c, 0x94, 0x27, 0x4b, 0x65, + 0x58, 0x25, 0x39, 0x4c, 0x96, 0x29, 0x16, 0x54, 0xb0, 0xcb, 0xc4, 0x53, 0x89, 0x34, 0xc8, 0x62, + 0x8c, 0xdb, 0xb0, 0x79, 0x45, 0xfd, 0x29, 0xf7, 0xa7, 0xf2, 0xb7, 0x5f, 0xab, 0xa4, 0xa6, 0x43, + 0x06, 0x99, 0x21, 0xdf, 0x33, 0xa0, 0x66, 0xfd, 0xd6, 0xb6, 0x86, 0xe3, 0xfe, 0x68, 0x28, 0x9f, + 0xb8, 0xe1, 0x68, 0x68, 0xa5, 0x4f, 0x9c, 0x49, 0xba, 0xcf, 0xfa, 0x67, 0x16, 0xd2, 0xf6, 0xfe, + 0xae, 0x41, 0x7d, 0xf5, 0x46, 0xe0, 0x3a, 0x54, 0x7b, 0xfd, 0xb1, 0xd9, 0x19, 0x58, 0x3d, 0xb4, + 0x81, 0x11, 0xd4, 0x9f, 0x5a, 0xb6, 0xd3, 0x19, 0x8c, 0xba, 0x2f, 0x86, 0xa7, 0xc7, 0x48, 0xc3, + 0xdb, 0x80, 0x16, 0x88, 0xd3, 0x39, 0x77, 0x24, 0x5a, 0xc0, 0x0f, 0xe1, 0xc1, 0xd8, 0xb2, 0x9d, + 0x81, 0x69, 0x5b, 0x63, 0xdb, 0xe9, 0x0f, 0x9d, 0x63, 0xcb, 0x36, 0x7b, 0xa6, 0x6d, 0xa2, 0x22, + 0x7e, 0x00, 0x38, 0x1f, 0xeb, 0x8c, 0x7a, 0xe7, 0x48, 0x97, 0xda, 0x67, 0x16, 0xe9, 0x1f, 0xf5, + 0xbb, 0xa6, 0x5c, 0x1d, 0x95, 0x24, 0x53, 0x6a, 0x5b, 0x26, 0x19, 0xf4, 0x25, 0x57, 0x2d, 0x82, + 0xca, 0xd2, 0x89, 0xc7, 0xa7, 0x9d, 0x71, 0x97, 0xf4, 0x3b, 0x16, 0xaa, 0x48, 0x27, 0x3e, 0x1d, + 0x2e, 0x81, 0x2a, 0xbe, 0x0f, 0x5b, 0x2b, 0x80, 0x63, 0x0e, 0x06, 0xa8, 0xb6, 0xf7, 0x27, 0x0d, + 0x36, 0x57, 0x5a, 0x2b, 0x45, 0x86, 0x23, 0x27, 0x45, 0xd2, 0x9d, 0xa5, 0x7b, 0x48, 0xf3, 0x42, + 0x1a, 0xc6, 0xd0, 0x4c, 0x91, 0xf9, 0xfa, 0xa8, 0x80, 0x01, 0xca, 0xc4, 0x1a, 0x9f, 0x0e, 0x6c, + 0x54, 0xc4, 0xf7, 0xa0, 0xb1, 0x28, 0xa7, 0x63, 0x92, 0xa7, 0x48, 0x97, 0x4f, 0x46, 0xbf, 0x67, + 0x0d, 0xed, 0xfe, 0x51, 0xdf, 0x22, 0xa8, 0x24, 0x29, 0x3d, 0xeb, 0xc8, 0x3c, 0x1d, 0xd8, 0xce, + 0x99, 0x39, 0x38, 0xb5, 0x50, 0x59, 0x52, 0x52, 0xd5, 0x67, 0xe6, 0xf8, 0x19, 0xaa, 0xec, 0xfd, + 0x61, 0x99, 0x96, 0xac, 0x3b, 0xae, 0x41, 0xc9, 0x3a, 0x3e, 0xb1, 0xcf, 0xd3, 0x94, 0x54, 0x44, + 0x96, 0x55, 0xea, 0x6b, 0x72, 0x63, 0x29, 0xd2, 0x35, 0x87, 0xa3, 0x61, 0xbf, 0x6b, 0x0e, 0x50, + 0x41, 0x76, 0x20, 0x05, 0x7b, 0x7d, 0xd5, 0x36, 0x93, 0x9c, 0xa3, 0x22, 0x6e, 0xc3, 0x0f, 0xde, + 0x45, 0x9d, 0x11, 0x71, 0x46, 0xa4, 0x67, 0x11, 0xab, 0x87, 0x74, 0xd9, 0xf6, 0x2c, 0x37, 0x54, + 0xee, 0x58, 0x7f, 0x79, 0xb5, 0xa3, 0x7d, 0xfd, 0x6a, 0x47, 0xfb, 0xe6, 0xd5, 0x8e, 0xf6, 0xcf, + 0x57, 0x3b, 0xda, 0x1f, 0x5f, 0xef, 0x6c, 0x7c, 0xf3, 0x7a, 0x67, 0xe3, 0x1f, 0xaf, 0x77, 0x36, + 0x7e, 0xf7, 0xd9, 0x94, 0x8b, 0xab, 0xe4, 0x62, 0xdf, 0x0d, 0x66, 0x07, 0xb9, 0x3f, 0x65, 0xd7, + 0x4f, 0x0e, 0x5e, 0xa6, 0xff, 0xcc, 0xe4, 0x9d, 0x8a, 0x2f, 0xca, 0xea, 0x8f, 0xd6, 0x93, 0xff, + 0x05, 0x00, 0x00, 0xff, 0xff, 0xe6, 0xb2, 0x04, 0x99, 0xbb, 0x0d, 0x00, 0x00, } func (this *ApiCollection) Equal(that interface{}) bool { @@ -1545,6 +1553,14 @@ func (this *ParseDirective) Equal(that interface{}) bool { if this.ApiName != that1.ApiName { return false } + if len(this.Parsers) != len(that1.Parsers) { + return false + } + for i := range this.Parsers { + if !this.Parsers[i].Equal(&that1.Parsers[i]) { + return false + } + } return true } func (this *BlockParser) Equal(that interface{}) bool { @@ -2159,6 +2175,20 @@ func (m *ParseDirective) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.Parsers) > 0 { + for iNdEx := len(m.Parsers) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Parsers[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintApiCollection(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + } if len(m.ApiName) > 0 { i -= len(m.ApiName) copy(dAtA[i:], m.ApiName) @@ -2596,6 +2626,12 @@ func (m *ParseDirective) Size() (n int) { if l > 0 { n += 1 + l + sovApiCollection(uint64(l)) } + if len(m.Parsers) > 0 { + for _, e := range m.Parsers { + l = e.Size() + n += 1 + l + sovApiCollection(uint64(l)) + } + } return n } @@ -4198,6 +4234,40 @@ func (m *ParseDirective) Unmarshal(dAtA []byte) error { } m.ApiName = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Parsers", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApiCollection + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthApiCollection + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthApiCollection + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Parsers = append(m.Parsers, GenericParser{}) + if err := m.Parsers[len(m.Parsers)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApiCollection(dAtA[iNdEx:]) diff --git a/x/subscription/keeper/cu_tracker.go b/x/subscription/keeper/cu_tracker.go index a742913b99..6426cffc5b 100644 --- a/x/subscription/keeper/cu_tracker.go +++ b/x/subscription/keeper/cu_tracker.go @@ -195,7 +195,7 @@ func (k Keeper) RewardAndResetCuTracker(ctx sdk.Context, cuTrackerTimerKeyBytes // Note: if the reward function doesn't reward the provider // because he was unstaked, we only print an error and not returning - _, _, err := k.dualstakingKeeper.RewardProvidersAndDelegators(ctx, provider, chainID, sdk.NewCoins(creditToSub), types.ModuleName, false, false, false) + _, err := k.dualstakingKeeper.RewardProvidersAndDelegators(ctx, provider, chainID, sdk.NewCoins(creditToSub), types.ModuleName, false, false, false) if errors.Is(err, epochstoragetypes.ErrProviderNotStaked) || errors.Is(err, epochstoragetypes.ErrStakeStorageNotFound) { utils.LavaFormatWarning("sending provider reward with delegations failed", err, utils.Attribute{Key: "provider", Value: provider}, diff --git a/x/subscription/types/expected_keepers.go b/x/subscription/types/expected_keepers.go index 264fe6f6d1..f459e5e1bc 100644 --- a/x/subscription/types/expected_keepers.go +++ b/x/subscription/types/expected_keepers.go @@ -68,7 +68,7 @@ type TimerStoreKeeper interface { } type DualStakingKeeper interface { - RewardProvidersAndDelegators(ctx sdk.Context, providerAddr string, chainID string, totalReward sdk.Coins, senderModule string, calcOnlyProvider bool, calcOnlyDelegators bool, calcOnlyContributor bool) (providerReward sdk.Coins, totalRewards sdk.Coins, err error) + RewardProvidersAndDelegators(ctx sdk.Context, providerAddr string, chainID string, totalReward sdk.Coins, senderModule string, calcOnlyProvider bool, calcOnlyDelegators bool, calcOnlyContributor bool) (providerReward sdk.Coins, err error) GetDelegation(ctx sdk.Context, delegator, provider, chainID string, epoch uint64) (dualstakingtypes.Delegation, bool) }