diff --git a/.github/workflows/build_push_ghcr.yaml b/.github/workflows/build_push_ghcr.yaml deleted file mode 100644 index 53d7868..0000000 --- a/.github/workflows/build_push_ghcr.yaml +++ /dev/null @@ -1,29 +0,0 @@ -name: Build and Release Docker Images on GHCR - -on: - release: - types: [created] - workflow_dispatch: - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/setup-go@v3 - with: - go-version: "1.21.0" - check-latest: true - - uses: actions/checkout@v2 - - name: Prepare Release Variables - id: vars - uses: ignite/cli/actions/release/vars@main - - name: build head - run: | - echo "${{ secrets.GHCR_TOKEN }}" | docker login ghcr.io -u "${{ secrets.GHCR_USER }}" --password-stdin - docker build . --tag ghcr.io/${{ github.repository }}_head:${{ steps.vars.outputs.tag_name }} --build-arg "GH_TOKEN=${{ secrets.GHCR_TOKEN }}" --build-arg="BLS_EXTENSION_VER=dev.3" -f docker/Dockerfile_head - docker push ghcr.io/${{ github.repository }}_head:${{ steps.vars.outputs.tag_name }} - - name: build worker - run: | - echo "${{ secrets.GHCR_TOKEN }}" | docker login ghcr.io -u "${{ secrets.GHCR_USER }}" --password-stdin - docker build . --tag ghcr.io/${{ github.repository }}_worker:${{ steps.vars.outputs.tag_name }} --build-arg "GH_TOKEN=${{ secrets.GHCR_TOKEN }}" --build-arg="BLS_EXTENSION_VER=dev.3" -f docker/Dockerfile_worker - docker push ghcr.io/${{ github.repository }}_worker:${{ steps.vars.outputs.tag_name }} diff --git a/README.md b/README.md index 266b73d..a6ea272 100644 --- a/README.md +++ b/README.md @@ -15,14 +15,6 @@ In order to build locally: GOOS=linux GOARCH=amd64 make ``` -***WARNING*** - -This repo is currently relying on a private module, current development requires - -```bash -export GOPRIVATE=github.com/allora-network/allora-appchain -``` - # Run locally ## Head @@ -44,6 +36,8 @@ export GOPRIVATE=github.com/allora-network/allora-appchain ``` ## Worker +Worker (for inference or forecast requests) node: + ``` ./allora-node \ --role=worker \ @@ -60,12 +54,35 @@ export GOPRIVATE=github.com/allora-network/allora-appchain --allora-chain-key-name=local-worker \ --allora-chain-restore-mnemonic='your mnemonic words...' --allora-node-rpc-address=https://some-allora-rpc-address/ \ --allora-chain-topic-id=1 \ - --allora-chain-initial-stake=1000 + --allora-chain-initial-stake=1000 \ + --allora-chain-worker-mode=worker +``` + +Reputer (for reputation requests) node: + +``` +./allora-node \ + --role=worker \ + --peer-db=/data/peerdb \ + --function-db=/data/function-db \ + --runtime-path=/app/runtime \ + --runtime-cli=bls-runtime \ + --workspace=/data/workspace \ + --private-key=/var/keys/priv.bin \ + --port=9011 \ + --rest-api=:6000 \ + --boot-nodes=/ip4//tcp/9010/p2p/ + --topic=1 \ + --allora-chain-key-name=local-worker \ + --allora-chain-restore-mnemonic='your mnemonic words...' --allora-node-rpc-address=https://some-allora-rpc-address/ \ + --allora-chain-topic-id=1 \ + --allora-chain-initial-stake=1000 \ + --allora-chain-worker-mode=reputer ``` ## Notes -If you plan to deploy without wanting to connect to the Allora blockchain, just by testing your setup and your inferences, do not set any `--allora-...` flag. +If you plan to deploy temporarily without attempting to connect to the Allora blockchain, e.g. just for testing your setup and your inferences and forecasts, do not set any `--allora-...` flag. ### Topic registration @@ -94,13 +111,13 @@ Blockless nodes need to define a number of directories: To build the image for the head: ``` -docker build -f docker/Dockerfile_head -t allora-inference-base:dev-head --build-arg "GH_TOKEN=${YOUR_GH_TOKEN}" --build-arg "BLS_EXTENSION_VER=${BLS_EXTENSION_VERSION}" . +docker build --pull -f docker/Dockerfile_head -t allora-inference-base:dev-head --build-arg "GH_TOKEN=${YOUR_GH_TOKEN}" --build-arg "BLS_EXTENSION_VER=${BLS_EXTENSION_VERSION}" . ``` -Then to build the image for the head: +To build the image for the worker: ``` -docker build -f docker/Dockerfile_worker -t allora-inference-base:dev-worker --build-arg "GH_TOKEN=${YOUR_GH_TOKEN}" --build-arg "BLS_EXTENSION_VER=${BLS_EXTENSION_VERSION}" . +docker build --pull -f docker/Dockerfile_worker -t allora-inference-base:dev-worker --build-arg "GH_TOKEN=${YOUR_GH_TOKEN}" --build-arg "BLS_EXTENSION_VER=${BLS_EXTENSION_VERSION}" . ``` where `YOUR_GH_TOKEN` is your Github token, and optionally `BLS_EXTENSION_VER` is the release version of the [Allora inference extension](https://github.com/allora-network/allora-inference-extension) to use (it will use latest if none is set). diff --git a/cmd/node/appchain.go b/cmd/node/appchain.go index 0da8030..952d0ee 100644 --- a/cmd/node/appchain.go +++ b/cmd/node/appchain.go @@ -5,26 +5,39 @@ import ( "encoding/json" "errors" "fmt" - "math" "math/rand" "os" "path/filepath" - "slices" "strconv" + "strings" "time" cosmossdk_io_math "cosmossdk.io/math" - types "github.com/allora-network/allora-chain/x/emissions" - "github.com/blocklessnetwork/b7s/models/blockless" - "github.com/blocklessnetwork/b7s/node/aggregate" + "github.com/allora-network/allora-chain/x/emissions/types" + "github.com/allora-network/b7s/models/blockless" + "github.com/allora-network/b7s/node/aggregate" sdktypes "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/query" "github.com/ignite/cli/v28/ignite/pkg/cosmosaccount" "github.com/ignite/cli/v28/ignite/pkg/cosmosclient" "github.com/rs/zerolog" "github.com/rs/zerolog/log" ) +// Exponential backoff retry settings +const NUM_WORKER_RETRIES = 5 +const NUM_REPUTER_RETRIES = 5 +const NUM_REGISTRATION_RETRIES = 3 +const NUM_STAKING_RETRIES = 3 +const NUM_WORKER_RETRY_MIN_DELAY = 0 +const NUM_WORKER_RETRY_MAX_DELAY = 2 +const NUM_REPUTER_RETRY_MIN_DELAY = 0 +const NUM_REPUTER_RETRY_MAX_DELAY = 2 +const NUM_REGISTRATION_RETRY_MIN_DELAY = 1 +const NUM_REGISTRATION_RETRY_MAX_DELAY = 2 +const NUM_STAKING_RETRY_MIN_DELAY = 1 +const NUM_STAKING_RETRY_MAX_DELAY = 2 +const REPUTER_TOPIC_SUFFIX = "/reputer" + func getAlloraClient(config AppChainConfig) (*cosmosclient.Client, error) { // create a allora client instance ctx := context.Background() @@ -46,7 +59,13 @@ func getAlloraClient(config AppChainConfig) (*cosmosclient.Client, error) { log.Info().Err(err).Str("directory", alloraClientHome).Msg("allora client home directory created") } - client, err := cosmosclient.New(ctx, cosmosclient.WithNodeAddress(config.NodeRPCAddress), cosmosclient.WithAddressPrefix(config.AddressPrefix), cosmosclient.WithHome(alloraClientHome)) + client, err := cosmosclient.New(ctx, + cosmosclient.WithNodeAddress(config.NodeRPCAddress), + cosmosclient.WithAddressPrefix(config.AddressPrefix), + cosmosclient.WithHome(alloraClientHome), + cosmosclient.WithGas(config.Gas), + cosmosclient.WithGasAdjustment(config.GasAdjustment), + ) if err != nil { log.Warn().Err(err).Msg("unable to create an allora blockchain client") config.SubmitTx = false @@ -63,7 +82,6 @@ func NewAppChain(config AppChainConfig, log zerolog.Logger) (*AppChain, error) { config.SubmitTx = false return nil, err } - var account cosmosaccount.Account // if we're giving a keyring ring name, with no mnemonic restore if config.AddressRestoreMnemonic == "" && config.AddressKeyName != "" { @@ -74,7 +92,7 @@ func NewAppChain(config AppChainConfig, log zerolog.Logger) (*AppChain, error) { log.Warn().Err(err).Msg("could not retrieve account from keyring") } } else if config.AddressRestoreMnemonic != "" && config.AddressKeyName != "" { - // restore from mneumonic + // restore from mnemonic account, err = client.AccountRegistry.Import(config.AddressKeyName, config.AddressRestoreMnemonic, config.AddressAccountPassphrase) if err != nil { if err.Error() == "account already exists" { @@ -95,6 +113,8 @@ func NewAppChain(config AppChainConfig, log zerolog.Logger) (*AppChain, error) { if err != nil { config.SubmitTx = false log.Warn().Err(err).Msg("could not retrieve allora blockchain address, transactions will not be submitted to chain") + } else { + log.Info().Str("address", address).Msg("allora blockchain address loaded") } // Create query client @@ -106,205 +126,154 @@ func NewAppChain(config AppChainConfig, log zerolog.Logger) (*AppChain, error) { } appchain := &AppChain{ - ReputerAddress: address, - ReputerAccount: account, - Logger: log, - Client: client, - QueryClient: queryClient, - Config: config, + Address: address, + Account: account, + Logger: log, + Client: client, + QueryClient: queryClient, + Config: config, } - registerWithBlockchain(appchain) - + if config.NodeRole == blockless.WorkerNode { + registerWithBlockchain(appchain) + } else { + appchain.Logger.Info().Msg("Node is not a worker, not registering with blockchain") + } return appchain, nil } +// Function that receives an array of topicId as string, and parses them to uint64 extracting +// the topicId from the string prior to the "/" character. +func parseTopicIds(appchain *AppChain, topicIds []string) []uint64 { + var b7sTopicIds []uint64 + for _, topicId := range topicIds { + topicUint64, err := strconv.ParseUint(topicId, 10, 64) + if err != nil { + appchain.Logger.Warn().Err(err).Str("topic", topicId).Msg("Could not register for topic, not numerical") + continue + } + b7sTopicIds = append(b7sTopicIds, topicUint64) + } + return b7sTopicIds +} + +func isReputerRegistered(appchain *AppChain, topicId uint64) (bool, error) { + ctx := context.Background() + + res, err := appchain.QueryClient.IsReputerRegisteredInTopicId(ctx, &types.QueryIsReputerRegisteredInTopicIdRequest{ + TopicId: topicId, + Address: appchain.Address, + }) + + if err != nil { + return false, err + } + + return res.IsRegistered, nil +} + +func isWorkerRegistered(appchain *AppChain, topicId uint64) (bool, error) { + ctx := context.Background() + + res, err := appchain.QueryClient.IsWorkerRegisteredInTopicId(ctx, &types.QueryIsWorkerRegisteredInTopicIdRequest{ + TopicId: topicId, + Address: appchain.Address, + }) + + if err != nil { + return false, err + } + + return res.IsRegistered, nil +} + // / Registration func registerWithBlockchain(appchain *AppChain) { ctx := context.Background() - isReputer := false - if appchain.Config.NodeRole == blockless.HeadNode { + var isReputer bool + if appchain.Config.WorkerMode == WorkerModeReputer { isReputer = true + } else if appchain.Config.WorkerMode == WorkerModeWorker { + isReputer = false + } else { + appchain.Logger.Fatal().Str("WorkerMode", appchain.Config.WorkerMode).Msg("Invalid Worker Mode") } appchain.Logger.Info().Bool("isReputer", isReputer).Msg("Node mode") - // Check if address is already registered in a topic - res, err := appchain.QueryClient.GetRegisteredTopicIds(ctx, &types.QueryRegisteredTopicIdsRequest{ - Address: appchain.ReputerAddress, - IsReputer: isReputer, - }) - if err != nil { - appchain.Logger.Fatal().Err(err).Msg("could not check if the node is already registered. Topic not created?") - } - var msg sdktypes.Msg - appchain.Logger.Info().Str("ReputerAddress", appchain.ReputerAddress).Msg("Current Address") - if len(res.TopicIds) > 0 { - appchain.Logger.Debug().Msg("Worker already registered for some topics, checking...") - var topicsToRegister []uint64 - var topicsToDeRegister []uint64 - // Calculate topics to deregister - for _, topicUint64 := range res.TopicIds { - topicIdStr := strconv.FormatUint(uint64(topicUint64), 10) - if !slices.Contains(appchain.Config.TopicIds, topicIdStr) { - appchain.Logger.Info().Str("topic", topicIdStr).Msg("marking deregistration for topic") - topicsToDeRegister = append(topicsToDeRegister, topicUint64) - } else { - appchain.Logger.Info().Str("topic", topicIdStr).Msg("Not deregistering topic") - } + // Parse topics into b7sTopicIds as numerical ids. Reputers and worker use different schema. + b7sTopicIds := parseTopicIds(appchain, appchain.Config.TopicIds) + // Print the array entries as a comma-separated value list + topicsList := strings.Join(strings.Fields(fmt.Sprint(b7sTopicIds)), ", ") + appchain.Logger.Info().Str("topicsList", topicsList).Msg("Topics list") + + // Iterate each topic + for _, topicId := range b7sTopicIds { + var is_registered bool + var err error + if isReputer { + is_registered, err = isReputerRegistered(appchain, topicId) + } else { + is_registered, err = isWorkerRegistered(appchain, topicId) } - // Calculate topics to register - for _, topicIdStr := range appchain.Config.TopicIds { - topicUint64, err := strconv.ParseUint(topicIdStr, 10, 64) - if err != nil { - appchain.Logger.Info().Err(err).Uint64("topic", topicUint64).Msg("Could not register for topic, not numerical") - continue - } - if !slices.Contains(res.TopicIds, topicUint64) { - appchain.Logger.Info().Uint64("topic", topicUint64).Msg("marking registration for topic") - topicsToRegister = append(topicsToRegister, topicUint64) - } else { - appchain.Logger.Info().Str("topic", topicIdStr).Msg("Topic is already registered, no registration for topic") - } + if err != nil { + appchain.Logger.Error().Err(err).Uint64("topicId", topicId).Msg("could not check if the node is already registered for topic, skipping.") + continue } - // Registration on new topics - for _, topicId := range topicsToRegister { - if err != nil { - appchain.Logger.Info().Err(err).Uint64("topic", topicId).Msg("Could not register for topic") - break - } - msg = &types.MsgAddNewRegistration{ - Creator: appchain.ReputerAddress, + if !is_registered { + // register the wroker in the topic + msg := &types.MsgRegister{ + Sender: appchain.Address, LibP2PKey: appchain.Config.LibP2PKey, MultiAddress: appchain.Config.MultiAddress, TopicId: topicId, - Owner: appchain.ReputerAddress, + Owner: appchain.Address, IsReputer: isReputer, } - - txResp, err := appchain.Client.BroadcastTx(ctx, appchain.ReputerAccount, msg) + res, err := appchain.SendDataWithRetry(ctx, msg, NUM_REGISTRATION_RETRIES, + NUM_REGISTRATION_RETRY_MIN_DELAY, NUM_REGISTRATION_RETRY_MAX_DELAY, "register node") if err != nil { - appchain.Logger.Fatal().Err(err).Uint64("topic", topicId).Msg("could not register the node with the Allora blockchain in topic") + appchain.Logger.Fatal().Err(err).Uint64("topic", topicId).Str("txHash", res.TxHash). + Msg("could not register the node with the Allora blockchain in topic") } else { - appchain.Logger.Info().Str("txhash", txResp.TxHash).Uint64("topic", topicId).Msg("successfully registered node with Allora blockchain in topic") - } - } - // Deregistration on old topics - for _, topicId := range topicsToDeRegister { - if err != nil { - appchain.Logger.Info().Err(err).Uint64("topic", topicId).Msg("Could not register for topic") - break - } - msg = &types.MsgRemoveRegistration{ - Creator: appchain.ReputerAddress, - TopicId: topicId, - IsReputer: isReputer, - } - - txResp, err := appchain.Client.BroadcastTx(ctx, appchain.ReputerAccount, msg) - if err != nil { - appchain.Logger.Fatal().Err(err).Uint64("topic", topicId).Msg("could not deregister the node with the Allora blockchain in topic") - } else { - appchain.Logger.Info().Str("txhash", txResp.TxHash).Uint64("topic", topicId).Msg("successfully deregistered node with Allora blockchain in topic") - } - } - } else { - appchain.Logger.Debug().Msg("Attempting first registration for this node") - // First registration: Check current balance of the account - pageRequest := &query.PageRequest{ - Limit: 100, - Offset: 0, - } - // Check balance is over initial stake configured - balanceRes, err := appchain.Client.BankBalances(ctx, appchain.ReputerAddress, pageRequest) - if err != nil { - appchain.Logger.Error().Err(err).Msg("could not get account balance - is account funded?") - return - } else { - if len(balanceRes) > 0 { - // Get uallo balance - var ualloBalance uint64 - for _, coin := range balanceRes { - if coin.Denom == "uallo" { - // Found the balance in "uallo" - ualloBalance = coin.Amount.Uint64() - break - } - } - if ualloBalance >= appchain.Config.InitialStake { - var topicsToRegister []uint64 - for _, topicToRegister := range appchain.Config.TopicIds { - topicToRegisterUint64, err := strconv.ParseUint(topicToRegister, 10, 64) + if isReputer { + var initstake = appchain.Config.InitialStake + if initstake > 0 { + msg := &types.MsgAddStake{ + Sender: appchain.Address, + Amount: cosmossdk_io_math.NewInt(initstake), + TopicId: topicId, + } + res, err := appchain.SendDataWithRetry(ctx, msg, NUM_STAKING_RETRIES, + NUM_STAKING_RETRY_MIN_DELAY, NUM_STAKING_RETRY_MAX_DELAY, "add stake") if err != nil { - appchain.Logger.Info().Err(err).Str("topic", topicToRegister).Msg("Could not register for topic, not numerical, skipping") - } else { - topicsToRegister = append(topicsToRegister, topicToRegisterUint64) + appchain.Logger.Error().Err(err).Uint64("topic", topicId).Str("txHash", res.TxHash). + Msg("could not stake the node with the Allora blockchain in specified topic") } - } - // If not registered in any topic, need an initial stake - msg = &types.MsgRegister{ - Creator: appchain.ReputerAddress, - LibP2PKey: appchain.Config.LibP2PKey, - MultiAddress: appchain.Config.MultiAddress, - InitialStake: cosmossdk_io_math.NewUint(appchain.Config.InitialStake), - TopicIds: topicsToRegister, - Owner: appchain.ReputerAddress, - IsReputer: isReputer, - } - txResp, err := appchain.Client.BroadcastTx(ctx, appchain.ReputerAccount, msg) - if err != nil { - appchain.Logger.Fatal().Err(err).Msg("could not register the node with the Allora blockchain in specified topics") } else { - appchain.Logger.Info().Str("txhash", txResp.TxHash).Msg("successfully registered node with Allora blockchain") + appchain.Logger.Info().Msg("No initial stake configured") } - appchain.Logger.Info().Str("balance", balanceRes.String()).Msg("Registered Node") - } else { - appchain.Logger.Fatal().Msg("account balance is lower than the initialStake requested") } - } else { - appchain.Logger.Info().Str("account", appchain.ReputerAddress).Msg("account is not funded in uallo") - return } + } else { + appchain.Logger.Info().Uint64("topic", topicId).Msg("node already registered for topic") } } } // Retry function with a constant number of retries. -func (ap *AppChain) SendInferencesWithRetry(ctx context.Context, req *types.MsgProcessInferences, MaxRetries, MinDelay, MaxDelay int) (*cosmosclient.Response, error) { - var txResp *cosmosclient.Response - var err error - - for retryCount := 0; retryCount <= MaxRetries; retryCount++ { - txResp, err := ap.Client.BroadcastTx(ctx, ap.ReputerAccount, req) - if err == nil { - ap.Logger.Info().Str("Tx Hash:", txResp.TxHash).Msg("successfully sent inferences to allora blockchain") - break - } - // Log the error for each retry. - ap.Logger.Info().Err(err).Msgf("Failed to send inferences to allora blockchain, retrying... (Retry %d/%d)", retryCount, MaxRetries) - // Generate a random number between MinDelay and MaxDelay - randomDelay := rand.Intn(MaxDelay-MinDelay+1) + MinDelay - // Apply exponential backoff to the random delay - backoffDelay := randomDelay << retryCount - // Wait for the calculated delay before retrying - time.Sleep(time.Duration(backoffDelay) * time.Second) - } - return txResp, err -} - -// Retry function with a constant number of retries. -func (ap *AppChain) SendWeightsWithRetry(ctx context.Context, req *types.MsgSetWeights, MaxRetries, MinDelay, MaxDelay int) (*cosmosclient.Response, error) { +func (ap *AppChain) SendDataWithRetry(ctx context.Context, req sdktypes.Msg, MaxRetries, MinDelay, MaxDelay int, SuccessMsg string) (*cosmosclient.Response, error) { var txResp *cosmosclient.Response var err error - for retryCount := 0; retryCount <= MaxRetries; retryCount++ { - txResp, err := ap.Client.BroadcastTx(ctx, ap.ReputerAccount, req) + txResponse, err := ap.Client.BroadcastTx(ctx, ap.Account, req) + txResp = &txResponse if err == nil { - ap.Logger.Info().Any("Tx Hash:", txResp.TxHash).Msg("successfully sent weights to allora blockchain") + ap.Logger.Info().Str("Tx Hash:", txResp.TxHash).Msg("Success: " + SuccessMsg) break } // Log the error for each retry. - ap.Logger.Info().Err(err).Msgf("Failed to send weights to allora blockchain, retrying... (Retry %d/%d)", retryCount, MaxRetries) + ap.Logger.Info().Err(err).Msgf("Failed: "+SuccessMsg+", retrying... (Retry %d/%d)", retryCount, MaxRetries) // Generate a random number between MinDelay and MaxDelay randomDelay := rand.Intn(MaxDelay-MinDelay+1) + MinDelay // Apply exponential backoff to the random delay @@ -315,140 +284,330 @@ func (ap *AppChain) SendWeightsWithRetry(ctx context.Context, req *types.MsgSetW return txResp, err } -// Sending Inferences to the AppChain -func (ap *AppChain) SendInferences(ctx context.Context, topicId uint64, results aggregate.Results) { +// Sending Inferences/Forecasts to the AppChain +func (ap *AppChain) SendWorkerModeData(ctx context.Context, topicId uint64, results aggregate.Results) { // Aggregate the inferences from all peers/workers - var inferences []*types.Inference - + WorkerDataBundles := make([]*types.WorkerDataBundle, 0) + var nonce *types.Nonce for _, result := range results { for _, peer := range result.Peers { - ap.Logger.Debug().Any("peer", peer) + ap.Logger.Debug().Str("worker peer", peer.String()) - // Get Peer $allo address + // Get Peer's $allo address res, err := ap.QueryClient.GetWorkerAddressByP2PKey(ctx, &types.QueryWorkerAddressByP2PKeyRequest{ Libp2PKey: peer.String(), }) if err != nil { - ap.Logger.Warn().Err(err).Str("peer", peer.String()).Msg("error getting peer address from chain, worker not registered? Ignoring peer.") + ap.Logger.Warn().Err(err).Str("peer", peer.String()).Msg("error getting worker peer address from chain, worker not registered? Ignoring peer.") continue } + ap.Logger.Debug().Str("worker address", res.Address).Msgf("%+v", result.Result) - value, err := checkJSONValueError(result.Result.Stdout) - if err != nil || value == "" { - ap.Logger.Warn().Err(err).Str("peer", peer.String()).Msg("error extracting value as number from stdout, ignoring inference.") + // Parse the result from the worker to get the inference and forecasts + var value WorkerDataResponse + err = json.Unmarshal([]byte(result.Result.Stdout), &value) + if err != nil { + ap.Logger.Warn().Err(err).Str("peer", peer.String()).Msg("error extracting WorkerDataBundle from stdout, ignoring bundle.") continue } - parsed, err := parseFloatToUint64(value) - if err != nil { - ap.Logger.Warn().Err(err).Str("peer", peer.String()).Str("value", value).Msg("error parsing inference as uint") + if nonce == nil { + nonce = &types.Nonce{BlockHeight: value.BlockHeight} + } + // Here reputer leader can choose to validate data further to ensure set is correct and act accordingly + if value.WorkerDataBundle == nil { + ap.Logger.Warn().Str("peer", peer.String()).Msg("WorkerDataBundle is nil from stdout, ignoring bundle.") continue } - inference := &types.Inference{ - TopicId: topicId, - Worker: res.Address, - Value: cosmossdk_io_math.NewUint(parsed), + if value.WorkerDataBundle.InferenceForecastsBundle == nil { + ap.Logger.Warn().Str("peer", peer.String()).Msg("InferenceForecastsBundle is nil from stdout, ignoring bundle.") + continue } - inferences = append(inferences, inference) + if value.WorkerDataBundle.InferenceForecastsBundle.Inference != nil && + value.WorkerDataBundle.InferenceForecastsBundle.Inference.TopicId != topicId { + ap.Logger.Warn().Str("peer", peer.String()).Msg("InferenceForecastsBundle topicId does not match with request topic, ignoring bundle.") + continue + } + + // Append the WorkerDataBundle (only) to the WorkerDataBundles slice + WorkerDataBundles = append(WorkerDataBundles, value.WorkerDataBundle) } } - req := &types.MsgProcessInferences{ - Sender: ap.ReputerAddress, - Inferences: inferences, + if nonce == nil { + ap.Logger.Warn().Msg("No valid WorkerDataBundles with nonces found, not sending data to the chain") + return + } + + // Make 1 request per worker + req := &types.MsgInsertBulkWorkerPayload{ + Sender: ap.Address, + Nonce: nonce, + TopicId: topicId, + WorkerDataBundles: WorkerDataBundles, + } + // Print req as JSON to the log + reqJSON, err := json.Marshal(req) + if err != nil { + ap.Logger.Error().Err(err).Msg("Error marshaling MsgInsertBulkWorkerPayload to print Msg as JSON") + } else { + ap.Logger.Info().Str("req_json", string(reqJSON)).Msg("Sending Worker Mode Data") } - ap.SendInferencesWithRetry(ctx, req, 5, 0, 2) + go func() { + _, _ = ap.SendDataWithRetry(ctx, req, NUM_WORKER_RETRIES, NUM_WORKER_RETRY_MIN_DELAY, NUM_WORKER_RETRY_MAX_DELAY, "Sent Worker Leader Data") + }() } -func (ap *AppChain) SendUpdatedWeights(ctx context.Context, topicId uint64, results aggregate.Results) { +// Can only look up the topic stakes of this many reputers at a time +const DEFAULT_MAX_REPUTERS_FOR_STAKE_QUERY = uint64(100) - weights := make([]*types.Weight, 0) - for _, result := range results { - extractedWeights, err := extractWeights(result.Result.Stdout) - if err != nil { - ap.Logger.Info().Err(err).Msg("Error extracting weight") - continue - } - - for peer, value := range extractedWeights { - ap.Logger.Info().Str("peer", peer) - parsed, err := parseFloatToUint64Weights(value) - if err != nil { - ap.Logger.Error().Err(err).Msg("Error parsing uint") - continue - } +// Only this number times MaxLimit (whose default is given above) of reputer stakes can be gathered at once +const MAX_NUMBER_STAKE_QUERIES_PER_REQUEST = uint64(3) - fmt.Printf("\n Worker Node: %s Weight: %v \n", peer, cosmossdk_io_math.NewUint(parsed)) +// Get the stake of each reputer in the given topic +func (ap *AppChain) getStakePerReputer(ctx context.Context, topicId uint64, reputerAddrs []*string) (map[string]cosmossdk_io_math.Int, error) { + maxReputers := DEFAULT_MAX_REPUTERS_FOR_STAKE_QUERY + params, err := ap.QueryClient.Params(ctx, &types.QueryParamsRequest{}) + if err != nil { + ap.Logger.Error().Err(err).Uint64("topic", topicId).Msg("could not get chain params") + } + if err == nil { + maxReputers = params.Params.MaxPageLimit + } - weight := &types.Weight{ - TopicId: topicId, - Reputer: ap.ReputerAddress, - Worker: peer, - Weight: cosmossdk_io_math.NewUint(parsed), + numberRequestsForStake := MAX_NUMBER_STAKE_QUERIES_PER_REQUEST + var stakesPerReputer = make(map[string]cosmossdk_io_math.Int) // This will be populated with each request/loop below + for i := uint64(0); i < numberRequestsForStake; i++ { + // Dereference only the needed reputer addresses to get the actual strings + addresses := make([]string, 0) + start := i * maxReputers + end := (i + 1) * maxReputers + if end > uint64(len(reputerAddrs)) { + end = uint64(len(reputerAddrs)) + } + if start >= end { + break + } + for _, addr := range reputerAddrs[start:end] { + if addr == nil { + return nil, fmt.Errorf("nil address in reputerAddrs") } - weights = append(weights, weight) + addresses = append(addresses, *addr) + } + res, err := ap.QueryClient.GetMultiReputerStakeInTopic(ctx, &types.QueryMultiReputerStakeInTopicRequest{ + TopicId: topicId, + Addresses: addresses, + }) + if err != nil { + ap.Logger.Error().Err(err).Uint64("topic", topicId).Msg("could not get reputer stakes from the chain") + return nil, err } - } - // Send updated weights to AppChain - req := &types.MsgSetWeights{ - Sender: ap.ReputerAddress, - Weights: weights, + // Create a map of reputer addresses to their stakes + for _, stake := range res.Amounts { + stakesPerReputer[stake.Reputer] = stake.Amount + } } - ap.SendWeightsWithRetry(ctx, req, 5, 0, 2) + return stakesPerReputer, err } -func parseFloatToUint64Weights(input string) (uint64, error) { - // Parse the string to a floating-point number - floatValue, err := strconv.ParseFloat(input, 64) - if err != nil { - return 0, err - } +func (ap *AppChain) argmaxBlockByStake( + blockToReputer *map[int64][]string, + stakesPerReputer map[string]cosmossdk_io_math.Int, +) int64 { + // Find the current block height with the highest voting power + firstIter := true + highestVotingPower := cosmossdk_io_math.ZeroInt() + blockOfMaxPower := int64(-1) + for block, reputersWhoVotedForBlock := range *blockToReputer { + // Calc voting power of this candidate block by total voting reputer stake + blockVotingPower := cosmossdk_io_math.ZeroInt() + for _, reputerAddr := range reputersWhoVotedForBlock { + blockVotingPower = blockVotingPower.Add(stakesPerReputer[reputerAddr]) + } - // Truncate or round the floating-point number to an integer - roundedValue := uint64(floatValue * 100000) // TODO: Change + // Decide if voting power exceeds that of current front-runner + if firstIter || blockVotingPower.GT(highestVotingPower) { + blockOfMaxPower = block + } + + firstIter = false + } - return roundedValue, nil + return blockOfMaxPower } -func parseFloatToUint64(input string) (uint64, error) { - // Parse the string to a floating-point number - floatValue, err := strconv.ParseFloat(input, 64) - if err != nil { - return 0, err - } +func (ap *AppChain) argmaxBlockByCount( + blockToReputer *map[int64][]string, +) int64 { + // Find the current block height with the highest voting power + firstIter := true + highestVotingPower := cosmossdk_io_math.ZeroInt() + blockOfMaxPower := int64(-1) + for block, reputersWhoVotedForBlock := range *blockToReputer { + // Calc voting power of this candidate block by total reputer count + blockVotingPower := cosmossdk_io_math.NewInt(int64(len(reputersWhoVotedForBlock))) + + // Decide if voting power exceeds that of current front-runner + if firstIter || blockVotingPower.GT(highestVotingPower) { + blockOfMaxPower = block + } - // Truncate or round the floating-point number to an integer - roundedValue := uint64(math.Round(floatValue)) + firstIter = false + } - return roundedValue, nil + return blockOfMaxPower } -func checkJSONValueError(stdout string) (string, error) { - var response Response - err := json.Unmarshal([]byte(stdout), &response) +// Take stake-weighted vote of what the reputer leader thinks the current and eval block heights should be +func (ap *AppChain) getStakeWeightedBlockHeights( + ctx context.Context, + topicId uint64, + blockCurrentToReputer, blockEvalToReputer *map[int64][]string, + reputerAddrs []*string, +) (int64, int64, error) { + useWeightedVote := true + stakesPerReputer, err := ap.getStakePerReputer(ctx, topicId, reputerAddrs) if err != nil { - return "Unable to unmarshall", err + ap.Logger.Error().Err(err).Uint64("topic", topicId).Msg("error getting reputer stakes from the chain => using unweighted vote") + // This removes a strict requirement for the reputer leader to have the correct stake + // at the cost of potentially allowing sybil attacks, though Blockless itself somewhat mitigates this + useWeightedVote = false } - if response.Value != "" { - return response.Value, nil - } else if response.Error != "" { - return "", errors.New("error found: " + response.Error) + // Find the current and ev block height with the highest voting power + if useWeightedVote { + return ap.argmaxBlockByStake(blockCurrentToReputer, stakesPerReputer), ap.argmaxBlockByStake(blockEvalToReputer, stakesPerReputer), nil } else { - return "", errors.New("no Error or Value field found in response") + return ap.argmaxBlockByCount(blockCurrentToReputer), ap.argmaxBlockByCount(blockEvalToReputer), nil } } -func extractWeights(stdout string) (map[string]string, error) { - fmt.Println("Extracting weights from stdout: ", stdout) +// Sending Losses to the AppChain +func (ap *AppChain) SendReputerModeData(ctx context.Context, topicId uint64, results aggregate.Results) { + // Aggregate the forecast from reputer leader + var valueBundles []*types.ReputerValueBundle + var reputerAddrs []*string + var reputerAddrSet = make(map[string]bool) // Prevents duplicate reputer addresses from being counted in vote tally + var nonceCurrent *types.Nonce + var nonceEval *types.Nonce + var blockCurrentToReputer = make(map[int64][]string) // map blockHeight to addresses of reputers who sent data for current block height + var blockEvalToReputer = make(map[int64][]string) // map blockHeight to addresses of reputers who sent data for eval block height + + for _, result := range results { + if len(result.Peers) > 0 { + peer := result.Peers[0] + ap.Logger.Debug().Str("worker peer", peer.String()) - var weights WorkerWeights - err := json.Unmarshal([]byte(stdout), &weights) + // Get Peer $allo address + res, err := ap.QueryClient.GetReputerAddressByP2PKey(ctx, &types.QueryReputerAddressByP2PKeyRequest{ + Libp2PKey: peer.String(), + }) + if err != nil { + ap.Logger.Warn().Err(err).Str("peer", peer.String()).Msg("error getting reputer peer address from chain, worker not registered? Ignoring peer.") + continue + } else { + // Print the address of the reputer + ap.Logger.Info().Str("Reputer Address", res.Address).Msg("Reputer Address") + } + + if _, ok := reputerAddrSet[res.Address]; !ok { + reputerAddrSet[res.Address] = true + + // Parse the result from the reputer to get the losses + // Parse the result from the worker to get the inferences and forecasts + var value ReputerDataResponse + err = json.Unmarshal([]byte(result.Result.Stdout), &value) + if err != nil { + ap.Logger.Warn().Err(err).Str("peer", peer.String()).Str("Value", result.Result.Stdout).Msg("error extracting ReputerDataResponse from stdout, ignoring bundle.") + continue + } + + // Here reputer leader can choose to validate data further to ensure set is correct and act accordingly + if value.ReputerValueBundle == nil { + ap.Logger.Warn().Str("peer", peer.String()).Msg("ReputerValueBundle is nil from stdout, ignoring bundle.") + continue + } + if value.ReputerValueBundle.ValueBundle == nil { + ap.Logger.Warn().Str("peer", peer.String()).Msg("ValueBundle is nil from stdout, ignoring bundle.") + continue + } + if value.ReputerValueBundle.ValueBundle.TopicId != topicId { + ap.Logger.Warn().Str("peer", peer.String()).Msg("ReputerValueBundle topicId does not match with request topicId, ignoring bundle.") + continue + } + // Append the WorkerDataBundle (only) to the WorkerDataBundles slice + valueBundles = append(valueBundles, value.ReputerValueBundle) + reputerAddrs = append(reputerAddrs, &res.Address) + blockCurrentToReputer[value.BlockHeight] = append(blockCurrentToReputer[value.BlockHeight], res.Address) + blockEvalToReputer[value.BlockHeightEval] = append(blockEvalToReputer[value.BlockHeightEval], res.Address) + } + } else { + ap.Logger.Warn().Msg("No peers in the result, ignoring") + } + } + + if len(reputerAddrs) == 0 { + ap.Logger.Warn().Msg("No reputer addresses found, not sending data to the chain") + return + } + + blockCurrentHeight, blockEvalHeight, err := ap.getStakeWeightedBlockHeights(ctx, topicId, &blockCurrentToReputer, &blockEvalToReputer, reputerAddrs) if err != nil { - return nil, err + ap.Logger.Error().Err(err).Msg("could not get stake-weighted block heights, not sending data to the chain") + return + } + if blockCurrentHeight == -1 || blockEvalHeight == -1 { + ap.Logger.Error().Msg("could not get stake-weighted block heights, not sending data to the chain") + return + } + if blockCurrentHeight < blockEvalHeight { + ap.Logger.Error().Int64("blockCurrentHeight", blockCurrentHeight).Int64("blockEvalHeight", blockEvalHeight).Msg("blockCurrentHeight < blockEvalHeight, not sending data to the chain") + return + } + nonceCurrent = &types.Nonce{BlockHeight: blockCurrentHeight} + nonceEval = &types.Nonce{BlockHeight: blockEvalHeight} + + // Remove those bundles that do not come from the current block height + var valueBundlesFiltered []*types.ReputerValueBundle + + for _, valueBundle := range valueBundles { + if valueBundle.ValueBundle.ReputerRequestNonce.ReputerNonce.BlockHeight == blockCurrentHeight && valueBundle.ValueBundle.ReputerRequestNonce.WorkerNonce.BlockHeight == blockEvalHeight { + ap.Logger.Debug(). + Str("reputer", valueBundle.ValueBundle.Reputer). + Str("nonce reputer", strconv.FormatInt(valueBundle.ValueBundle.ReputerRequestNonce.ReputerNonce.BlockHeight, 10)). + Str("nonce worker", strconv.FormatInt(valueBundle.ValueBundle.ReputerRequestNonce.WorkerNonce.BlockHeight, 10)). + Msg("Valid nonce, adding to valueBundlesFiltered") + valueBundlesFiltered = append(valueBundlesFiltered, valueBundle) + } else { + ap.Logger.Warn(). + Str("reputer", valueBundle.ValueBundle.Reputer). + Str("nonce reputer", strconv.FormatInt(valueBundle.ValueBundle.ReputerRequestNonce.ReputerNonce.BlockHeight, 10)). + Str("nonce worker", strconv.FormatInt(valueBundle.ValueBundle.ReputerRequestNonce.WorkerNonce.BlockHeight, 10)). + Msg("Rejected Bundle, non-matching nonces.") + } + } + + // Make 1 request per worker + req := &types.MsgInsertBulkReputerPayload{ + Sender: ap.Address, + ReputerRequestNonce: &types.ReputerRequestNonce{ + ReputerNonce: nonceCurrent, + WorkerNonce: nonceEval, + }, + TopicId: topicId, + ReputerValueBundles: valueBundles, + } + // Print req as JSON to the log + reqJSON, err := json.Marshal(req) + if err != nil { + ap.Logger.Error().Err(err).Msg("Error marshaling MsgInsertBulkReputerPayload to print Msg as JSON") + } else { + ap.Logger.Info().Str("req_json", string(reqJSON)).Msg("Sending Reputer Mode Data") } - return weights.Weights, nil + go func() { + _, _ = ap.SendDataWithRetry(ctx, req, NUM_REPUTER_RETRIES, NUM_REPUTER_RETRY_MIN_DELAY, NUM_REPUTER_RETRY_MAX_DELAY, "Send Reputer Leader Data") + }() } diff --git a/cmd/node/appchain_test.go b/cmd/node/appchain_test.go new file mode 100644 index 0000000..4dbdd1b --- /dev/null +++ b/cmd/node/appchain_test.go @@ -0,0 +1,188 @@ +package main + +import ( + "context" + "encoding/hex" + "fmt" + "os" + "testing" + "time" + + alloraMath "github.com/allora-network/allora-chain/math" + "github.com/allora-network/allora-chain/x/emissions/types" + "github.com/allora-network/b7s/host" + "github.com/allora-network/b7s/models/blockless" + "github.com/allora-network/b7s/models/execute" + "github.com/allora-network/b7s/node/aggregate" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + "github.com/libp2p/go-libp2p/core/peer" + "github.com/rs/zerolog" + "github.com/stretchr/testify/suite" +) + +type AppChainTestSuit struct { + suite.Suite + app *AppChain +} + +func TestAppChainTestSuite(t *testing.T) { + suite.Run(t, new(AppChainTestSuit)) +} + +func (ap *AppChainTestSuit) SetupTest() { + + cfg := parseFlags() + + // Initialize logging. + log := zerolog.New(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}).With().Timestamp().Logger().Level(zerolog.DebugLevel) + + // Get the list of boot nodes addresses. + bootNodeAddrs, err := getBootNodeAddresses(cfg.BootNodes) + if err != nil { + return + } + + host, err := host.New(log, cfg.Host.Address, cfg.Host.Port, + host.WithPrivateKey(cfg.Host.PrivateKey), + host.WithBootNodes(bootNodeAddrs), + host.WithDialBackPeers(nil), + host.WithDialBackAddress(cfg.Host.DialBackAddress), + host.WithDialBackPort(cfg.Host.DialBackPort), + host.WithDialBackWebsocketPort(cfg.Host.DialBackWebsocketPort), + host.WithWebsocket(cfg.Host.Websocket), + host.WithWebsocketPort(cfg.Host.WebsocketPort), + ) + + if err != nil { + return + } + + cfg.AppChainConfig.NodeRole = blockless.WorkerNode + cfg.AppChainConfig.AddressPrefix = "allo" + cfg.AppChainConfig.StringSeperator = "|" + cfg.AppChainConfig.LibP2PKey = host.ID().String() + cfg.AppChainConfig.MultiAddress = host.Addresses()[0] + + ap.app, err = connectToAlloraBlockchain(cfg.AppChainConfig, log) +} +func (ap *AppChainTestSuit) TestSendWorkerModeData() { + ctx, _ := context.WithCancel(context.Background()) + var aggre = []aggregate.Result{ + { + Result: execute.RuntimeOutput{ + Stdout: "{\"infererValue\": \"3234.12\",\"forecasterValues\":[{\"node\":\"allo1inf1\",\"value\",\"0.256\"},{\"node\":\"allo1inf2\",\"value\":\"1.48\"},{\"node\":\"allo1inf1111\",\"value\":\"0.569885\"}]}", + Stderr: "", + ExitCode: 0, + Log: "", + }, + Peers: []peer.ID{"12D3KooWAPLuwMuvH9pmGfAZkCrfhKdhJNYn8eaDSJyX9Kd3HjVS"}, + Frequency: 25, + }, + { + Result: execute.RuntimeOutput{ + Stdout: "{\"infererValue\": \"1234.56\",\"forecasterValues\":[{\"node\":\"allo1inf1\",\"value\",\"0.256\"},{\"node\":\"allo1inf2\",\"value\":\"1.48\"},{\"node\":\"allo1inf1111\",\"value\":\"0.569885\"}]}", + Stderr: "", + ExitCode: 0, + Log: "", + }, + Peers: []peer.ID{"12D3KooWQrN5U3BApv4JYjE5HyKXFKkRF2U8c5FgK3zMPjzkZTpQ"}, + Frequency: 25, + }, + { + Result: execute.RuntimeOutput{ + Stdout: "{\"infererValue\": \"9876.34\",\"forecasterValues\":[{\"node\":\"allo1inf1\",\"value\",\"0.256\"},{\"node\":\"allo1inf2\",\"value\":\"1.48\"},{\"node\":\"allo1inf1111\",\"value\":\"0.569885\"}]}", + Stderr: "", + ExitCode: 0, + Log: "", + }, + Peers: []peer.ID{"12D3KooWRfswWHRe4718tbMWHU2B2sEbZxJXQsdWCJmURReMozqX"}, + Frequency: 25, + }, + } + ap.app.SendWorkerModeData(ctx, 1, aggre) +} +func (ap *AppChainTestSuit) TestSendReputerModeData() { + ctx, _ := context.WithCancel(context.Background()) + var aggre = []aggregate.Result{ + { + Result: execute.RuntimeOutput{ + Stdout: "{\"networkInference\":0.014399999999973807,\n \"naiveNetworkInference\":0.01960000000002801,\n \"inferrerInferences\":[\n {\"node\":\"allo1inf1\",\"value\":0.18490000000005475},\n {\"node\":\"allo1inf2\",\"value\":0.3248999999999274},\n {\"node\":\"allo1inf0000\",\"value\":0.02889999999994743}\n ],\n \"forecasterInferences\":[\n {\"node\":\"allo1inf1\",\"value\":0.05760000000000436},\n {\"node\":\"allo1inf2\",\"value\":1.587599999999977},\n {\"node\":\"allo1inf1111\",\"value\":0.006399999999988359}\n ],\n \"oneOutNetworkInferences\":[\n {\"node\":\"allo1inf1\",\"value\":0.05760000000000436},\n {\"node\":\"allo1inf2\",\"value\":0.06759999999999528},\n {\"node\":\"allo1inf0000\",\"value\":1.0200999999999816}\n ],\n \"oneInNetworkInferences\":[\n {\"node\":\"allo1inf1\",\"value\":0.05760000000000436},\n {\"node\":\"allo1inf2\",\"value\":0.06759999999999528},\n {\"node\":\"allo1inf1111\",\"value\":1.0200999999999816}\n ]}", + Stderr: "", + ExitCode: 0, + Log: "", + }, + Peers: []peer.ID{"allo1lfhccfylj30t2zz9mzudx54h25x8mu0jrzjfz2"}, + Frequency: 25, + }, + { + Result: execute.RuntimeOutput{ + Stdout: "{\"networkInference\":0.014399999999973807,\n \"naiveNetworkInference\":0.01960000000002801,\n \"inferrerInferences\":[\n {\"node\":\"allo1inf1\",\"value\":0.18490000000005475},\n {\"node\":\"allo1inf2\",\"value\":0.3248999999999274},\n {\"node\":\"allo1inf0000\",\"value\":0.02889999999994743}\n ],\n \"forecasterInferences\":[\n {\"node\":\"allo1inf1\",\"value\":0.05760000000000436},\n {\"node\":\"allo1inf2\",\"value\":1.587599999999977},\n {\"node\":\"allo1inf1111\",\"value\":0.006399999999988359}\n ],\n \"oneOutNetworkInferences\":[\n {\"node\":\"allo1inf1\",\"value\":0.05760000000000436},\n {\"node\":\"allo1inf2\",\"value\":0.06759999999999528},\n {\"node\":\"allo1inf0000\",\"value\":1.0200999999999816}\n ],\n \"oneInNetworkInferences\":[\n {\"node\":\"allo1inf1\",\"value\":0.05760000000000436},\n {\"node\":\"allo1inf2\",\"value\":0.06759999999999528},\n {\"node\":\"allo1inf1111\",\"value\":1.0200999999999816}\n ]}", + Stderr: "", + ExitCode: 0, + Log: "", + }, + Peers: []peer.ID{"12D3KooWQrN5U3BApv4JYjE5HyKXFKkRF2U8c5FgK3zMPjzkZTpQ"}, + Frequency: 25, + }, + { + Result: execute.RuntimeOutput{ + Stdout: "{\"networkInference\":0.014399999999973807,\n \"naiveNetworkInference\":0.01960000000002801,\n \"inferrerInferences\":[\n {\"node\":\"allo1inf1\",\"value\":0.18490000000005475},\n {\"node\":\"allo1inf2\",\"value\":0.3248999999999274},\n {\"node\":\"allo1inf0000\",\"value\":0.02889999999994743}\n ],\n \"forecasterInferences\":[\n {\"node\":\"allo1inf1\",\"value\":0.05760000000000436},\n {\"node\":\"allo1inf2\",\"value\":1.587599999999977},\n {\"node\":\"allo1inf1111\",\"value\":0.006399999999988359}\n ],\n \"oneOutNetworkInferences\":[\n {\"node\":\"allo1inf1\",\"value\":0.05760000000000436},\n {\"node\":\"allo1inf2\",\"value\":0.06759999999999528},\n {\"node\":\"allo1inf0000\",\"value\":1.0200999999999816}\n ],\n \"oneInNetworkInferences\":[\n {\"node\":\"allo1inf1\",\"value\":0.05760000000000436},\n {\"node\":\"allo1inf2\",\"value\":0.06759999999999528},\n {\"node\":\"allo1inf1111\",\"value\":1.0200999999999816}\n ]}", + Stderr: "", + ExitCode: 0, + Log: "", + }, + Peers: []peer.ID{"12D3KooWRfswWHRe4718tbMWHU2B2sEbZxJXQsdWCJmURReMozqX"}, + Frequency: 25, + }, + } + ap.app.SendReputerModeData(ctx, 1, aggre) +} +func (ap *AppChainTestSuit) TestSendDataWithRetry() { + ctx, _ := context.WithCancel(context.Background()) + + req := &types.MsgInsertBulkWorkerPayload{ + Sender: "allo1mnfm9c7cdgqnkk66sganp78m0ydmcr4pce8kju", + Nonce: &types.Nonce{BlockHeight: 1}, + TopicId: 0, + WorkerDataBundles: []*types.WorkerDataBundle{ + { + Worker: "allo1353a4uac03etdylz86tyq9ssm3x2704j66t99e", + InferenceForecastsBundle: &types.InferenceForecastBundle{ + Inference: &types.Inference{ + TopicId: 0, + BlockHeight: 1, + Inferer: "allo163xn94xytks2375ulpxdv7kqvvvxfvazpxyqzh", + Value: alloraMath.NewDecFromInt64(100), + }, + Forecast: &types.Forecast{ + TopicId: 0, + BlockHeight: 10, + Forecaster: "allo1d8vj2se0f63x90u4msfuy5mva3arengrr7t5f6", + ForecastElements: []*types.ForecastElement{ + { + Inferer: "allo148awdjfw7jf0847mkqvqn8mu4tqa92r52tzw5j", + Value: alloraMath.NewDecFromInt64(100), + }, + { + Inferer: "allo148awdjfw7jf0847mkqvqn8mu4tqa92r52tzw5j", + Value: alloraMath.NewDecFromInt64(100), + }, + }, + }, + }, + InferencesForecastsBundleSignature: []byte("Signature"), + }, + }, + } + src := make([]byte, 0) + src, _ = req.WorkerDataBundles[0].InferenceForecastsBundle.XXX_Marshal(src, true) + sig, pk, err := ap.app.Client.Context().Keyring.Sign(ap.app.Account.Name, src, signing.SignMode_SIGN_MODE_DIRECT) + pkStr := hex.EncodeToString(pk.Bytes()) + if err != nil { + fmt.Println("Error signing the nonce: ", err) + return + } + req.WorkerDataBundles[0].Pubkey = pkStr + req.WorkerDataBundles[0].InferencesForecastsBundleSignature = sig + ap.app.SendDataWithRetry(ctx, req, 5, 0, 2, "test send with retry") +} diff --git a/cmd/node/execute.go b/cmd/node/execute.go index 6acc074..7d348ce 100644 --- a/cmd/node/execute.go +++ b/cmd/node/execute.go @@ -2,18 +2,20 @@ package main import ( "context" - "encoding/json" "errors" "fmt" "net/http" "strconv" - - "github.com/blocklessnetwork/b7s/api" - "github.com/blocklessnetwork/b7s/models/blockless" - "github.com/blocklessnetwork/b7s/models/codes" - "github.com/blocklessnetwork/b7s/models/execute" - "github.com/blocklessnetwork/b7s/node/aggregate" + "strings" + + "github.com/allora-network/b7s/api" + "github.com/allora-network/b7s/models/blockless" + "github.com/allora-network/b7s/models/codes" + "github.com/allora-network/b7s/models/execute" + "github.com/allora-network/b7s/node" + "github.com/allora-network/b7s/node/aggregate" "github.com/labstack/echo/v4" + "github.com/rs/zerolog" ) // ExecuteRequest describes the payload for the REST API request for function execution. @@ -31,55 +33,57 @@ type ExecuteResponse struct { Cluster execute.Cluster `json:"cluster,omitempty"` } -// ExecuteResult represents the API representation of a single execution response. -// It is similar to the model in `execute.Result`, except it omits the usage information for now. -type ExecuteResult struct { - Code codes.Code `json:"code,omitempty"` - Result execute.RuntimeOutput `json:"result,omitempty"` - RequestID string `json:"request_id,omitempty"` -} - -func sendResultsToChain(ctx echo.Context, a api.API, appChainClient AppChain, req ExecuteRequest, res ExecuteResponse) { - - // Only in weight functions that we will have a "type" in the response - functionType := "inferences" - functionTypeFromFn, err := getResponseInfo(res.Results[0].Result.Stdout) - if err != nil { - a.Log.Warn().Str("function", req.FunctionID).Err(err).Msg("node failed to extract response info from stdout") - } else { - if functionTypeFromFn != "" { - functionType = functionTypeFromFn +func sendResultsToChain(log zerolog.Logger, appChainClient *AppChain, res node.ChanData) { + log.Info().Msg("Sending Results to chain") + if appChainClient == nil || res.Res != codes.OK { + reason := "unknown" + if appChainClient == nil { + reason = "AppChainClient is disabled" + } else if res.Res != codes.OK { + reason = fmt.Sprintf("Response code is not OK: %s", res.Res) } - } - - // var topicId uint64 = req.Topic - topicId, err := strconv.ParseUint(req.Topic, 10, 64) - if err != nil { - a.Log.Error().Str("Topic", req.Topic).Str("function", functionType).Err(err).Msg("Cannot parse topic ID") + log.Warn().Msgf("Worker results not submitted to chain, not attempted. Reason: %s", reason) return } - a.Log.Debug().Str("Topic", req.Topic).Str("function", functionType).Msg("Found topic ID") + stdout := aggregate.Aggregate(res.Data)[0].Result.Stdout + log.Info().Str("stdout", stdout).Msg("Aggregated stdout result") + + log.Debug().Str("Topic", res.Topic).Str("worker mode", appChainClient.Config.WorkerMode).Msg("Found topic ID") // TODO: We can move this context to the AppChain struct (previous context was breaking the tx broadcast response) reqCtx := context.Background() - if functionType == inferenceType { - appChainClient.SendInferences(reqCtx, topicId, res.Results) - } else if functionType == weightsType { - appChainClient.SendUpdatedWeights(reqCtx, topicId, res.Results) - } -} + if appChainClient.Config.WorkerMode == WorkerModeWorker { // for inference or forecast + topicId, err := strconv.ParseUint(res.Topic, 10, 64) + if err != nil { + log.Error().Str("Topic", res.Topic).Str("worker mode", appChainClient.Config.WorkerMode).Err(err).Msg("Cannot parse worker topic ID") + return + } + appChainClient.SendWorkerModeData(reqCtx, topicId, aggregate.Aggregate(res.Data)) + } else { // for losses + // if topicId does not end in "/reputer -func getResponseInfo(stdout string) (string, error) { - var responseInfo ResponseInfo - err := json.Unmarshal([]byte(stdout), &responseInfo) - if err != nil { - return "", err + if !strings.HasSuffix(res.Topic, REPUTER_TOPIC_SUFFIX) { + log.Error().Str("Topic", res.Topic).Str("worker mode", appChainClient.Config.WorkerMode).Msg("Invalid reputer topic format") + return + } + // Get the topicId from the reputer topic string + index := strings.Index(res.Topic, "/") + if index == -1 { + // Handle the error: "/" not found in res.Topic + log.Error().Str("Topic", res.Topic).Msg("Invalid topic format") + return + } + topicId, err := strconv.ParseUint(res.Topic[:index], 10, 64) + if err != nil { + log.Error().Str("Topic", res.Topic).Str("worker mode", appChainClient.Config.WorkerMode).Err(err).Msg("Cannot parse reputer topic ID") + return + } + appChainClient.SendReputerModeData(reqCtx, topicId, aggregate.Aggregate(res.Data)) } - - return responseInfo.FunctionType, nil } -func createExecutor(a api.API, appChainClient *AppChain) func(ctx echo.Context) error { +func createExecutor(a api.API) func(ctx echo.Context) error { + return func(ctx echo.Context) error { // Unpack the API request. @@ -116,23 +120,6 @@ func createExecutor(a api.API, appChainClient *AppChain) func(ctx echo.Context) res.Message = err.Error() } - // Might be disabled if so we should log out - if appChainClient != nil && appChainClient.Config.SubmitTx && res.Code == codes.OK { - // don't block the return to the consumer to send these to chain - go sendResultsToChain(ctx, a, *appChainClient, req, res) - } else { - a.Log.Debug().Msg("Inference results would have been submitted to chain.") - reason := "unknown" - if appChainClient == nil { - reason = "AppChainClient is disabled" - } else if !appChainClient.Config.SubmitTx { - reason = "Submitting transactions is disabled in AppChainClient" - } else if res.Code != codes.OK { - reason = fmt.Sprintf("Response code is not OK: %s, message: %s", res.Code, res.Message) - } - a.Log.Warn().Msgf("Inference results not submitted to chain, not attempted. Reason: %s", reason) - } - // Send the response. return ctx.JSON(http.StatusOK, res) } diff --git a/cmd/node/flags.go b/cmd/node/flags.go index f7ec6c4..5c143bf 100644 --- a/cmd/node/flags.go +++ b/cmd/node/flags.go @@ -3,7 +3,7 @@ package main import ( "github.com/spf13/pflag" - "github.com/blocklessnetwork/b7s/node" + "github.com/allora-network/b7s/node" ) // Default values. @@ -62,8 +62,10 @@ func parseFlags() *alloraCfg { pflag.StringVarP(&cfg.AppChainConfig.NodeRPCAddress, "allora-node-rpc-address", "", "http://localhost:26657", "The address for the client to connect to a node.") pflag.StringSliceVar(&cfg.AppChainConfig.TopicIds, "allora-chain-topic-id", nil, "The topic id for the topic that the node will subscribe to.") pflag.Uint64Var(&cfg.AppChainConfig.ReconnectSeconds, "allora-chain-reconnect-seconds", 60, "If connection to Allora Appchain breaks, it will attempt to reconnect with this interval. O means no reconnection.") - pflag.Uint64Var(&cfg.AppChainConfig.InitialStake, "allora-chain-initial-stake", 1000, "Upon registering on a new topic, amount of stake to use.") - + pflag.Int64Var(&cfg.AppChainConfig.InitialStake, "allora-chain-initial-stake", 0, "Upon registering on a new topic, amount of stake to use.") + pflag.StringVarP(&cfg.AppChainConfig.WorkerMode, "allora-chain-worker-mode", "", WorkerModeWorker, "Worker mode of an Allora Network node.") + pflag.StringVar(&cfg.AppChainConfig.Gas, "allora-chain-gas", "auto", "Max gas on Allora client.") + pflag.Float64Var(&cfg.AppChainConfig.GasAdjustment, "allora-chain-gas-adjustment", 0.1, "Gas adjustment on Allora client.") pflag.CommandLine.SortFlags = false pflag.Parse() diff --git a/cmd/node/main.go b/cmd/node/main.go index dfef9f7..4256ac8 100644 --- a/cmd/node/main.go +++ b/cmd/node/main.go @@ -2,33 +2,43 @@ package main import ( "context" + "encoding/hex" + "encoding/json" "errors" + "fmt" "math" "net/http" "os" "os/signal" "path/filepath" + "strconv" + "sync" "time" "github.com/cockroachdb/pebble" + "github.com/cosmos/cosmos-sdk/types/tx/signing" "github.com/labstack/echo/v4" "github.com/rs/zerolog" "github.com/ziflex/lecho/v3" - "github.com/blocklessnetwork/b7s/api" - "github.com/blocklessnetwork/b7s/executor" - "github.com/blocklessnetwork/b7s/executor/limits" - "github.com/blocklessnetwork/b7s/fstore" - "github.com/blocklessnetwork/b7s/host" - "github.com/blocklessnetwork/b7s/models/blockless" - "github.com/blocklessnetwork/b7s/node" - "github.com/blocklessnetwork/b7s/peerstore" - "github.com/blocklessnetwork/b7s/store" + alloraMath "github.com/allora-network/allora-chain/math" + "github.com/allora-network/allora-chain/x/emissions/types" + "github.com/allora-network/b7s/api" + "github.com/allora-network/b7s/executor" + "github.com/allora-network/b7s/executor/limits" + "github.com/allora-network/b7s/fstore" + "github.com/allora-network/b7s/host" + "github.com/allora-network/b7s/models/blockless" + "github.com/allora-network/b7s/models/execute" + "github.com/allora-network/b7s/node" + "github.com/allora-network/b7s/peerstore" + "github.com/allora-network/b7s/store" ) const ( - success = 0 - failure = 1 + success = 0 + failure = 1 + notFoundValue = -1 ) func main() { @@ -40,11 +50,369 @@ func connectToAlloraBlockchain(cfg AppChainConfig, log zerolog.Logger) (*AppChai if err != nil || appchain == nil { log.Warn().Err(err).Msg("error connecting to allora blockchain") return nil, err + } else { + log.Info().Msg("connected to allora blockchain") } appchain.Config.SubmitTx = true return appchain, nil } +func NewAlloraExecutor(e blockless.Executor) *AlloraExecutor { + return &AlloraExecutor{ + Executor: e, + } +} + +func (e *AlloraExecutor) ExecuteFunction(requestID string, req execute.Request) (execute.Result, error) { + // First call the blockless.Executor's method to get the result + result, err := e.Executor.ExecuteFunction(requestID, req) + // print incoming result: + fmt.Println("Result from WASM: ", result.Result.Stdout) + + // Get the topicId from the env var + var topicId uint64 + var topicFound bool = false + var alloraBlockHeightCurrent int64 = notFoundValue + var alloraBlockHeightEval int64 = notFoundValue + var topicAllowsNegative bool = false + for _, envVar := range req.Config.Environment { + if envVar.Name == "TOPIC_ID" { + topicFound = true + // Get the topicId from the environment variable from str as uint64 + topicId, err = strconv.ParseUint(envVar.Value, 10, 64) + if err != nil { + // check if it ends with "/reputer" and extract the previous numerical value + if len(envVar.Value) > 8 && envVar.Value[len(envVar.Value)-8:] == "/reputer" { + topicId, err = strconv.ParseUint(envVar.Value[:len(envVar.Value)-8], 10, 64) + if err != nil { + fmt.Println("Error parsing topic ID: ", err) + return result, err + } + } else { + fmt.Println("Error parsing topic ID: no int, no '/reputer' suffix ", err) + return result, err + } + } + fmt.Println("TOPIC_ID: ", topicId) + } else if envVar.Name == "ALLORA_BLOCK_HEIGHT_CURRENT" { + alloraBlockHeightCurrent, err = strconv.ParseInt(envVar.Value, 10, 64) + if err != nil { + fmt.Println("Error parsing ALLORA_BLOCK_HEIGHT_CURRENT: ", err) + return result, err + } + fmt.Println("ALLORA_BLOCK_HEIGHT_CURRENT: ", alloraBlockHeightCurrent) + } else if envVar.Name == "ALLORA_BLOCK_HEIGHT_EVAL" { + // Get the topicId from the environment variable from str as uint64 + alloraBlockHeightEval, err = strconv.ParseInt(envVar.Value, 10, 64) + if err != nil { + fmt.Println("Error parsing ALLORA_BLOCK_HEIGHT_EVAL: ", err) + return result, err + } + fmt.Println("ALLORA_BLOCK_HEIGHT_EVAL: ", alloraBlockHeightEval) + } else if envVar.Name == "LOSS_FUNCTION_ALLOWS_NEGATIVE" { + if envVar.Value == "true" { + topicAllowsNegative = true + } + fmt.Println("LOSS_FUNCTION_ALLOWS_NEGATIVE: ", strconv.FormatBool(topicAllowsNegative)) + } + } + if !topicFound { + fmt.Println("No topic ID found in the environment variables.") + return result, nil + } + if alloraBlockHeightCurrent == notFoundValue { + fmt.Println("No ALLORA_BLOCK_HEIGHT_CURRENT found in the environment variables.") + return result, nil + } + + if e.appChain == nil { + fmt.Println("Appchain is nil, cannot sign the payload, returning as is.") + return result, nil + } + // Iterate env vars to get the ALLORA_NONCE, if found, sign it and add the signature to the result + // Check if this worker node is reputer or worker mode + if e.appChain.Config.WorkerMode == WorkerModeWorker { + // Get the nonce from the environment variable, convert to bytes + // If appchain is null or SubmitTx is false, do not sign the nonce + if e.appChain != nil && e.appChain.Client != nil { + // Get the account from the appchain + accountName := e.appChain.Account.Name + var responseValue InferenceForecastResponse + err = json.Unmarshal([]byte(result.Result.Stdout), &responseValue) + if err != nil { + fmt.Println("Error serializing InferenceForecastResponse proto message: ", err) + } else { + // Define an empty bundle + inferenceForecastsBundle := &types.InferenceForecastBundle{} + // Build inference if existent + if responseValue.InfererValue != "" { + infererValue := alloraMath.MustNewDecFromString(responseValue.InfererValue) + inference := &types.Inference{ + TopicId: topicId, + Inferer: e.appChain.Address, + Value: infererValue, + BlockHeight: alloraBlockHeightCurrent, + } + inferenceForecastsBundle.Inference = inference + } + // Build Forecast + if len(responseValue.ForecasterValues) > 0 { + var forecasterElements []*types.ForecastElement + for _, val := range responseValue.ForecasterValues { + decVal := alloraMath.MustNewDecFromString(val.Value) + if !topicAllowsNegative { + decVal, err = alloraMath.Log10(decVal) + if err != nil { + fmt.Println("Error Log10 forecasterElements: ", err) + return result, err + } + } + forecasterElements = append(forecasterElements, &types.ForecastElement{ + Inferer: val.Worker, + Value: decVal, + }) + } + + if len(forecasterElements) > 0 { + forecasterValues := &types.Forecast{ + TopicId: topicId, + BlockHeight: alloraBlockHeightCurrent, + Forecaster: e.appChain.Address, + ForecastElements: forecasterElements, + } + inferenceForecastsBundle.Forecast = forecasterValues + } + } + + // Marshall and sign the bundle + protoBytesIn := make([]byte, 0) // Create a byte slice with initial length 0 and capacity greater than 0 + protoBytesIn, err := inferenceForecastsBundle.XXX_Marshal(protoBytesIn, true) + if err != nil { + fmt.Println("Error Marshalling InferenceForecastsBundle: ", err) + return result, err + } + sig, pk, err := e.appChain.Client.Context().Keyring.Sign(accountName, protoBytesIn, signing.SignMode_SIGN_MODE_DIRECT) + pkStr := hex.EncodeToString(pk.Bytes()) + if err != nil { + fmt.Println("Error signing the InferenceForecastsBundle message: ", err) + return result, err + } + // Create workerDataBundle with signature + workerDataBundle := &types.WorkerDataBundle{ + Worker: e.appChain.Address, + InferenceForecastsBundle: inferenceForecastsBundle, + InferencesForecastsBundleSignature: sig, + Pubkey: pkStr, + } + + // Bundle it with topic and blockheight info + workerDataResponse := &WorkerDataResponse{ + WorkerDataBundle: workerDataBundle, + BlockHeight: alloraBlockHeightCurrent, + TopicId: int64(topicId), + } + // Serialize the workerDataBundle into json + workerDataBundleBytes, err := json.Marshal(workerDataResponse) + if err != nil { + fmt.Println("Error serializing WorkerDataBundle: ", err) + return result, err + } + outputJson := string(workerDataBundleBytes) + fmt.Println("Signed OutputJson sent to consensus: ", outputJson) + result.Result.Stdout = outputJson + } + } else { + fmt.Println("Appchain is nil, cannot sign the payload.") + } + } else if e.appChain.Config.WorkerMode == WorkerModeReputer { + // Get the nonce from the environment variable, convert to bytes + // If appchain is null or SubmitTx is false, do not sign the nonce + if e.appChain != nil && e.appChain.Client != nil { + fmt.Println("Worker mode is Reputer, packaging output for consensus.") + // Check also the EVAL nonce + if alloraBlockHeightEval == notFoundValue { + fmt.Println("No ALLORA_BLOCK_HEIGHT_EVAL found in the environment variables.") + return result, nil + } + // Create ReputerRequestNonce + reputerRequestNonce := &types.ReputerRequestNonce{ + ReputerNonce: &types.Nonce{ + BlockHeight: alloraBlockHeightCurrent, + }, + WorkerNonce: &types.Nonce{ + BlockHeight: alloraBlockHeightEval, + }, + } + + // Now get the string of the value, unescape it and unmarshall into ValueBundle + // Unmarshal the "value" field from the LossResponse struct + var wasmValueBundle ReputerWASMResponse + err = json.Unmarshal([]byte(result.Result.Stdout), &wasmValueBundle) + if err != nil { + e.appChain.Logger.Error().Err(err).Msg("Error unmarshalling JSON Value.") + return result, err + } + var nestedValueBundle ValueBundle + err = json.Unmarshal([]byte(wasmValueBundle.Value), &nestedValueBundle) + if err != nil { + e.appChain.Logger.Error().Err(err).Msg("Error unmarshalling nested JSON ValueBundle:") + return result, err + } + + combinedValue := alloraMath.MustNewDecFromString(nestedValueBundle.CombinedValue) + naiveValue := alloraMath.MustNewDecFromString(nestedValueBundle.NaiveValue) + + // Log10 values the output when never_negative is set as true + if !topicAllowsNegative { + combinedValue, err = alloraMath.Log10(combinedValue) + if err != nil { + e.appChain.Logger.Error().Err(err).Msg("Error Log10 for Combined Value:") + return result, err + } + naiveValue, err = alloraMath.Log10(naiveValue) + if err != nil { + e.appChain.Logger.Error().Err(err).Msg("Error Log10 for Naive Value:") + return result, err + } + } + + // Get the values from the nestedValueBundle + var ( + inferVal []*types.WorkerAttributedValue + forecastsVal []*types.WorkerAttributedValue + outInferVal []*types.WithheldWorkerAttributedValue + outForecastVal []*types.WithheldWorkerAttributedValue + inInferVal []*types.WorkerAttributedValue + ) + + for _, inf := range nestedValueBundle.InfererValues { + value := alloraMath.MustNewDecFromString(inf.Value) + if !topicAllowsNegative { + value, err = alloraMath.Log10(value) + if err != nil { + e.appChain.Logger.Error().Err(err).Msg("Error Log10 for Inferer Value:") + return result, err + } + } + inferVal = append(inferVal, &types.WorkerAttributedValue{ + Worker: inf.Worker, + Value: value, + }) + } + for _, inf := range nestedValueBundle.ForecasterValues { + value := alloraMath.MustNewDecFromString(inf.Value) + if !topicAllowsNegative { + value, err = alloraMath.Log10(value) + if err != nil { + e.appChain.Logger.Error().Err(err).Msg("Error Log10 for Forecaster Value:") + return result, err + } + } + forecastsVal = append(forecastsVal, &types.WorkerAttributedValue{ + Worker: inf.Worker, + Value: value, + }) + } + for _, inf := range nestedValueBundle.OneOutInfererValues { + value := alloraMath.MustNewDecFromString(inf.Value) + if !topicAllowsNegative { + value, err = alloraMath.Log10(value) + if err != nil { + e.appChain.Logger.Error().Err(err).Msg("Error Log10 for OutInferer Value:") + return result, err + } + } + outInferVal = append(outInferVal, &types.WithheldWorkerAttributedValue{ + Worker: inf.Worker, + Value: value, + }) + } + for _, inf := range nestedValueBundle.OneOutForecasterValues { + value := alloraMath.MustNewDecFromString(inf.Value) + if !topicAllowsNegative { + value, err = alloraMath.Log10(value) + if err != nil { + e.appChain.Logger.Error().Err(err).Msg("Error Log10 for OutForecaster Value:") + return result, err + } + } + outForecastVal = append(outForecastVal, &types.WithheldWorkerAttributedValue{ + Worker: inf.Worker, + Value: value, + }) + } + for _, inf := range nestedValueBundle.OneInForecasterValues { + value := alloraMath.MustNewDecFromString(inf.Value) + if !topicAllowsNegative { + value, err = alloraMath.Log10(value) + if err != nil { + e.appChain.Logger.Error().Err(err).Msg("Error Log10 for InForecaster Value:") + return result, err + } + } + inInferVal = append(inInferVal, &types.WorkerAttributedValue{ + Worker: inf.Worker, + Value: value, + }) + } + + newValueBundle := &types.ValueBundle{ + TopicId: topicId, + ReputerRequestNonce: reputerRequestNonce, + Reputer: e.appChain.Address, + CombinedValue: combinedValue, + NaiveValue: naiveValue, + InfererValues: inferVal, + ForecasterValues: forecastsVal, + OneOutInfererValues: outInferVal, + OneOutForecasterValues: outForecastVal, + OneInForecasterValues: inInferVal, + } + + // Marshall and sign the bundle + // Get the account from the appchain + accountName := e.appChain.Account.Name + protoBytesIn := make([]byte, 0) + protoBytesIn, err := newValueBundle.XXX_Marshal(protoBytesIn, true) + if err != nil { + fmt.Println("Error Marshalling newValueBundle: ", err) + return result, err + } + sig, pk, err := e.appChain.Client.Context().Keyring.Sign(accountName, protoBytesIn, signing.SignMode_SIGN_MODE_DIRECT) + pkStr := hex.EncodeToString(pk.Bytes()) + if err != nil { + fmt.Println("Error signing the InferenceForecastsBundle message: ", err) + return result, err + } + + // Create workerDataBundle with signature and pubkey + valueBundle := &types.ReputerValueBundle{ + ValueBundle: newValueBundle, + Signature: sig, + Pubkey: pkStr, + } + + reputerDataResponse := &ReputerDataResponse{ + ReputerValueBundle: valueBundle, + BlockHeight: alloraBlockHeightCurrent, + BlockHeightEval: alloraBlockHeightEval, + TopicId: int64(topicId), + } + + // Serialize the workerDataBundle into json + reputerDataResponseBytes, err := json.Marshal(reputerDataResponse) + if err != nil { + fmt.Println("Error serializing WorkerDataBundle: ", err) + return result, err + } + outputJson := string(reputerDataResponseBytes) + fmt.Println("Signed OutputJson sent to consensus: ", outputJson) + result.Result.Stdout = outputJson + } + } + return result, err +} + func run() int { // Signal catching for clean shutdown. @@ -138,6 +506,7 @@ func run() int { } // If this is a worker node, initialize an executor. + var alloraExecutor *AlloraExecutor = nil if role == blockless.WorkerNode { // Executor options. @@ -175,7 +544,9 @@ func run() int { return failure } - opts = append(opts, node.WithExecutor(executor)) + alloraExecutor = NewAlloraExecutor(executor) + + opts = append(opts, node.WithExecutor(alloraExecutor)) opts = append(opts, node.WithWorkspace(cfg.Workspace)) } @@ -197,42 +568,68 @@ func run() int { opts = append(opts, node.WithTopics(cfg.Topics)) } + var appchain *AppChain = nil + if role == blockless.WorkerNode { + cfg.AppChainConfig.NodeRole = role + cfg.AppChainConfig.AddressPrefix = "allo" + cfg.AppChainConfig.StringSeperator = "|" + cfg.AppChainConfig.LibP2PKey = host.ID().String() + cfg.AppChainConfig.MultiAddress = host.Addresses()[0] + appchain, err = connectToAlloraBlockchain(cfg.AppChainConfig, log) + if alloraExecutor != nil { + alloraExecutor.appChain = appchain + } + + if cfg.AppChainConfig.ReconnectSeconds > 0 { + go func(executor *AlloraExecutor) { + ticker := time.NewTicker(time.Second * time.Duration(math.Max(1, math.Min(float64(cfg.AppChainConfig.ReconnectSeconds), 3600)))) + defer ticker.Stop() + + for range ticker.C { + if appchain == nil || !appchain.Config.SubmitTx { + log.Debug().Uint64("reconnectSeconds", cfg.AppChainConfig.ReconnectSeconds).Msg("Attempt reconnection to allora blockchain") + appchain, err = connectToAlloraBlockchain(cfg.AppChainConfig, log) + if err != nil { + log.Debug().Msg("Failed to connect to allora blockchain") + } else { + log.Debug().Msg("Resetting up chain connection.") + if alloraExecutor != nil { + executor.appChain = appchain + } else { + log.Warn().Msg("No valid alloraExecutor with which to associate chain client.") + } + } + } + } + }(alloraExecutor) // Pass alloraExecutor as an argument to the goroutine + } + } + + var resLoc sync.RWMutex + response := func(msg []byte) { + resLoc.Lock() + var data node.ChanData + msgerr := json.Unmarshal(msg, &data) + if msgerr == nil { + sendResultsToChain(log, appchain, data) + } else { + log.Error().Err(msgerr).Msg("Unable to unmarshall") + } + resLoc.Unlock() + } // Instantiate node. - node, err := node.New(log, host, peerstore, fstore, opts...) + node, err := node.New(log, host, peerstore, fstore, response, opts...) if err != nil { log.Error().Err(err).Msg("could not create node") return failure } - // Create the main context. - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() + ctx, rcancel := context.WithCancel(context.Background()) + defer rcancel() done := make(chan struct{}) failed := make(chan struct{}) - var appchain *AppChain = nil - cfg.AppChainConfig.NodeRole = role - cfg.AppChainConfig.AddressPrefix = "allo" - cfg.AppChainConfig.StringSeperator = "|" - cfg.AppChainConfig.LibP2PKey = host.ID().String() - cfg.AppChainConfig.MultiAddress = host.Addresses()[0] - appchain, err = connectToAlloraBlockchain(cfg.AppChainConfig, log) - - if cfg.AppChainConfig.ReconnectSeconds > 0 { - go func() { - ticker := time.NewTicker(time.Second * time.Duration(math.Max(1, math.Min(float64(cfg.AppChainConfig.ReconnectSeconds), 3600)))) - defer ticker.Stop() - - for range ticker.C { - if appchain == nil || !appchain.Config.SubmitTx { - log.Debug().Uint64("reconnectSeconds", cfg.AppChainConfig.ReconnectSeconds).Msg("Attempt reconnection to allora blockchain") - appchain, err = connectToAlloraBlockchain(cfg.AppChainConfig, log) - } - } - }() - } - // Start node main loop in a separate goroutine. go func() { @@ -259,7 +656,7 @@ func run() int { return failure } - // Create echo server and iniialize logging. + // Create echo server and initialize logging. server := echo.New() server.HideBanner = true server.HidePort = true @@ -273,7 +670,7 @@ func run() int { // Set endpoint handlers. server.GET("/api/v1/health", api.Health) - server.POST("/api/v1/functions/execute", createExecutor(*api, appchain)) + server.POST("/api/v1/functions/execute", createExecutor(*api)) server.POST("/api/v1/functions/install", api.Install) server.POST("/api/v1/functions/requests/result", api.ExecutionResult) diff --git a/cmd/node/role.go b/cmd/node/role.go index 6046104..5bd9156 100644 --- a/cmd/node/role.go +++ b/cmd/node/role.go @@ -3,7 +3,7 @@ package main import ( "errors" - "github.com/blocklessnetwork/b7s/models/blockless" + "github.com/allora-network/b7s/models/blockless" ) func parseNodeRole(role string) (blockless.NodeRole, error) { diff --git a/cmd/node/types.go b/cmd/node/types.go index 7f5e596..b4536f0 100644 --- a/cmd/node/types.go +++ b/cmd/node/types.go @@ -1,9 +1,9 @@ package main import ( - types "github.com/allora-network/allora-chain/x/emissions" - "github.com/blocklessnetwork/b7s/config" - "github.com/blocklessnetwork/b7s/models/blockless" + "github.com/allora-network/allora-chain/x/emissions/types" + "github.com/allora-network/b7s/config" + "github.com/allora-network/b7s/models/blockless" "github.com/ignite/cli/v28/ignite/pkg/cosmosaccount" "github.com/ignite/cli/v28/ignite/pkg/cosmosclient" "github.com/rs/zerolog" @@ -15,13 +15,12 @@ type alloraCfg struct { } type AppChain struct { - ReputerAddress string - ReputerAccount cosmosaccount.Account - Client *cosmosclient.Client - QueryClient types.QueryClient - WorkersAddress map[string]string - Config AppChainConfig - Logger zerolog.Logger + Address string + Account cosmosaccount.Account + Client *cosmosclient.Client + QueryClient types.QueryClient + Config AppChainConfig + Logger zerolog.Logger } type AppChainConfig struct { @@ -37,34 +36,62 @@ type AppChainConfig struct { MultiAddress string TopicIds []string NodeRole blockless.NodeRole - ReconnectSeconds uint64 // seconds to wait for reconnection - InitialStake uint64 // uallo to initially stake upon registration on a new topi + ReconnectSeconds uint64 // seconds to wait for reconnection + InitialStake int64 // uallo to initially stake upon registration on a new topi + WorkerMode string // Allora Network worker mode to use + Gas string // gas to use for the allora client + GasAdjustment float64 // gas adjustment to use for the allora client } -type WeightsResponse struct { - Value string `json:"value"` +type NodeValue struct { + Worker string `json:"worker,omitempty"` + Value string `json:"value,omitempty"` } -type WorkerWeights struct { - Type string `json:"type"` - Weights map[string]string `json:"weights"` +// WORKER +type InferenceForecastResponse struct { + InfererValue string `json:"infererValue,omitempty"` + ForecasterValues []NodeValue `json:"forecasterValue,omitempty"` } -type WeightsCalcDependencies struct { - LatestWeights map[string]float64 - ActualPrice float64 +type WorkerDataResponse struct { + *types.WorkerDataBundle + BlockHeight int64 `json:"blockHeight,omitempty"` + TopicId int64 `json:"topicId,omitempty"` } -type ResponseInfo struct { - FunctionType string `json:"type"` +// REPUTER +// Local struct to hold the value bundle from the wasm function response +type ValueBundle struct { + CombinedValue string `json:"combinedValue,omitempty"` + NaiveValue string `json:"naiveValue,omitempty"` + InfererValues []NodeValue `json:"infererValues,omitempty"` + ForecasterValues []NodeValue `json:"forecasterValues,omitempty"` + OneOutInfererValues []NodeValue `json:"oneOutInfererValues,omitempty"` + OneOutForecasterValues []NodeValue `json:"oneOutForecasterValues,omitempty"` + OneInForecasterValues []NodeValue `json:"oneInForecasterValues,omitempty"` } -type Response struct { +// Wrapper around the ReputerValueBundle to include the block height and topic id for the leader +type ReputerDataResponse struct { + *types.ReputerValueBundle + BlockHeight int64 `json:"blockHeight,omitempty"` + BlockHeightEval int64 `json:"blockHeightEval,omitempty"` + TopicId int64 `json:"topicId,omitempty"` +} + +type ReputerWASMResponse struct { Value string `json:"value,omitempty"` - Error string `json:"error,omitempty"` } -var ( - inferenceType = "inferences" - weightsType = "weights" +const ( + WorkerModeWorker = "worker" + WorkerModeReputer = "reputer" ) + +type AlloraExecutor struct { + blockless.Executor + appChain *AppChain +} + +const AlloraExponential = 18 diff --git a/docker/Dockerfile_head b/docker/Dockerfile_head index eea39af..7921102 100644 --- a/docker/Dockerfile_head +++ b/docker/Dockerfile_head @@ -1,10 +1,9 @@ -FROM golang:1.21-bookworm AS builder +FROM golang:1.22-bookworm AS builder ADD . /src WORKDIR /src ARG GH_TOKEN RUN git config --global url."https://${GH_TOKEN}@github.com".insteadOf "https://github.com" -ENV GOPRIVATE="github.com/allora-network/" RUN go mod download && \ go mod tidy && \ diff --git a/docker/Dockerfile_worker b/docker/Dockerfile_worker index b98a15e..080696d 100644 --- a/docker/Dockerfile_worker +++ b/docker/Dockerfile_worker @@ -1,10 +1,9 @@ -FROM golang:1.21-bookworm AS builder +FROM golang:1.22-bookworm AS builder ADD . /src WORKDIR /src ARG GH_TOKEN RUN git config --global url."https://${GH_TOKEN}@github.com".insteadOf "https://github.com" -ENV GOPRIVATE="github.com/allora-network/" RUN go mod download && \ go mod tidy && \ @@ -72,9 +71,9 @@ RUN if [ -n $BLS_EXTENSION_VER]; then \ COPY --from=builder /src/dist/allora-node /usr/local/bin/allora-node COPY --from=builder /src/dist/allora-keys /usr/local/bin/allora-keys -# Smoke test -RUN /app/runtime/bls-runtime --help && \ - /app/runtime/extensions/allora-inference-extension --help +# # Smoke test +# RUN /app/runtime/bls-runtime --help && \ +# /app/runtime/extensions/allora-inference-extension --help RUN groupadd -g 1001 ${USERNAME} \ && useradd -m -d ${APP_PATH} -u 1001 -g 1001 ${USERNAME} \ diff --git a/docker/Dockerfile_worker_py3.9 b/docker/Dockerfile_worker_py3.9 index 7f244b9..1d0eb17 100644 --- a/docker/Dockerfile_worker_py3.9 +++ b/docker/Dockerfile_worker_py3.9 @@ -1,10 +1,9 @@ -FROM golang:1.21-bookworm AS builder +FROM golang:1.22-bookworm AS builder ADD . /src WORKDIR /src ARG GH_TOKEN RUN git config --global url."https://${GH_TOKEN}@github.com".insteadOf "https://github.com" -ENV GOPRIVATE="github.com/allora-network/" RUN go mod download && \ go mod tidy && \ diff --git a/go.mod b/go.mod index dd72797..badef31 100644 --- a/go.mod +++ b/go.mod @@ -1,30 +1,38 @@ module github.com/allora-network/allora-inference-base -go 1.21.1 - -toolchain go1.21.5 +go 1.22.2 require ( - cosmossdk.io/math v1.2.0 - github.com/allora-network/allora-chain v0.0.4-0.20240306064310-0611ec300dd0 - github.com/cockroachdb/pebble v1.0.0 - github.com/cosmos/cosmos-sdk v0.50.3 - github.com/ignite/cli/v28 v28.1.1 + cosmossdk.io/math v1.3.0 + github.com/allora-network/allora-chain v0.2.1-dev + github.com/allora-network/b7s v0.0.2-0.20240418175046-eca9bfd68831 + github.com/cockroachdb/pebble v1.1.0 + github.com/cosmos/cosmos-sdk v0.50.5 + github.com/ignite/cli/v28 v28.3.0 github.com/labstack/echo/v4 v4.11.4 github.com/libp2p/go-libp2p v0.32.2 github.com/multiformats/go-multiaddr v0.12.2 github.com/spf13/pflag v1.0.5 + github.com/ziflex/lecho/v3 v3.5.0 +) + +require ( + github.com/blocklessnetwork/b7s-attributes v0.0.0 // indirect + github.com/cockroachdb/apd/v3 v3.2.1 // indirect + github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect + github.com/golang-jwt/jwt v3.2.2+incompatible // indirect + golang.org/x/time v0.5.0 // indirect ) require ( - cosmossdk.io/api v0.7.2 // indirect + cosmossdk.io/api v0.7.3 // indirect cosmossdk.io/collections v0.4.0 // indirect cosmossdk.io/core v0.11.0 // indirect cosmossdk.io/depinject v1.0.0-alpha.4 // indirect cosmossdk.io/errors v1.0.1 // indirect - cosmossdk.io/log v1.3.0 // indirect + cosmossdk.io/log v1.3.1 // indirect cosmossdk.io/store v1.0.2 // indirect - cosmossdk.io/x/tx v0.13.0 // indirect + cosmossdk.io/x/tx v0.13.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect @@ -37,7 +45,7 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/blang/semver/v4 v4.0.0 // indirect - github.com/blocklessnetwork/b7s-attributes v0.0.0 // indirect + //github.com/blocklessnetwork/b7s-attributes v0.0.0 // indirect github.com/boltdb/bolt v1.3.1 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/cavaliergopher/grab/v3 v3.0.1 // indirect @@ -49,20 +57,20 @@ require ( github.com/cockroachdb/errors v1.11.1 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/redact v1.1.5 // indirect - github.com/cometbft/cometbft v0.38.3 // indirect + github.com/cometbft/cometbft v0.38.6 // indirect github.com/cometbft/cometbft-db v0.9.1 // indirect github.com/containerd/cgroups v1.1.0 // indirect github.com/containerd/cgroups/v3 v3.0.3 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect - github.com/cosmos/cosmos-db v1.0.0 // indirect - github.com/cosmos/cosmos-proto v1.0.0-beta.3 // indirect + github.com/cosmos/cosmos-db v1.0.2 // indirect + github.com/cosmos/cosmos-proto v1.0.0-beta.4 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/gogoproto v1.4.11 // indirect - github.com/cosmos/iavl v1.0.0 // indirect + github.com/cosmos/iavl v1.0.1 // indirect github.com/cosmos/ibc-go/modules/capability v1.0.0 // indirect - github.com/cosmos/ibc-go/v8 v8.0.0 // indirect + github.com/cosmos/ibc-go/v8 v8.2.0 // indirect github.com/cosmos/ics23/go v0.10.0 // indirect github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect github.com/danieljoos/wincred v1.2.1 // indirect @@ -83,7 +91,7 @@ require ( github.com/flynn/noise v1.1.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/getsentry/sentry-go v0.26.0 // indirect + github.com/getsentry/sentry-go v0.27.0 // indirect github.com/go-kit/kit v0.13.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect @@ -94,9 +102,8 @@ require ( github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.3 // indirect - github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/golang/glog v1.2.0 // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.1.2 // indirect github.com/google/go-cmp v0.6.0 // indirect @@ -138,7 +145,7 @@ require ( github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect github.com/jbenet/goprocess v0.1.4 // indirect github.com/jmhodges/levigo v1.0.0 // indirect - github.com/klauspost/compress v1.17.5 // indirect + github.com/klauspost/compress v1.17.7 // indirect github.com/klauspost/cpuid/v2 v2.2.6 // indirect github.com/koron/go-ssdp v0.0.4 // indirect github.com/kr/pretty v0.3.1 // indirect @@ -160,7 +167,7 @@ require ( github.com/libp2p/go-netroute v0.2.1 // indirect github.com/libp2p/go-reuseport v0.4.0 // indirect github.com/libp2p/go-yamux/v4 v4.0.1 // indirect - github.com/linxGnu/grocksdb v1.8.11 // indirect + github.com/linxGnu/grocksdb v1.8.12 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect github.com/miekg/dns v1.1.58 // indirect @@ -192,8 +199,8 @@ require ( github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/polydawn/refmt v0.89.0 // indirect github.com/prometheus/client_golang v1.18.0 // indirect - github.com/prometheus/client_model v0.5.0 // indirect - github.com/prometheus/common v0.46.0 // indirect + github.com/prometheus/client_model v0.6.0 // indirect + github.com/prometheus/common v0.47.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/quic-go v0.41.0 // indirect @@ -212,7 +219,7 @@ require ( github.com/spf13/cast v1.6.0 // indirect github.com/spf13/cobra v1.8.0 // indirect github.com/spf13/viper v1.18.2 // indirect - github.com/stretchr/testify v1.8.4 // indirect + github.com/stretchr/testify v1.9.0 github.com/subosito/gotenv v1.6.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tendermint/go-amino v0.16.0 // indirect @@ -231,18 +238,17 @@ require ( go.uber.org/mock v0.4.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect - golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect - golang.org/x/mod v0.14.0 // indirect + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect + golang.org/x/mod v0.15.0 // indirect golang.org/x/sync v0.6.0 // indirect - golang.org/x/term v0.16.0 // indirect - golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.17.0 // indirect + golang.org/x/term v0.17.0 // indirect + golang.org/x/tools v0.18.0 // indirect gonum.org/v1/gonum v0.14.0 // indirect - google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect - google.golang.org/grpc v1.60.1 // indirect - google.golang.org/protobuf v1.32.0 // indirect + google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/grpc v1.63.2 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect @@ -254,17 +260,15 @@ require ( ) require ( - github.com/blocklessnetwork/b7s v0.4.9 github.com/labstack/gommon v0.4.2 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/rs/zerolog v1.31.0 + github.com/rs/zerolog v1.32.0 github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect - github.com/ziflex/lecho/v3 v3.5.0 - golang.org/x/crypto v0.18.0 // indirect - golang.org/x/net v0.20.0 // indirect - golang.org/x/sys v0.16.0 // indirect + golang.org/x/crypto v0.19.0 // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/sys v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect ) diff --git a/go.sum b/go.sum index 43c366b..576bd0b 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= -cosmossdk.io/api v0.7.2 h1:BO3i5fvKMKvfaUiMkCznxViuBEfyWA/k6w2eAF6q1C4= -cosmossdk.io/api v0.7.2/go.mod h1:IcxpYS5fMemZGqyYtErK7OqvdM0C8kdW3dq8Q/XIG38= +cosmossdk.io/api v0.7.3 h1:V815i8YOwOAQa1rLCsSMjVG5Gnzs02JLq+l7ks8s1jk= +cosmossdk.io/api v0.7.3/go.mod h1:IcxpYS5fMemZGqyYtErK7OqvdM0C8kdW3dq8Q/XIG38= cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s= cosmossdk.io/collections v0.4.0/go.mod h1:oa5lUING2dP+gdDquow+QjlF45eL1t4TJDypgGd+tv0= cosmossdk.io/core v0.11.0 h1:vtIafqUi+1ZNAE/oxLOQQ7Oek2n4S48SWLG8h/+wdbo= @@ -12,16 +12,16 @@ cosmossdk.io/depinject v1.0.0-alpha.4 h1:PLNp8ZYAMPTUKyG9IK2hsbciDWqna2z1Wsl98ok cosmossdk.io/depinject v1.0.0-alpha.4/go.mod h1:HeDk7IkR5ckZ3lMGs/o91AVUc7E596vMaOmslGFM3yU= cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= cosmossdk.io/errors v1.0.1/go.mod h1:MeelVSZThMi4bEakzhhhE/CKqVv3nOJDA25bIqRDu/U= -cosmossdk.io/log v1.3.0 h1:L0Z0XstClo2kOU4h3V1iDoE5Ji64sg5HLOogzGg67Oo= -cosmossdk.io/log v1.3.0/go.mod h1:HIDyvWLqZe2ovlWabsDN4aPMpY/nUEquAhgfTf2ZzB8= -cosmossdk.io/math v1.2.0 h1:8gudhTkkD3NxOP2YyyJIYYmt6dQ55ZfJkDOaxXpy7Ig= -cosmossdk.io/math v1.2.0/go.mod h1:l2Gnda87F0su8a/7FEKJfFdJrM0JZRXQaohlgJeyQh0= +cosmossdk.io/log v1.3.1 h1:UZx8nWIkfbbNEWusZqzAx3ZGvu54TZacWib3EzUYmGI= +cosmossdk.io/log v1.3.1/go.mod h1:2/dIomt8mKdk6vl3OWJcPk2be3pGOS8OQaLUM/3/tCM= +cosmossdk.io/math v1.3.0 h1:RC+jryuKeytIiictDslBP9i1fhkVm6ZDmZEoNP316zE= +cosmossdk.io/math v1.3.0/go.mod h1:vnRTxewy+M7BtXBNFybkuhSH4WfedVAAnERHgVFhp3k= cosmossdk.io/store v1.0.2 h1:lSg5BTvJBHUDwswNNyeh4K/CbqiHER73VU4nDNb8uk0= cosmossdk.io/store v1.0.2/go.mod h1:EFtENTqVTuWwitGW1VwaBct+yDagk7oG/axBMPH+FXs= -cosmossdk.io/x/tx v0.13.0 h1:8lzyOh3zONPpZv2uTcUmsv0WTXy6T1/aCVDCqShmpzU= -cosmossdk.io/x/tx v0.13.0/go.mod h1:CpNQtmoqbXa33/DVxWQNx5Dcnbkv2xGUhL7tYQ5wUsY= -cosmossdk.io/x/upgrade v0.1.0 h1:z1ZZG4UL9ICTNbJDYZ6jOnF9GdEK9wyoEFi4BUScHXE= -cosmossdk.io/x/upgrade v0.1.0/go.mod h1:/6jjNGbiPCNtmA1N+rBtP601sr0g4ZXuj3yC6ClPCGY= +cosmossdk.io/x/tx v0.13.1 h1:Mg+EMp67Pz+NukbJqYxuo8uRp7N/a9uR+oVS9pONtj8= +cosmossdk.io/x/tx v0.13.1/go.mod h1:CBCU6fsRVz23QGFIQBb1DNX2DztJCf3jWyEkHY2nJQ0= +cosmossdk.io/x/upgrade v0.1.1 h1:aoPe2gNvH+Gwt/Pgq3dOxxQVU3j5P6Xf+DaUJTDZATc= +cosmossdk.io/x/upgrade v0.1.1/go.mod h1:MNLptLPcIFK9CWt7Ra//8WUZAxweyRDNcbs5nkOcQy0= dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= @@ -57,10 +57,14 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/allora-network/allora-chain v0.0.1-0.20240223163905-f4ccc6195d82 h1:Xa7U+AEzvJC3mgaW02xO2SACIEwGTc1Lfb8XSAnmd5M= -github.com/allora-network/allora-chain v0.0.1-0.20240223163905-f4ccc6195d82/go.mod h1:n/uJmsa0D44UH5bDt+9w8tClIw5wj9P78x35sslefIQ= -github.com/allora-network/allora-chain v0.0.4-0.20240306064310-0611ec300dd0 h1:IzVv+xGjGmXuuvOU6A8UFEqADmeWDaL/pR2fnaE8kgs= -github.com/allora-network/allora-chain v0.0.4-0.20240306064310-0611ec300dd0/go.mod h1:n/uJmsa0D44UH5bDt+9w8tClIw5wj9P78x35sslefIQ= +github.com/allora-network/allora-chain v0.1.0-dev.a53b6d4.0.20240526151956-574b2f09d09e h1:8SQlhMZDDPm51KqDiGu5GEU/ZhYA+ZAgWOegfrxmiOI= +github.com/allora-network/allora-chain v0.1.0-dev.a53b6d4.0.20240526151956-574b2f09d09e/go.mod h1:7UrL7qr/wLTnBBfTGZHHui9tjDfx89FvDj22YD2TVow= +github.com/allora-network/allora-chain v0.1.0-dev.a53b6d4.0.20240530034517-701b22338ce3 h1:udZYnIlglfhJ4zJNsMyl/fXJxie3vWrfdP04zIOyPXg= +github.com/allora-network/allora-chain v0.1.0-dev.a53b6d4.0.20240530034517-701b22338ce3/go.mod h1:7UrL7qr/wLTnBBfTGZHHui9tjDfx89FvDj22YD2TVow= +github.com/allora-network/allora-chain v0.2.1-dev h1:Cjq86Va8WEr7Hixw52BR3nO8vwEfmk8ndOd++Jm7fWE= +github.com/allora-network/allora-chain v0.2.1-dev/go.mod h1:7UrL7qr/wLTnBBfTGZHHui9tjDfx89FvDj22YD2TVow= +github.com/allora-network/b7s v0.0.2-0.20240418175046-eca9bfd68831 h1:4s9e1sjeHlqG4SWoV29vcf/WGX9KeATx1V38X4k2f+I= +github.com/allora-network/b7s v0.0.2-0.20240418175046-eca9bfd68831/go.mod h1:rJJrdC5Y83LEDFxo/iJp3JJpi8I6TJncOTigMWk8ieE= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= @@ -92,8 +96,6 @@ github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5M github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/blocklessnetwork/b7s v0.4.9 h1:bHgOm6zxvsP9+sPxfaAf15TMA5OEOj3U9PEUEJ/RA9Q= -github.com/blocklessnetwork/b7s v0.4.9/go.mod h1:ctN87vLjhddWpFR3yiWA23Gr34lxLBMcwZDmVH81jr0= github.com/blocklessnetwork/b7s-attributes v0.0.0 h1:GoJmJpZVZOLjCE52jmTzfQLy2VAWdOuCdcrvct0HyC8= github.com/blocklessnetwork/b7s-attributes v0.0.0/go.mod h1:0c+ZemB4kfylI14IERH4CSUslZtKcQIuVHk8L4DiLI8= github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= @@ -141,20 +143,24 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= +github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/cockroachdb/datadriven v1.0.3-0.20230801171734-e384cf455877 h1:1MLK4YpFtIEo3ZtMA5C795Wtv5VuUnrXX7mQG+aHg6o= -github.com/cockroachdb/datadriven v1.0.3-0.20230801171734-e384cf455877/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= +github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8= github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= -github.com/cockroachdb/pebble v1.0.0 h1:WZWlV/s78glZbY2ylUITDOWSVBD3cLjcWPLRPFbHNYg= -github.com/cockroachdb/pebble v1.0.0/go.mod h1:bynZ3gvVyhlvjLI7PT6dmZ7g76xzJ7HpxfjgkzCGz6s= +github.com/cockroachdb/pebble v1.1.0 h1:pcFh8CdCIt2kmEpK0OIatq67Ln9uGDYY3d5XnE0LJG4= +github.com/cockroachdb/pebble v1.1.0/go.mod h1:sEHm5NOXxyiAoKWhoFxT8xMgd/f3RA6qUqQ1BXKrh2E= github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/cometbft/cometbft v0.38.3 h1:9siuLEzayytYvRdPBhdrV52xcmAgZLj/BNuqTZ9vezg= -github.com/cometbft/cometbft v0.38.3/go.mod h1:kyyCNpl66hAJkiKHJzCYCwrCnZuTWqYDqhP5JPHT4FM= +github.com/cometbft/cometbft v0.38.6 h1:QSgpCzrGWJ2KUq1qpw+FCfASRpE27T6LQbfEHscdyOk= +github.com/cometbft/cometbft v0.38.6/go.mod h1:8rSPxzUJYquCN8uuBgbUHOMg2KAwvr7CyUw+6ukO4nw= github.com/cometbft/cometbft-db v0.9.1 h1:MIhVX5ja5bXNHF8EYrThkG9F7r9kSfv8BX4LWaxWJ4M= github.com/cometbft/cometbft-db v0.9.1/go.mod h1:iliyWaoV0mRwBJoizElCwwRA9Tf7jZJOURcRZF9m60U= github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= @@ -173,12 +179,12 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk= github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis= -github.com/cosmos/cosmos-db v1.0.0 h1:EVcQZ+qYag7W6uorBKFPvX6gRjw6Uq2hIh4hCWjuQ0E= -github.com/cosmos/cosmos-db v1.0.0/go.mod h1:iBvi1TtqaedwLdcrZVYRSSCb6eSy61NLj4UNmdIgs0U= -github.com/cosmos/cosmos-proto v1.0.0-beta.3 h1:VitvZ1lPORTVxkmF2fAp3IiA61xVwArQYKXTdEcpW6o= -github.com/cosmos/cosmos-proto v1.0.0-beta.3/go.mod h1:t8IASdLaAq+bbHbjq4p960BvcTqtwuAxid3b/2rOD6I= -github.com/cosmos/cosmos-sdk v0.50.3 h1:zP0AXm54ws2t2qVWvcQhEYVafhOAREU2QL0gnbwjvXw= -github.com/cosmos/cosmos-sdk v0.50.3/go.mod h1:tlrkY1sntOt1q0OX/rqF0zRJtmXNoffAS6VFTcky+w8= +github.com/cosmos/cosmos-db v1.0.2 h1:hwMjozuY1OlJs/uh6vddqnk9j7VamLv+0DBlbEXbAKs= +github.com/cosmos/cosmos-db v1.0.2/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= +github.com/cosmos/cosmos-proto v1.0.0-beta.4 h1:aEL7tU/rLOmxZQ9z4i7mzxcLbSCY48OdY7lIWTLG7oU= +github.com/cosmos/cosmos-proto v1.0.0-beta.4/go.mod h1:oeB+FyVzG3XrQJbJng0EnV8Vljfk9XvTIpGILNU/9Co= +github.com/cosmos/cosmos-sdk v0.50.5 h1:MOEi+DKYgW67YaPgB+Pf+nHbD3V9S/ayitRKJYLfGIA= +github.com/cosmos/cosmos-sdk v0.50.5/go.mod h1:oV/k6GJgXV9QPoM2fsYDPPsyPBgQbdotv532O6Mz1OQ= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= @@ -186,12 +192,12 @@ github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU= github.com/cosmos/gogoproto v1.4.11 h1:LZcMHrx4FjUgrqQSWeaGC1v/TeuVFqSLa43CC6aWR2g= github.com/cosmos/gogoproto v1.4.11/go.mod h1:/g39Mh8m17X8Q/GDEs5zYTSNaNnInBSohtaxzQnYq1Y= -github.com/cosmos/iavl v1.0.0 h1:bw6t0Mv/mVCJvlMTOPHWLs5uUE3BRBfVWCRelOzl+so= -github.com/cosmos/iavl v1.0.0/go.mod h1:CmTGqMnRnucjxbjduneZXT+0vPgNElYvdefjX2q9tYc= +github.com/cosmos/iavl v1.0.1 h1:D+mYbcRO2wptYzOM1Hxl9cpmmHU1ZEt9T2Wv5nZTeUw= +github.com/cosmos/iavl v1.0.1/go.mod h1:8xIUkgVvwvVrBu81scdPty+/Dx9GqwHnAvXz4cwF7RY= github.com/cosmos/ibc-go/modules/capability v1.0.0 h1:r/l++byFtn7jHYa09zlAdSeevo8ci1mVZNO9+V0xsLE= github.com/cosmos/ibc-go/modules/capability v1.0.0/go.mod h1:D81ZxzjZAe0ZO5ambnvn1qedsFQ8lOwtqicG6liLBco= -github.com/cosmos/ibc-go/v8 v8.0.0 h1:QKipnr/NGwc+9L7NZipURvmSIu+nw9jOIWTJuDBqOhg= -github.com/cosmos/ibc-go/v8 v8.0.0/go.mod h1:C6IiJom0F3cIQCD5fKwVPDrDK9j/xTu563AWuOmXois= +github.com/cosmos/ibc-go/v8 v8.2.0 h1:7oCzyy1sZCcgpeQLnHxC56brsSz3KWwQGKXalXwXFzE= +github.com/cosmos/ibc-go/v8 v8.2.0/go.mod h1:wj3qx75iC/XNnsMqbPDCIGs0G6Y3E/lo3bdqCyoCy+8= github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM= github.com/cosmos/ics23/go v0.10.0/go.mod h1:ZfJSmng/TBNTBkFemHHHj5YY7VAU/MBU980F4VU1NG0= github.com/cosmos/ledger-cosmos-go v0.13.3 h1:7ehuBGuyIytsXbd4MP43mLeoN2LTOEnk5nvue4rK+yM= @@ -275,8 +281,8 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/getsentry/sentry-go v0.26.0 h1:IX3++sF6/4B5JcevhdZfdKIHfyvMmAq/UnqcyT2H6mA= -github.com/getsentry/sentry-go v0.26.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= +github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= @@ -357,8 +363,8 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= @@ -494,8 +500,8 @@ github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFck github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ignite/cli/v28 v28.1.1 h1:Kj/6UdQfPBwP/MZ3TVQPpfhAhfztM7PebloN/fOHzgU= -github.com/ignite/cli/v28 v28.1.1/go.mod h1:Z73HiXgw1bJL948CiUudGOfMyiYwCnwkcjcRs/Td/pk= +github.com/ignite/cli/v28 v28.3.0 h1:UpazVPeANrNPI0K5g9kLRivtWl43L3b454hvs8Wf6Os= +github.com/ignite/cli/v28 v28.3.0/go.mod h1:64+GF1iHSCehhQuZ74wsDUO9gnLR17EJAk70+YMgHGU= github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= @@ -549,8 +555,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.17.5 h1:d4vBd+7CHydUqpFBgUEKkSdtSugf9YFmSkvUYPquI5E= -github.com/klauspost/compress v1.17.5/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= +github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -612,8 +618,8 @@ github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCy github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= -github.com/linxGnu/grocksdb v1.8.11 h1:BGol9e5gB1BrsTvOxloC88pe70TCqgrfLNwkyWW0kD8= -github.com/linxGnu/grocksdb v1.8.11/go.mod h1:xZCIb5Muw+nhbDK4Y5UJuOrin5MceOuiXkVUR7vp4WY= +github.com/linxGnu/grocksdb v1.8.12 h1:1/pCztQUOa3BX/1gR3jSZDoaKFpeHFvQ1XrqZpSvZVo= +github.com/linxGnu/grocksdb v1.8.12/go.mod h1:xZCIb5Muw+nhbDK4Y5UJuOrin5MceOuiXkVUR7vp4WY= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -801,8 +807,8 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1: github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= +github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -810,8 +816,8 @@ github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt2 github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.46.0 h1:doXzt5ybi1HBKpsZOL0sSkaNHJJqkyfEWZGGqqScV0Y= -github.com/prometheus/common v0.46.0/go.mod h1:Tp0qkxpb9Jsg54QMe+EAmqXkSV7Evdy1BTn+g2pa/hQ= +github.com/prometheus/common v0.47.0 h1:p5Cz0FNHo7SnWOmWmoRozVcjEp0bIVU8cV7OShpjL1k= +github.com/prometheus/common v0.47.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -844,8 +850,8 @@ github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A= -github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= +github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -928,8 +934,9 @@ github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5J github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -940,8 +947,9 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= @@ -1047,13 +1055,13 @@ golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA= -golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= +golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1070,8 +1078,8 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= -golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1106,8 +1114,8 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1185,12 +1193,12 @@ golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= -golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -1226,8 +1234,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= -golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= +golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1258,12 +1266,12 @@ google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac h1:ZL/Teoy/ZGnzyrqK/Optxxp2pmVh+fmJ97slxSRyzUg= -google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:+Rvu7ElI+aLzyDQhpHMFMMltsD6m7nqpuWDd2CwJw3k= -google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac h1:OZkkudMUu9LVQMCoRUbI/1p5VCo9BOrlvkqMvWtqa6s= -google.golang.org/genproto/googleapis/api v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac h1:nUQEQmH/csSvFECKYRv6HWEyypysidKl2I6Qpsglq/0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -1285,8 +1293,8 @@ google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= -google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= +google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= +google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1301,8 +1309,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=