diff --git a/Dockerfile b/Dockerfile index ce922af..ecb46d4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,4 +8,4 @@ RUN go mod download COPY . . RUN make build -RUN bats -T --print-output-on-failure --verbose-run tests +RUN bats -T --print-output-on-failure tests diff --git a/Dockerfile.kyve b/Dockerfile.kyve deleted file mode 100644 index e69de29..0000000 diff --git a/app/app.go b/app/app.go new file mode 100644 index 0000000..20dc88d --- /dev/null +++ b/app/app.go @@ -0,0 +1,489 @@ +package app + +import ( + "fmt" + "github.com/KYVENetwork/ksync/app/genesis" + "github.com/KYVENetwork/ksync/app/source" + "github.com/KYVENetwork/ksync/engines/celestia-core-v34" + "github.com/KYVENetwork/ksync/engines/cometbft-v37" + "github.com/KYVENetwork/ksync/engines/cometbft-v38" + "github.com/KYVENetwork/ksync/engines/tendermint-v34" + "github.com/KYVENetwork/ksync/flags" + "github.com/KYVENetwork/ksync/logger" + "github.com/KYVENetwork/ksync/metrics" + "github.com/KYVENetwork/ksync/types" + "github.com/KYVENetwork/ksync/utils" + "os" + "os/exec" + "strconv" + "strings" + "syscall" + "time" +) + +type CosmosApp struct { + binaryPath string + isCosmovisor bool + homePath string + chainRest string + + cmd *exec.Cmd + + Genesis *genesis.Genesis + Source *source.Source + ConsensusEngine types.Engine +} + +func NewCosmosApp() (*CosmosApp, error) { + app := &CosmosApp{} + + if err := app.LoadBinaryPath(); err != nil { + return nil, fmt.Errorf("failed to load binary path: %w", err) + } + + if err := app.LoadHomePath(); err != nil { + return nil, fmt.Errorf("failed to load home path from binary: %w", err) + } + + if err := app.LoadChainRest(); err != nil { + return nil, fmt.Errorf("failed to load chain rest endpoint: %w", err) + } + + if err := app.LoadConsensusEngine(); err != nil { + return nil, fmt.Errorf("failed to load consensus engine from binary: %w", err) + } + + appGenesis, err := genesis.NewGenesis(app.GetHomePath()) + if err != nil { + return nil, fmt.Errorf("failed to init genesis: %w", err) + } + + app.Genesis = appGenesis + + appSource, err := source.NewSource(app.Genesis.GetChainId()) + if err != nil { + return nil, fmt.Errorf("failed to init source: %w", err) + } + + app.Source = appSource + + return app, nil +} + +func (app *CosmosApp) GetBinaryPath() string { + return app.binaryPath +} + +func (app *CosmosApp) GetHomePath() string { + return app.homePath +} + +func (app *CosmosApp) GetChainRest() string { + return app.chainRest +} + +func (app *CosmosApp) IsCosmovisor() bool { + return app.isCosmovisor +} + +func (app *CosmosApp) IsReset() bool { + return app.ConsensusEngine.GetHeight() == 0 +} + +func (app *CosmosApp) GetContinuationHeight() int64 { + height := app.ConsensusEngine.GetHeight() + 1 + if height == 1 { + return app.Genesis.GetInitialHeight() + } + + return height +} + +func (app *CosmosApp) AutoSelectBinaryVersion(height int64) error { + if !flags.AutoSelectBinaryVersion { + return nil + } + + if !app.isCosmovisor { + return fmt.Errorf("cannot auto-select version because binary is not cosmovisor") + } + + upgradeName, err := app.Source.GetUpgradeNameForHeight(height) + if err != nil { + return fmt.Errorf("failed to get upgrade name for height %d: %w", height, err) + } + + upgradePath := fmt.Sprintf("%s/cosmovisor/upgrades/%s", app.homePath, upgradeName) + if upgradeName == "genesis" { + upgradePath = fmt.Sprintf("%s/cosmovisor/genesis", app.homePath) + } + + if _, err := os.Stat(upgradePath); err != nil { + return fmt.Errorf("upgrade \"%s\" not installed in cosmovisor", upgradeName) + } + + symlinkPath := fmt.Sprintf("%s/cosmovisor/current", app.homePath) + + if _, err := os.Lstat(symlinkPath); err == nil { + if err := os.Remove(symlinkPath); err != nil { + return fmt.Errorf("failed to remove symlink from path %s: %w", symlinkPath, err) + } + } + + logger.Logger.Debug().Str("upgradePath", upgradePath).Str("symlinkPath", symlinkPath).Msg("created symlink to upgrade directory") + + if err := os.Symlink(upgradePath, symlinkPath); err != nil { + return fmt.Errorf("failed to create symlink to upgrade directory: %w", err) + } + + logger.Logger.Info().Msgf("selected binary version \"%s\" from height %d for cosmovisor", upgradeName, height) + return app.LoadConsensusEngine() +} + +func (app *CosmosApp) StartAll(snapshotInterval int64) error { + // we close the dbs again before starting the actual cosmos app + // because on some versions the cosmos app accesses the blockstore.db, + // during the boot phase, although it should not do that. So if we would not + // close the dbs before starting the cosmos app binary it would panic + if err := app.ConsensusEngine.CloseDBs(); err != nil { + return fmt.Errorf("failed to close dbs in engine: %w", err) + } + + if err := app.StartBinary(snapshotInterval); err != nil { + return fmt.Errorf("failed to start app: %w", err) + } + + // we start the proxy app before opening the dbs since + // when the proxy app completes we can be sure that the + // app binary has fully booted + if err := app.ConsensusEngine.StartProxyApp(); err != nil { + return fmt.Errorf("failed to start proxy app: %w", err) + } + + if err := app.ConsensusEngine.OpenDBs(); err != nil { + return fmt.Errorf("failed to open dbs in engine: %w", err) + } + + return nil +} + +func (app *CosmosApp) StopAll() { + // we do not return on error here since we are shutting the + // application down anyway and ensure that everything else + // can get closed + if err := app.ConsensusEngine.StopProxyApp(); err != nil { + logger.Logger.Error().Msgf("failed to stop proxy app: %s", err) + } + + if err := app.ConsensusEngine.CloseDBs(); err != nil { + logger.Logger.Error().Msgf("failed to close dbs in engine: %s", err) + } + + app.StopBinary() +} + +func (app *CosmosApp) RestartAll(snapshotInterval int64) error { + app.StopAll() + return app.StartAll(snapshotInterval) +} + +func (app *CosmosApp) StartBinary(snapshotInterval int64) error { + if app.cmd != nil { + return nil + } + + cmd := exec.Command(app.binaryPath) + + if app.isCosmovisor { + cmd.Args = append(cmd.Args, "run") + cmd.Env = append(os.Environ(), "COSMOVISOR_DISABLE_LOGS=true", "UNSAFE_SKIP_BACKUP=true") + } + + cmd.Args = append(cmd.Args, "start", + "--home", + app.homePath, + "--with-tendermint=false", + "--address", + app.ConsensusEngine.GetProxyAppAddress(), + ) + + if flags.Debug { + cmd.Args = append(cmd.Args, "--log_level", "debug") + } + + if snapshotInterval > 0 { + cmd.Args = append( + cmd.Args, + "--state-sync.snapshot-interval", + strconv.FormatInt(snapshotInterval, 10), + ) + + if flags.Pruning { + cmd.Args = append( + cmd.Args, + "--pruning", + "custom", + "--pruning-keep-recent", + strconv.FormatInt(utils.SnapshotPruningWindowFactor*snapshotInterval, 10), + "--pruning-interval", + "10", + ) + + if flags.KeepSnapshots { + cmd.Args = append( + cmd.Args, + "--state-sync.snapshot-keep-recent", + "0", + ) + } else { + cmd.Args = append( + cmd.Args, + "--state-sync.snapshot-keep-recent", + strconv.FormatInt(utils.SnapshotPruningWindowFactor, 10), + ) + } + } else { + cmd.Args = append( + cmd.Args, + "--state-sync.snapshot-keep-recent", + "0", + "--pruning", + "nothing", + ) + } + } + + cmd.Args = append(cmd.Args, strings.Split(flags.AppFlags, ",")...) + + if flags.AppLogs { + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + } + + logger.Logger.Info().Msg("starting cosmos app from provided binary") + + if err := cmd.Start(); err != nil { + return fmt.Errorf("failed to start cosmos app: %w", err) + } + + logger.Logger.Debug().Strs("args", cmd.Args).Int("processId", cmd.Process.Pid).Msg("app binary started") + + app.cmd = cmd + return nil +} + +func (app *CosmosApp) StartBinaryP2P() error { + if app.cmd != nil { + return nil + } + + cmd := exec.Command(app.binaryPath) + + if app.isCosmovisor { + cmd.Args = append(cmd.Args, "run") + cmd.Env = append(os.Environ(), "COSMOVISOR_DISABLE_LOGS=true") + } + + cmd.Args = append(cmd.Args, "start", + "--home", + app.homePath, + "--p2p.pex=false", + "--p2p.persistent_peers", + "", + "--p2p.private_peer_ids", + "", + "--p2p.unconditional_peer_ids", + "", + ) + + if flags.Debug { + cmd.Args = append(cmd.Args, "--log_level", "debug") + } + + cmd.Args = append(cmd.Args, strings.Split(flags.AppFlags, ",")...) + + if flags.AppLogs { + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + } + + logger.Logger.Info().Msg("starting cosmos app from provided binary in p2p mode") + + if err := cmd.Start(); err != nil { + return fmt.Errorf("failed to start cosmos app: %w", err) + } + + logger.Logger.Debug().Strs("args", cmd.Args).Int("processId", cmd.Process.Pid).Msg("app binary started") + + app.cmd = cmd + return nil +} + +func (app *CosmosApp) StopBinary() { + if app.cmd == nil { + return + } + + // if KSYNC received an interrupt we can be sure that the subprocess + // received it too so we don't need to stop it + if metrics.GetInterrupt() { + return + } + + // ensure that we don't stop any other process in the goroutine below + // after this method returns + pId := app.cmd.Process.Pid + logger.Logger.Debug().Int("processId", pId).Msg("stopping app binary") + + defer func() { + app.cmd = nil + }() + + // we try multiple times to send a SIGTERM signal to the app because + // not every time the app properly receives it, therefore we try until the + // app actually exits + go func() { + for app.cmd != nil && pId == app.cmd.Process.Pid { + logger.Logger.Debug().Int("processId", app.cmd.Process.Pid).Msg("sending SIGTERM signal to binary process") + _ = app.cmd.Process.Signal(syscall.SIGTERM) + time.Sleep(5 * time.Second) + } + }() + + if _, err := app.cmd.Process.Wait(); err != nil { + logger.Logger.Error().Msgf("failed to wait for process with id %d to be terminated: %s", app.cmd.Process.Pid, err) + } + + logger.Logger.Debug().Int("processId", app.cmd.Process.Pid).Msg("app binary stopped") + return +} + +func (app *CosmosApp) LoadBinaryPath() error { + binaryPath, err := exec.LookPath(flags.BinaryPath) + if err != nil { + return err + } + + app.binaryPath = binaryPath + app.isCosmovisor = strings.HasSuffix(binaryPath, "cosmovisor") + + logger.Logger.Info().Msgf("loaded cosmos app at path \"%s\" from app binary", binaryPath) + return nil +} + +func (app *CosmosApp) LoadHomePath() error { + if flags.HomePath != "" { + app.homePath = flags.HomePath + return nil + } + + cmd := exec.Command(app.binaryPath) + + if app.isCosmovisor { + cmd.Args = append(cmd.Args, "run") + cmd.Env = append(os.Environ(), "COSMOVISOR_DISABLE_LOGS=true") + } + + out, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("failed to get output of binary: %w", err) + } + + // here we search for a specific line in the binary output when simply + // executed without arguments. In the output, the default home path + // is printed, which is parsed and used by KSYNC + for _, line := range strings.Split(string(out), "\n") { + if strings.Contains(line, "--home") { + if strings.Count(line, "\"") != 2 { + return fmt.Errorf("failed to find home flag in binary output") + } + + app.homePath = strings.Split(line, "\"")[1] + logger.Logger.Info().Msgf("loaded home path \"%s\" from app binary", app.homePath) + return nil + } + } + + return fmt.Errorf("failed to find home path in binary output") +} + +func (app *CosmosApp) LoadChainRest() (err error) { + app.chainRest, err = func() (string, error) { + if flags.ChainRest != "" { + return strings.TrimSuffix(flags.ChainRest, "/"), nil + } + + switch flags.ChainId { + case utils.ChainIdMainnet: + return utils.RestEndpointMainnet, nil + case utils.ChainIdKaon: + return utils.RestEndpointKaon, nil + case utils.ChainIdKorellia: + return utils.RestEndpointKorellia, nil + default: + return "", fmt.Errorf("flag --chain-id has to be either \"%s\", \"%s\" or \"%s\"", utils.ChainIdMainnet, utils.ChainIdKaon, utils.ChainIdKorellia) + } + }() + + if err != nil { + return err + } + + logger.Logger.Info().Msgf("loaded chain rest endpoint \"%s\"", app.GetChainRest()) + return nil +} + +func (app *CosmosApp) LoadConsensusEngine() error { + // if there is already a consensus engine running we close the dbs + // before loading a new one + if app.ConsensusEngine != nil { + if err := app.ConsensusEngine.CloseDBs(); err != nil { + return fmt.Errorf("failed to close dbs in engine: %w", err) + } + } + + cmd := exec.Command(app.binaryPath) + + if app.isCosmovisor { + cmd.Args = append(cmd.Args, "run") + cmd.Env = append(os.Environ(), "COSMOVISOR_DISABLE_LOGS=true") + } + + cmd.Args = append(cmd.Args, "version", "--long") + + out, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("failed to get output of binary: %w", err) + } + + app.ConsensusEngine, err = func() (types.Engine, error) { + for _, engine := range []string{"github.com/tendermint/tendermint@v", "github.com/cometbft/cometbft@v"} { + for _, line := range strings.Split(string(out), "\n") { + if strings.Contains(line, fmt.Sprintf("- %s", engine)) { + dependency := strings.Split(strings.ReplaceAll(strings.Split(line, " => ")[len(strings.Split(line, " => "))-1], "- ", ""), "@v") + + if strings.Contains(dependency[1], "0.34.") && strings.Contains(dependency[0], "celestia-core") { + return celestia_core_v34.NewEngine(app.homePath) + } else if strings.Contains(dependency[1], "0.34.") { + return tendermint_v34.NewEngine(app.homePath) + } else if strings.Contains(dependency[1], "0.37.") { + return cometbft_v37.NewEngine(app.homePath) + } else if strings.Contains(dependency[1], "0.38.") { + return cometbft_v38.NewEngine(app.homePath) + } else { + return nil, fmt.Errorf("failed to find engine in binary dependencies") + } + } + } + } + + return nil, fmt.Errorf("failed to find engine in binary dependencies") + }() + + if err != nil { + return err + } + + logger.Logger.Info().Msgf("loaded consensus engine \"%s\" from app binary", app.ConsensusEngine.GetName()) + return nil +} diff --git a/app/collector/blocks.go b/app/collector/blocks.go new file mode 100644 index 0000000..8e65f57 --- /dev/null +++ b/app/collector/blocks.go @@ -0,0 +1,366 @@ +package collector + +import ( + "encoding/json" + "fmt" + "github.com/KYVENetwork/ksync/types" + "github.com/KYVENetwork/ksync/utils" + tmJson "github.com/tendermint/tendermint/libs/json" + "strconv" + "time" +) + +type RpcBlockCollector struct { + rpc string + blockRpcReqTimeout time.Duration + earliestAvailableHeight int64 + latestAvailableHeight int64 +} + +func NewRpcBlockCollector(rpc string, blockRpcReqTimeout int64) (*RpcBlockCollector, error) { + result, err := utils.GetFromUrl(fmt.Sprintf("%s/status", rpc)) + if err != nil { + return nil, fmt.Errorf("failed to query rpc endpoint %s: %w", rpc, err) + } + + var statusResponse types.StatusResponse + if err := tmJson.Unmarshal(result, &statusResponse); err != nil { + return nil, fmt.Errorf("failed to unmarshal rpc endpoint response: %w", err) + } + + if statusResponse.Result.SyncInfo.LatestBlockHeight == 0 { + return nil, fmt.Errorf("rpc node is empty and has not yet indexed any data") + } + + return &RpcBlockCollector{ + rpc: rpc, + blockRpcReqTimeout: time.Duration(blockRpcReqTimeout * int64(time.Millisecond)), + earliestAvailableHeight: statusResponse.Result.SyncInfo.EarliestBlockHeight, + latestAvailableHeight: statusResponse.Result.SyncInfo.LatestBlockHeight, + }, nil +} + +func (collector *RpcBlockCollector) GetEarliestAvailableHeight() int64 { + return collector.earliestAvailableHeight +} + +func (collector *RpcBlockCollector) GetLatestAvailableHeight() int64 { + return collector.latestAvailableHeight +} + +func (collector *RpcBlockCollector) GetBlock(height int64) ([]byte, error) { + blockResponse, err := utils.GetFromUrl(fmt.Sprintf("%s/block?height=%d", collector.rpc, height)) + if err != nil { + return nil, fmt.Errorf("failed to get block %d from rpc: %w", height, err) + } + + block, err := collector.extractRawBlockFromDataItemValue(blockResponse) + if err != nil { + return nil, fmt.Errorf("failed to extract block %d: %w", height, err) + } + + return block, nil +} + +func (collector *RpcBlockCollector) StreamBlocks(blockCh chan<- *types.BlockItem, errorCh chan<- error, continuationHeight, targetHeight int64) { + for { + blockResponse, err := utils.GetFromUrl(fmt.Sprintf("%s/block?height=%d", collector.rpc, continuationHeight)) + if err != nil { + errorCh <- fmt.Errorf("failed to get block %d from rpc: %w", continuationHeight, err) + return + } + + block, err := collector.extractRawBlockFromDataItemValue(blockResponse) + if err != nil { + errorCh <- fmt.Errorf("failed to extract block %d: %w", continuationHeight, err) + return + } + + blockCh <- &types.BlockItem{ + Height: continuationHeight, + Block: block, + } + + if targetHeight > 0 && continuationHeight >= targetHeight+1 { + break + } + + continuationHeight++ + time.Sleep(collector.blockRpcReqTimeout) + } +} + +func (collector *RpcBlockCollector) extractRawBlockFromDataItemValue(value []byte) ([]byte, error) { + var block struct { + Result struct { + Block json.RawMessage `json:"block"` + } `json:"result"` + } + + if err := json.Unmarshal(value, &block); err != nil { + return nil, fmt.Errorf("failed to unmarshal block response: %w", err) + } + + return block.Result.Block, nil +} + +type KyveBlockCollector struct { + poolId int64 + runtime string + chainRest string + earliestAvailableHeight int64 + latestAvailableHeight int64 +} + +func NewKyveBlockCollector(poolId int64, chainRest string) (*KyveBlockCollector, error) { + poolResponse, err := utils.GetPool(chainRest, poolId) + if err != nil { + return nil, fmt.Errorf("fail to get pool with id %d: %w", poolId, err) + } + + if poolResponse.Pool.Data.Runtime != utils.RuntimeTendermint && poolResponse.Pool.Data.Runtime != utils.RuntimeTendermintBsync { + return nil, fmt.Errorf("found invalid runtime on block pool %d: Expected = %s or %s Found = %s", poolId, utils.RuntimeTendermint, utils.RuntimeTendermintBsync, poolResponse.Pool.Data.Runtime) + } + + if poolResponse.Pool.Data.CurrentKey == "" { + return nil, fmt.Errorf("pool %d is empty and has not yet archived any data", poolId) + } + + startHeight, err := strconv.ParseInt(poolResponse.Pool.Data.StartKey, 10, 64) + if err != nil { + return nil, fmt.Errorf("failed to parse start height %s from pool: %w", poolResponse.Pool.Data.StartKey, err) + } + + currentHeight, err := strconv.ParseInt(poolResponse.Pool.Data.CurrentKey, 10, 64) + if err != nil { + return nil, fmt.Errorf("failed to parse end height %s from pool: %w", poolResponse.Pool.Data.CurrentKey, err) + } + + return &KyveBlockCollector{ + poolId: poolId, + runtime: poolResponse.Pool.Data.Runtime, + chainRest: chainRest, + earliestAvailableHeight: startHeight, + latestAvailableHeight: currentHeight, + }, nil +} + +func (collector *KyveBlockCollector) GetEarliestAvailableHeight() int64 { + return collector.earliestAvailableHeight +} + +func (collector *KyveBlockCollector) GetLatestAvailableHeight() int64 { + return collector.latestAvailableHeight +} + +func (collector *KyveBlockCollector) GetBlock(height int64) ([]byte, error) { + finalizedBundle, err := collector.getFinalizedBundleForBlockHeight(height) + if err != nil { + return nil, fmt.Errorf("failed to get finalized bundle for block height %d: %w", height, err) + } + + deflated, err := utils.GetDataFromFinalizedBundle(*finalizedBundle) + if err != nil { + return nil, fmt.Errorf("failed to get data from finalized bundle with storage id %s: %w", finalizedBundle.StorageId, err) + } + + // parse bundle + var bundle types.Bundle + + if err := json.Unmarshal(deflated, &bundle); err != nil { + return nil, fmt.Errorf("failed to unmarshal bundle: %w", err) + } + + for _, dataItem := range bundle { + h, err := strconv.ParseInt(dataItem.Key, 10, 64) + if err != nil { + return nil, fmt.Errorf("failed parse block height from key %s: %w", dataItem.Key, err) + } + + // skip blocks until we reach start height + if h < height { + continue + } + + // depending on the runtime the actual block can be nested in the value, before + // passing the value to the block executor we extract it + block, err := collector.extractRawBlockFromDataItemValue(dataItem.Value) + if err != nil { + return nil, fmt.Errorf("failed to extract block %d from data item value: %w", height, err) + } + + return block, nil + } + + return nil, fmt.Errorf("failed to find block %d in finalized bundle %s", height, finalizedBundle.StorageId) +} + +func (collector *KyveBlockCollector) StreamBlocks(blockCh chan<- *types.BlockItem, errorCh chan<- error, continuationHeight, targetHeight int64) { + // from the height where the collector should start downloading blocks we derive the pagination + // key of the bundles page so we can start from there + paginationKey, err := collector.getPaginationKeyForBlockHeight(continuationHeight) + if err != nil { + errorCh <- fmt.Errorf("failed to get pagination key for continuation height %d: %w", continuationHeight, err) + return + } + +BundleCollector: + for { + bundlesPage, nextKey, err := utils.GetFinalizedBundlesPage(collector.chainRest, collector.poolId, utils.BundlesPageLimit, paginationKey, false) + if err != nil { + errorCh <- fmt.Errorf("failed to get finalized bundles page: %w", err) + return + } + + for _, finalizedBundle := range bundlesPage { + maxBundleHeight, err := strconv.ParseInt(finalizedBundle.ToKey, 10, 64) + if err != nil { + errorCh <- fmt.Errorf("failed to parse bundle to key to int64: %w", err) + return + } + + // if the highest height in the bundle is still smaller than our continuation height + // we can skip this bundle + if maxBundleHeight < continuationHeight { + continue + } + + deflated, err := utils.GetDataFromFinalizedBundle(finalizedBundle) + if err != nil { + errorCh <- fmt.Errorf("failed to get data from finalized bundle with storage id %s: %w", finalizedBundle.StorageId, err) + return + } + + // parse bundle + var bundle types.Bundle + + if err := json.Unmarshal(deflated, &bundle); err != nil { + errorCh <- fmt.Errorf("failed to unmarshal bundle: %w", err) + return + } + + for _, dataItem := range bundle { + height, err := strconv.ParseInt(dataItem.Key, 10, 64) + if err != nil { + errorCh <- fmt.Errorf("failed parse block height from key %s: %w", dataItem.Key, err) + return + } + + // skip blocks until we reach start height + if height < continuationHeight { + continue + } + + // depending on the runtime the actual block can be nested in the value, before + // passing the value to the block executor we extract it + block, err := collector.extractRawBlockFromDataItemValue(dataItem.Value) + if err != nil { + errorCh <- fmt.Errorf("failed to extract block %d from data item value: %w", height, err) + } + + // send block to block executor + blockCh <- &types.BlockItem{ + Height: height, + Block: block, + } + + // update continuation height + continuationHeight = height + 1 + + // exit if target height is reached + if targetHeight > 0 && height >= targetHeight+1 { + break BundleCollector + } + } + } + + if nextKey == "" { + // if we are at the end of the page we continue and wait for + // new finalized bundles + time.Sleep(30 * time.Second) + continue + } + + time.Sleep(utils.RequestTimeoutMS) + paginationKey = nextKey + } +} + +func (collector *KyveBlockCollector) extractRawBlockFromDataItemValue(value []byte) ([]byte, error) { + if collector.runtime == utils.RuntimeTendermint { + var block struct { + Block struct { + Block json.RawMessage `json:"block"` + } `json:"block"` + } + + if err := json.Unmarshal(value, &block); err != nil { + return nil, fmt.Errorf("failed to unmarshal tendermint data item: %w", err) + } + + return block.Block.Block, nil + } + + if collector.runtime == utils.RuntimeTendermintBsync { + return value, nil + } + + return nil, fmt.Errorf("unknown runtime %s", collector.runtime) +} + +// getFinalizedBundleForBlockHeight gets the bundle which contains the block for the given height +func (collector *KyveBlockCollector) getFinalizedBundleForBlockHeight(height int64) (*types.FinalizedBundle, error) { + // the index is an incremental id for each data item. Since the index starts from zero + // and the start key is usually 1 we subtract it from the specified height so we get + // the correct index + index := height - collector.earliestAvailableHeight + + raw, err := utils.GetFromUrl(fmt.Sprintf( + "%s/kyve/v1/bundles/%d?index=%d", + collector.chainRest, + collector.poolId, + index, + )) + if err != nil { + return nil, fmt.Errorf("failed to get finalized bundle for index %d: %w", index, err) + } + + var bundlesResponse types.FinalizedBundlesResponse + + if err := json.Unmarshal(raw, &bundlesResponse); err != nil { + return nil, fmt.Errorf("failed to unmarshal finalized bundles response: %w", err) + } + + if len(bundlesResponse.FinalizedBundles) == 1 { + return &bundlesResponse.FinalizedBundles[0], nil + } + + return nil, fmt.Errorf("failed to find finalized bundle for block height %d: %w", height, err) +} + +// getPaginationKeyForBlockHeight gets the pagination key right for the bundle so the StartBlockCollector can +// directly start at the correct bundle. Therefore, it does not need to search through all the bundles until +// it finds the correct one +func (collector *KyveBlockCollector) getPaginationKeyForBlockHeight(height int64) (string, error) { + finalizedBundle, err := collector.getFinalizedBundleForBlockHeight(height) + if err != nil { + return "", fmt.Errorf("failed to get finalized bundle for block height %d: %w", height, err) + } + + bundleId, err := strconv.ParseInt(finalizedBundle.Id, 10, 64) + if err != nil { + return "", fmt.Errorf("failed to parse bundle id %s: %w", finalizedBundle.Id, err) + } + + // if bundleId is zero we start from the beginning, meaning the paginationKey should be empty + if bundleId == 0 { + return "", nil + } + + _, paginationKey, err := utils.GetFinalizedBundlesPageWithOffset(collector.chainRest, collector.poolId, 1, bundleId-1, "", false) + if err != nil { + return "", fmt.Errorf("failed to get finalized bundles: %w", err) + } + + return paginationKey, nil +} diff --git a/app/collector/snapshots.go b/app/collector/snapshots.go new file mode 100644 index 0000000..fd805b9 --- /dev/null +++ b/app/collector/snapshots.go @@ -0,0 +1,215 @@ +package collector + +import ( + "encoding/json" + "fmt" + "github.com/KYVENetwork/ksync/types" + "github.com/KYVENetwork/ksync/utils" + "strconv" + "strings" + "time" +) + +type KyveSnapshotCollector struct { + poolId int64 + chainRest string + + earliestAvailableHeight int64 + latestAvailableHeight int64 + interval int64 + totalBundles int64 +} + +func NewKyveSnapshotCollector(poolId int64, chainRest string) (*KyveSnapshotCollector, error) { + poolResponse, err := utils.GetPool(chainRest, poolId) + if err != nil { + return nil, fmt.Errorf("fail to get pool with id %d: %w", poolId, err) + } + + if poolResponse.Pool.Data.Runtime != utils.RuntimeTendermintSsync { + return nil, fmt.Errorf("found invalid runtime on snapshot pool %d: Expected = %s Found = %s", poolId, utils.RuntimeTendermintSsync, poolResponse.Pool.Data.Runtime) + } + + var config types.TendermintSSyncConfig + if err := json.Unmarshal([]byte(poolResponse.Pool.Data.Config), &config); err != nil { + return nil, fmt.Errorf("failed to unmarshal snapshot pool config %s: %w", poolResponse.Pool.Data.Config, err) + } + + startHeight, _, err := utils.ParseSnapshotFromKey(poolResponse.Pool.Data.StartKey) + if err != nil { + return nil, fmt.Errorf("failed to parse height %s from start key: %w", poolResponse.Pool.Data.StartKey, err) + } + + currentHeight, chunkIndex, err := utils.ParseSnapshotFromKey(poolResponse.Pool.Data.CurrentKey) + if err != nil { + return nil, fmt.Errorf("failed to parse height %s from current key: %w", poolResponse.Pool.Data.CurrentKey, err) + } + + // we expect that the current snapshot is not complete yet and that the latest + // available snapshot is the one before it, to get the height of that we simply + // go back the snapshot interval from the current height + latestAvailableHeight := currentHeight - config.Interval + + // if however the last chunk of the current snapshot has already been archived the latest available + // snapshot height is indeed the current one. We can check this if the new bundle summary + // format "height/format/chunkIndex/totalChunks" is available and by comparing the total number of chunks + // in the snapshot with our current chunk index. We just skip if parsing the number of total chunks + // fails + if summary := strings.Split(poolResponse.Pool.Data.CurrentSummary, "/"); len(summary) == 4 { + if totalChunks, err := strconv.ParseInt(summary[3], 10, 64); err == nil && totalChunks == chunkIndex+1 { + latestAvailableHeight = currentHeight + } + } + + return &KyveSnapshotCollector{ + poolId: poolId, + chainRest: chainRest, + earliestAvailableHeight: startHeight, + latestAvailableHeight: latestAvailableHeight, + interval: config.Interval, + totalBundles: poolResponse.Pool.Data.TotalBundles, + }, nil +} + +func (collector *KyveSnapshotCollector) GetEarliestAvailableHeight() int64 { + return collector.earliestAvailableHeight +} + +func (collector *KyveSnapshotCollector) GetLatestAvailableHeight() int64 { + return collector.latestAvailableHeight +} + +func (collector *KyveSnapshotCollector) GetInterval() int64 { + return collector.interval +} + +func (collector *KyveSnapshotCollector) GetSnapshotHeight(targetHeight int64) int64 { + // if no target height was given the snapshot height is the latest available, + // also if the target height is greater than the latest available height + if targetHeight == 0 || targetHeight > collector.latestAvailableHeight { + return collector.latestAvailableHeight + } + + // get the nearest snapshot height on the interval below the given target height + // by subtracting the modulo remainder + return targetHeight - (targetHeight % collector.interval) +} + +func (collector *KyveSnapshotCollector) GetCurrentHeight() (int64, error) { + poolResponse, err := utils.GetPool(collector.chainRest, collector.poolId) + if err != nil { + return 0, fmt.Errorf("fail to get pool with id %d: %w", collector.poolId, err) + } + + currentHeight, _, err := utils.ParseSnapshotFromKey(poolResponse.Pool.Data.CurrentKey) + if err != nil { + return 0, fmt.Errorf("failed to parse height %s from current key: %w", poolResponse.Pool.Data.CurrentKey, err) + } + + return currentHeight, nil +} + +func (collector *KyveSnapshotCollector) GetSnapshotFromBundleId(bundleId int64) (*types.SnapshotDataItem, error) { + chunkBundleFinalized, err := utils.GetFinalizedBundleById(collector.chainRest, collector.poolId, bundleId) + if err != nil { + return nil, fmt.Errorf("failed getting finalized bundle by id %d: %w", bundleId, err) + } + + data, err := utils.GetDataFromFinalizedBundle(*chunkBundleFinalized) + if err != nil { + return nil, fmt.Errorf("failed getting data from finalized bundle: %w", err) + } + + var bundle types.SnapshotBundle + if err := json.Unmarshal(data, &bundle); err != nil { + return nil, fmt.Errorf("failed to unmarshal snapshot bundle: %w", err) + } + + if len(bundle) != 1 { + return nil, fmt.Errorf("found multiple bundles in snapshot bundle") + } + + return &bundle[0], nil +} + +func (collector *KyveSnapshotCollector) DownloadChunkFromBundleId(bundleId int64) ([]byte, error) { + chunkBundleFinalized, err := utils.GetFinalizedBundleById(collector.chainRest, collector.poolId, bundleId) + if err != nil { + return nil, fmt.Errorf("failed getting finalized bundle by id %d: %w", bundleId, err) + } + + data, err := utils.GetDataFromFinalizedBundle(*chunkBundleFinalized) + if err != nil { + return nil, fmt.Errorf("failed getting data from finalized bundle: %w", err) + } + + var bundle types.SnapshotBundle + if err := json.Unmarshal(data, &bundle); err != nil { + return nil, fmt.Errorf("failed to unmarshal snapshot bundle: %w", err) + } + + if len(bundle) != 1 { + return nil, fmt.Errorf("found multiple bundles in snapshot bundle") + } + + return bundle[0].Value.Chunk, nil +} + +func (collector *KyveSnapshotCollector) FindSnapshotBundleIdForHeight(height int64) (int64, error) { + latestBundleId := collector.totalBundles - 1 + + // if the height is the latest height we can calculate the location of bundle id for the first + // chunk immediately + if height == collector.latestAvailableHeight { + finalizedBundle, err := utils.GetFinalizedBundleById(collector.chainRest, collector.poolId, latestBundleId) + if err != nil { + return 0, fmt.Errorf("failed to get finalized bundle with id %d: %w", latestBundleId, err) + } + + h, chunkIndex, err := utils.ParseSnapshotFromKey(finalizedBundle.ToKey) + if err != nil { + return 0, fmt.Errorf("failed to parse snapshot key %s: %w", finalizedBundle.ToKey, err) + } + + if h == height { + return latestBundleId - chunkIndex, nil + } + } + + // if the height is not the latest height we try to find it with binary search + // TODO: consider interpolation search + low := int64(0) + high := latestBundleId + + // stop when low and high meet + for low <= high { + // check in the middle + mid := (low + high) / 2 + + finalizedBundle, err := utils.GetFinalizedBundleById(collector.chainRest, collector.poolId, mid) + if err != nil { + return 0, fmt.Errorf("failed to get finalized bundle with id %d: %w", mid, err) + } + + h, chunkIndex, err := utils.ParseSnapshotFromKey(finalizedBundle.ToKey) + if err != nil { + return 0, fmt.Errorf("failed to parse snapshot key %s: %w", finalizedBundle.ToKey, err) + } + + if h < height { + // target height is in the right half + low = mid + 1 + } else if h > height { + // target height is in the left half + high = mid - 1 + } else { + // found it, now we just go back to the bundle where the first chunk index + // is located + return mid - chunkIndex, nil + } + + time.Sleep(utils.RequestTimeoutMS) + } + + return 0, fmt.Errorf("failed to find snapshot bundle id for height %d", height) +} diff --git a/app/genesis/genesis.go b/app/genesis/genesis.go new file mode 100644 index 0000000..e025312 --- /dev/null +++ b/app/genesis/genesis.go @@ -0,0 +1,122 @@ +package genesis + +import ( + "encoding/json" + "fmt" + "github.com/KYVENetwork/ksync/metrics" + "os" + "strconv" +) + +type Genesis struct { + genesisPath string + fileSize int64 + chainId string + initialHeight int64 +} + +func NewGenesis(homePath string) (*Genesis, error) { + genesis := &Genesis{genesisPath: fmt.Sprintf("%s/config/genesis.json", homePath)} + + if err := genesis.loadFileSize(); err != nil { + return nil, fmt.Errorf("failed to load file size: %w", err) + } + + if err := genesis.formatGenesisFile(); err != nil { + return nil, fmt.Errorf("failed to format genesis file: %w", err) + } + + if err := genesis.loadValues(); err != nil { + return nil, fmt.Errorf("failed to load values from genesis file: %w", err) + } + + metrics.SetSourceId(genesis.GetChainId()) + return genesis, nil +} + +func (genesis *Genesis) GetChainId() string { + return genesis.chainId +} + +func (genesis *Genesis) GetInitialHeight() int64 { + return genesis.initialHeight +} + +func (genesis *Genesis) GetFileSize() int64 { + return genesis.fileSize +} + +func (genesis *Genesis) loadFileSize() error { + fileInfo, err := os.Stat(genesis.genesisPath) + if err != nil { + return fmt.Errorf("failed to find genesis at %s: %w", genesis.genesisPath, err) + } + + genesis.fileSize = fileInfo.Size() + return nil +} + +func (genesis *Genesis) loadValues() error { + genesisFile, err := os.ReadFile(genesis.genesisPath) + if err != nil { + return fmt.Errorf("failed to open genesis.json at %s: %w", genesis.genesisPath, err) + } + + var value struct { + ChainId string `json:"chain_id"` + InitialHeight string `json:"initial_height"` + } + + if err := json.Unmarshal(genesisFile, &value); err != nil { + return fmt.Errorf("failed to unmarshal genesis file: %w", err) + } + + initialHeight, err := strconv.ParseInt(value.InitialHeight, 10, 64) + if err != nil { + return fmt.Errorf("failed to parse initial height %s to int64: %w", value.InitialHeight, err) + } + + genesis.chainId = value.ChainId + genesis.initialHeight = initialHeight + return nil +} + +// formatGenesisFile ensures that the "initial_height" value is of type string +// because sometimes it is of type integer. If it is an integer it causes problems +// later on in the cosmos app. Still need to find out why this is an integer sometimes. +func (genesis *Genesis) formatGenesisFile() error { + genesisFile, err := os.ReadFile(genesis.genesisPath) + if err != nil { + return fmt.Errorf("error opening genesis.json at %s: %w", genesis.genesisPath, err) + } + + var genesisBefore struct { + InitialHeight int `json:"initial_height"` + } + + // if we can not unmarshal the initial_height to an integer it means + // that it is of type string which is desired. In this case we return + // and don't format the genesis file + if err := json.Unmarshal(genesisFile, &genesisBefore); err != nil { + return nil + } + + var genesisAfter map[string]interface{} + + if err := json.Unmarshal(genesisFile, &genesis); err != nil { + return fmt.Errorf("failed to unmarshal genesis file: %w", err) + } + + genesisAfter["initial_height"] = strconv.Itoa(genesisBefore.InitialHeight) + + genesisJson, err := json.MarshalIndent(genesisAfter, "", " ") + if err != nil { + return fmt.Errorf("failed to marshal genesis file: %w", err) + } + + if err := os.WriteFile(genesis.genesisPath, genesisJson, os.ModePerm); err != nil { + return fmt.Errorf("failed to write genesis.json: %w", err) + } + + return nil +} diff --git a/sources/helpers/helpers.go b/app/source/helpers.go similarity index 69% rename from sources/helpers/helpers.go rename to app/source/helpers.go index 60d6817..71976d0 100644 --- a/sources/helpers/helpers.go +++ b/app/source/helpers.go @@ -1,8 +1,7 @@ -package helpers +package source import ( "fmt" - "github.com/KYVENetwork/ksync/collectors/pool" "github.com/KYVENetwork/ksync/types" "github.com/KYVENetwork/ksync/utils" "gopkg.in/yaml.v2" @@ -17,11 +16,21 @@ const ( greenYes = "\033[32m" + "YES" + "\033[0m" ) +func FormatOutput(entry *types.Entry, chainId string) (string, string, string) { + var blockKey, stateKey, heightKey string + if chainId == utils.ChainIdMainnet && entry.Networks.Kyve != nil { + blockKey, stateKey, heightKey = FormatKeys(entry.Networks.Kyve.BlockStartKey, entry.Networks.Kyve.LatestBlockKey, entry.Networks.Kyve.StateStartKey, entry.Networks.Kyve.LatestStateKey) + } else if chainId == utils.ChainIdKaon && entry.Networks.Kaon != nil { + blockKey, stateKey, heightKey = FormatKeys(entry.Networks.Kaon.BlockStartKey, entry.Networks.Kaon.LatestBlockKey, entry.Networks.Kaon.StateStartKey, entry.Networks.Kaon.LatestStateKey) + } + return blockKey, stateKey, heightKey +} + func LoadLatestPoolData(sourceRegistry types.SourceRegistry) (*types.SourceRegistry, error) { for _, entry := range sourceRegistry.Entries { if entry.Networks.Kyve != nil && entry.Networks.Kyve.Integrations != nil && entry.Networks.Kyve.Integrations.KSYNC != nil { if entry.Networks.Kyve.Integrations.KSYNC.BlockSyncPool != nil { - poolResponse, err := pool.GetPoolInfo(utils.RestEndpointMainnet, int64(*entry.Networks.Kyve.Integrations.KSYNC.BlockSyncPool)) + poolResponse, err := utils.GetPool(utils.RestEndpointMainnet, int64(*entry.Networks.Kyve.Integrations.KSYNC.BlockSyncPool)) if err != nil { return nil, err } @@ -29,7 +38,7 @@ func LoadLatestPoolData(sourceRegistry types.SourceRegistry) (*types.SourceRegis entry.Networks.Kyve.LatestBlockKey = &poolResponse.Pool.Data.CurrentKey } if entry.Networks.Kyve.Integrations.KSYNC.StateSyncPool != nil { - poolResponse, err := pool.GetPoolInfo(utils.RestEndpointMainnet, int64(*entry.Networks.Kyve.Integrations.KSYNC.StateSyncPool)) + poolResponse, err := utils.GetPool(utils.RestEndpointMainnet, int64(*entry.Networks.Kyve.Integrations.KSYNC.StateSyncPool)) if err != nil { return nil, err } @@ -39,7 +48,7 @@ func LoadLatestPoolData(sourceRegistry types.SourceRegistry) (*types.SourceRegis } if entry.Networks.Kaon != nil && entry.Networks.Kaon.Integrations != nil && entry.Networks.Kaon.Integrations.KSYNC != nil { if entry.Networks.Kaon.Integrations.KSYNC.BlockSyncPool != nil { - poolResponse, err := pool.GetPoolInfo(utils.RestEndpointKaon, int64(*entry.Networks.Kaon.Integrations.KSYNC.BlockSyncPool)) + poolResponse, err := utils.GetPool(utils.RestEndpointKaon, int64(*entry.Networks.Kaon.Integrations.KSYNC.BlockSyncPool)) if err != nil { return nil, err } @@ -47,7 +56,7 @@ func LoadLatestPoolData(sourceRegistry types.SourceRegistry) (*types.SourceRegis entry.Networks.Kaon.LatestBlockKey = &poolResponse.Pool.Data.CurrentKey } if entry.Networks.Kaon.Integrations.KSYNC.StateSyncPool != nil { - poolResponse, err := pool.GetPoolInfo(utils.RestEndpointKaon, int64(*entry.Networks.Kaon.Integrations.KSYNC.StateSyncPool)) + poolResponse, err := utils.GetPool(utils.RestEndpointKaon, int64(*entry.Networks.Kaon.Integrations.KSYNC.StateSyncPool)) if err != nil { return nil, err } @@ -59,32 +68,6 @@ func LoadLatestPoolData(sourceRegistry types.SourceRegistry) (*types.SourceRegis return &sourceRegistry, nil } -func GetSourceRegistryEntry(registryUrl, source string) (*types.Entry, error) { - registry, err := GetSourceRegistryWithoutPoolData(registryUrl) - if err != nil { - return nil, fmt.Errorf("failed to get source registry: %v", err) - } - - for _, entry := range registry.Entries { - if strings.ToLower(entry.SourceID) == strings.ToLower(source) { - return &entry, nil - } - - if entry.Networks.Kyve != nil { - if strings.ToLower(entry.Networks.Kyve.SourceMetadata.Title) == strings.ToLower(source) { - return &entry, nil - } - } - - if entry.Networks.Kaon != nil { - if strings.ToLower(entry.Networks.Kaon.SourceMetadata.Title) == strings.ToLower(source) { - return &entry, nil - } - } - } - return nil, fmt.Errorf("could not find source registry entry for %v", source) -} - func GetSourceRegistry(url string) (*types.SourceRegistry, error) { response, err := http.Get(url) if err != nil { @@ -115,31 +98,6 @@ func GetSourceRegistry(url string) (*types.SourceRegistry, error) { return r, nil } -func GetSourceRegistryWithoutPoolData(url string) (*types.SourceRegistry, error) { - response, err := http.Get(url) - if err != nil { - return nil, err - } - - if response.StatusCode != 200 { - return nil, fmt.Errorf("got status code %d != 200", response.StatusCode) - } - - data, err := ioutil.ReadAll(response.Body) - if err != nil { - return nil, err - } - - var sourceRegistry types.SourceRegistry - - err = yaml.Unmarshal(data, &sourceRegistry) - if err != nil { - return nil, err - } - - return &sourceRegistry, nil -} - func FormatKeys(blockStartKey, latestBlockKey, stateStartKey, latestStateKey *string) (string, string, string) { var blockSync, stateSync, heightSync = redNo, redNo, redNo diff --git a/app/source/source.go b/app/source/source.go new file mode 100644 index 0000000..71e0df5 --- /dev/null +++ b/app/source/source.go @@ -0,0 +1,133 @@ +package source + +import ( + "fmt" + "github.com/KYVENetwork/ksync/flags" + "github.com/KYVENetwork/ksync/types" + "github.com/KYVENetwork/ksync/utils" + "gopkg.in/yaml.v2" + "io/ioutil" + "net/http" + "strconv" +) + +type Source struct { + sourceId string + registryUrl string + + sourceRegistry types.SourceRegistry +} + +func NewSource(sourceId string) (*Source, error) { + response, err := http.Get(utils.DefaultRegistryURL) + if err != nil { + return nil, err + } + + if response.StatusCode != 200 { + return nil, fmt.Errorf("got status code %d != 200", response.StatusCode) + } + + data, err := ioutil.ReadAll(response.Body) + if err != nil { + return nil, err + } + + var sourceRegistry types.SourceRegistry + + err = yaml.Unmarshal(data, &sourceRegistry) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal source-registry: %w", err) + } + + return &Source{ + sourceId: sourceId, + sourceRegistry: sourceRegistry, + }, nil +} + +func (source *Source) GetSourceBlockPoolId() (int64, error) { + if flags.BlockPoolId != "" { + return strconv.ParseInt(flags.BlockPoolId, 10, 64) + } + + entry, found := source.sourceRegistry.Entries[source.sourceId] + if !found { + return 0, fmt.Errorf("source with id \"%s\" not found in registry", source.sourceId) + } + + if flags.ChainId == utils.ChainIdMainnet { + return int64(*entry.Networks.Kyve.Integrations.KSYNC.BlockSyncPool), nil + } else if flags.ChainId == utils.ChainIdKaon { + return int64(*entry.Networks.Kaon.Integrations.KSYNC.BlockSyncPool), nil + } + + return 0, fmt.Errorf("failed to get block pool id from registry entry") +} + +func (source *Source) GetSourceSnapshotPoolId() (int64, error) { + if flags.SnapshotPoolId != "" { + return strconv.ParseInt(flags.SnapshotPoolId, 10, 64) + } + + entry, found := source.sourceRegistry.Entries[source.sourceId] + if !found { + return 0, fmt.Errorf("source with id \"%s\" not found in registry", source.sourceId) + } + + if flags.ChainId == utils.ChainIdMainnet { + return int64(*entry.Networks.Kyve.Integrations.KSYNC.StateSyncPool), nil + } else if flags.ChainId == utils.ChainIdKaon { + return int64(*entry.Networks.Kaon.Integrations.KSYNC.StateSyncPool), nil + } + + return 0, fmt.Errorf("failed to get block pool id from registry entry") +} + +func (source *Source) GetUpgradeNameForHeight(height int64) (string, error) { + entry, found := source.sourceRegistry.Entries[source.sourceId] + if !found { + return "", fmt.Errorf("source with id \"%s\" not found in registry", source.sourceId) + } + + upgradeName := "genesis" + + for _, upgrade := range entry.Codebase.Settings.Upgrades { + upgradeHeight, err := strconv.ParseInt(upgrade.Height, 10, 64) + if err != nil { + return "", fmt.Errorf("failed to parse upgrade height %s: %w", upgrade.Height, err) + } + + if height < upgradeHeight { + break + } + + upgradeName = upgrade.Name + } + + return upgradeName, nil +} + +func (source *Source) GetRecommendedVersionForHeight(height int64) (string, error) { + entry, found := source.sourceRegistry.Entries[source.sourceId] + if !found { + return "", fmt.Errorf("source with id \"%s\" not found in registry", source.sourceId) + } + + var recommendedVersion string + + for _, upgrade := range entry.Codebase.Settings.Upgrades { + upgradeHeight, err := strconv.ParseInt(upgrade.Height, 10, 64) + if err != nil { + return "", fmt.Errorf("failed to parse upgrade height %s: %w", upgrade.Height, err) + } + + if height < upgradeHeight { + break + } + + recommendedVersion = upgrade.RecommendedVersion + } + + return recommendedVersion, nil +} diff --git a/backup/backup.go b/backup/backup.go deleted file mode 100644 index 63118b4..0000000 --- a/backup/backup.go +++ /dev/null @@ -1,94 +0,0 @@ -package backup - -import ( - "fmt" - "github.com/KYVENetwork/ksync/backup/helpers" - "github.com/KYVENetwork/ksync/types" - log "github.com/KYVENetwork/ksync/utils" - "path/filepath" -) - -var ( - logger = log.KsyncLogger("backup") -) - -func GetBackupConfig(homePath string, backupInterval, backupKeepRecent int64, backupCompression, backupDest string) (backupCfg *types.BackupConfig, err error) { - backupCfg = &types.BackupConfig{ - Interval: backupInterval, - KeepRecent: backupKeepRecent, - Src: filepath.Join(homePath, "data"), - Dest: backupDest, - Compression: backupCompression, - } - - if backupInterval > 0 { - if backupCfg.KeepRecent < 2 && backupCfg.KeepRecent != 0 { - return nil, fmt.Errorf("backup-keep-recent needs to be >= 2") - } - if backupCfg.Dest == "" { - backupPath, err := helpers.GetBackupDestPath() - if err != nil { - return nil, fmt.Errorf("failed to get backup directory: %w", err) - } - backupCfg.Dest = backupPath - } - - if err = helpers.ValidatePaths(backupCfg.Src, backupCfg.Dest); err != nil { - return nil, fmt.Errorf("backup path validation failed: %w", err) - } - } - - return -} - -func CreateBackup(backupCfg *types.BackupConfig, chainId string, height int64, parallel bool) error { - destPath, err := helpers.CreateBackupDestFolder(backupCfg.Dest, chainId, height) - if err != nil { - return err - } - - logger.Info().Str("from", backupCfg.Src).Str("to", destPath).Msg("start copying") - - if err = helpers.CopyDir(backupCfg.Src, destPath); err != nil { - return fmt.Errorf("could not copy backup to destination: %w", err) - } - - logger.Info().Bool("compression", backupCfg.Compression != "").Msg("created copy successfully") - - // execute compression async - if backupCfg.Compression != "" { - if parallel { - go func() { - logger.Info().Str("src-path", destPath).Str("compression", backupCfg.Compression).Msg("start compressing") - - if err = helpers.CompressDirectory(destPath, backupCfg.Compression); err != nil { - logger.Error().Str("err", err.Error()).Msg("compression failed") - return - } - - logger.Info().Str("src-path", destPath).Str("compression", backupCfg.Compression).Msg("compressed backup successfully") - }() - } else { - logger.Info().Str("src-path", destPath).Str("compression", backupCfg.Compression).Msg("start compressing") - - if err = helpers.CompressDirectory(destPath, backupCfg.Compression); err != nil { - logger.Error().Str("err", err.Error()).Msg("compression failed") - return err - } - - logger.Info().Str("src-path", destPath).Str("compression", backupCfg.Compression).Msg("compressed backup successfully") - } - } - - if backupCfg.KeepRecent >= 2 { - logger.Info().Str("path", filepath.Join(backupCfg.Dest, chainId)).Msg("starting to cleanup backup directory") - - if err := helpers.ClearBackups(filepath.Join(backupCfg.Dest, chainId), backupCfg.KeepRecent); err != nil { - return fmt.Errorf("clearing backup directory failed: %w", err) - } - - logger.Info().Msg("cleaned backup directory successfully") - } - - return nil -} diff --git a/backup/helpers/helpers.go b/backup/helpers/helpers.go deleted file mode 100644 index 769dd5d..0000000 --- a/backup/helpers/helpers.go +++ /dev/null @@ -1,185 +0,0 @@ -package helpers - -import ( - "fmt" - "io" - "os" - "os/exec" - "path/filepath" - "sort" - "strconv" -) - -func CreateBackupDestFolder(backupDir string, chainId string, height int64) (string, error) { - if _, err := os.Stat(filepath.Join(backupDir, chainId)); os.IsNotExist(err) { - if err := os.Mkdir(filepath.Join(backupDir, chainId), 0o755); err != nil { - return "", fmt.Errorf("failed to create backup directory: %w", err) - } - } - - h := strconv.FormatInt(height, 10) - - if err := os.Mkdir(filepath.Join(backupDir, chainId, h), 0o755); err != nil { - return "", fmt.Errorf("failed to create backup directory: %w", err) - } - - if err := os.Mkdir(filepath.Join(backupDir, chainId, h, "data"), 0o755); err != nil { - return "", fmt.Errorf("failed to create backup data directory: %w", err) - } - - return filepath.Join(backupDir, chainId, h, "data"), nil -} - -func GetBackupDestPath() (string, error) { - home, err := os.UserHomeDir() - if err != nil { - return "", fmt.Errorf("could not find home directory: %w", err) - } - - ksyncDir := filepath.Join(home, ".ksync") - - if _, err = os.Stat(ksyncDir); os.IsNotExist(err) { - if err := os.Mkdir(ksyncDir, 0o755); err != nil { - return "", fmt.Errorf("could not create .ksync directory: %w", err) - } - } - - backupDir := filepath.Join(ksyncDir, "backups") - if _, err = os.Stat(backupDir); os.IsNotExist(err) { - if err := os.Mkdir(backupDir, 0o755); err != nil { - return "", fmt.Errorf("could not create .ksync/backups directory: %w", err) - } - } - - return backupDir, nil -} - -func ValidatePaths(srcPath, destPath string) error { - pathInfo, err := os.Stat(srcPath) - if err != nil { - return err - } - if !pathInfo.IsDir() { - return err - } - pathInfo, err = os.Stat(destPath) - if err != nil { - return err - } - if !pathInfo.IsDir() { - return err - } - - return nil -} - -func CopyDir(srcDir, destDir string) error { - // Create the destination directory if it doesn't exist - if err := os.MkdirAll(destDir, 0755); err != nil { - return err - } - - // Walk through the source directory and copy its contents to the destination - return filepath.Walk(srcDir, func(srcPath string, fileInfo os.FileInfo, err error) error { - if err != nil { - return err - } - - // Construct the corresponding destination path - destPath := filepath.Join(destDir, srcPath[len(srcDir):]) - - if fileInfo.IsDir() { - // Create the destination directory if it doesn't exist - return os.MkdirAll(destPath, 0755) - } else { - // Open the source file for reading - srcFile, err := os.Open(srcPath) - if err != nil { - return err - } - defer srcFile.Close() - - // Create the destination file - destFile, err := os.Create(destPath) - if err != nil { - return err - } - defer destFile.Close() - - // Copy the contents from source to destination - if _, err := io.Copy(destFile, srcFile); err != nil { - return err - } - } - return nil - }) -} - -func CompressDirectory(srcPath, compressionType string) error { - var cmd *exec.Cmd - - switch compressionType { - case "tar.gz": - cmd = exec.Command("tar", "-zcvf", filepath.Base(srcPath)+"."+compressionType, filepath.Base(srcPath)) - case "zip": - cmd = exec.Command("zip", "-r", filepath.Base(srcPath)+"."+compressionType, filepath.Base(srcPath)) - default: - return fmt.Errorf("unsupported compression type: %s", compressionType) - } - - cmd.Dir = filepath.Dir(srcPath) - cmd.Stdout = nil - - // Run the command - if err := cmd.Run(); err != nil { - return err - } - - if err := os.RemoveAll(srcPath); err != nil { - return err - } - - return nil -} - -func ClearBackups(srcPath string, threshold int64) error { - // Get and sort all created Backups - entries, err := os.ReadDir(srcPath) - if err != nil { - return err - } - - backups := make([]os.DirEntry, 0) - for _, entry := range entries { - if entry.IsDir() { - // Make sure to only clear backups with height as a name - if _, err := strconv.ParseInt(entry.Name(), 10, 64); err == nil { - backups = append(backups, entry) - } - } - } - - sort.Slice(backups, func(i, j int) bool { - a, _ := strconv.Atoi(backups[i].Name()) - b, _ := strconv.Atoi(backups[j].Name()) - return a < b - }) - - if int64(len(backups)) > threshold { - for { - oldestBackup := backups[0].Name() - err = os.RemoveAll(filepath.Join(srcPath, oldestBackup)) - if err != nil { - return err - } - - backups = backups[1:] - - if int64(len(backups)) <= threshold { - break - } - } - } - - return nil -} diff --git a/blocksync/blocksync.go b/blocksync/blocksync.go deleted file mode 100644 index 0f5bea2..0000000 --- a/blocksync/blocksync.go +++ /dev/null @@ -1,124 +0,0 @@ -package blocksync - -import ( - "errors" - "fmt" - "github.com/KYVENetwork/ksync/blocksync/helpers" - "github.com/KYVENetwork/ksync/bootstrap" - "github.com/KYVENetwork/ksync/types" - "github.com/KYVENetwork/ksync/utils" - "strings" - "time" -) - -var ( - logger = utils.KsyncLogger("block-sync") -) - -func PerformBlockSyncValidationChecks(chainRest string, blockRpcConfig *types.BlockRpcConfig, blockPoolId *int64, continuationHeight, targetHeight int64, checkEndHeight, userInput bool) error { - logger.Info().Msg(fmt.Sprintf("loaded current block height of node: %d", continuationHeight-1)) - - // perform boundary checks - _, startHeight, endHeight, err := helpers.GetBlockBoundaries(chainRest, blockRpcConfig, blockPoolId) - if err != nil { - return fmt.Errorf("failed to get block boundaries: %w", err) - } - - logger.Info().Msg(fmt.Sprintf("retrieved block boundaries, earliest block height = %d, latest block height %d", startHeight, endHeight)) - - if continuationHeight < startHeight { - return fmt.Errorf("app is currently at height %d but first available block on pool is %d", continuationHeight, startHeight) - } - - if continuationHeight > endHeight { - return fmt.Errorf("app is currently at height %d but last available block on pool is %d", continuationHeight, endHeight) - } - - if targetHeight > 0 && continuationHeight > targetHeight { - return fmt.Errorf("requested target height is %d but app is already at block height %d", targetHeight, continuationHeight) - } - - if checkEndHeight && targetHeight > 0 && targetHeight > endHeight { - return fmt.Errorf("requested target height is %d but last available block on pool is %d", targetHeight, endHeight) - } - - if targetHeight == 0 { - logger.Info().Msg(fmt.Sprintf("no target height specified, syncing to latest available block height %d", endHeight)) - } - - if userInput { - answer := "" - - if targetHeight > 0 { - fmt.Printf("\u001B[36m[KSYNC]\u001B[0m should %d blocks from height %d to %d be synced [y/N]: ", targetHeight-continuationHeight+1, continuationHeight-1, targetHeight) - } else { - fmt.Printf("\u001B[36m[KSYNC]\u001B[0m should %d blocks from height %d to %d be synced [y/N]: ", endHeight-continuationHeight+1, continuationHeight-1, endHeight) - } - - if _, err := fmt.Scan(&answer); err != nil { - return fmt.Errorf("failed to read in user input: %s", err) - } - - if strings.ToLower(answer) != "y" { - return errors.New("aborted block-sync") - } - } - - return nil -} - -func StartBlockSyncWithBinary(engine types.Engine, binaryPath, homePath, chainId, chainRest, storageRest string, blockRpcConfig *types.BlockRpcConfig, blockPoolId *int64, targetHeight int64, backupCfg *types.BackupConfig, appFlags string, rpcServer, optOut, debug bool) error { - logger.Info().Msg("starting block-sync") - - if err := bootstrap.StartBootstrapWithBinary(engine, binaryPath, homePath, chainRest, storageRest, blockRpcConfig, blockPoolId, appFlags, debug); err != nil { - return fmt.Errorf("failed to bootstrap node: %w", err) - } - - // start binary process thread - processId, err := utils.StartBinaryProcessForDB(engine, binaryPath, debug, strings.Split(appFlags, ",")) - if err != nil { - return fmt.Errorf("failed to start binary process: %w", err) - } - - if err := engine.OpenDBs(); err != nil { - return fmt.Errorf("failed to open dbs in engine: %w", err) - } - - if rpcServer { - go engine.StartRPCServer() - } - - utils.TrackSyncStartEvent(engine, utils.BLOCK_SYNC, chainId, chainRest, storageRest, targetHeight, optOut) - - start := time.Now() - - currentHeight := engine.GetHeight() - - // db executes blocks against app until target height is reached - if err := StartBlockSyncExecutor(engine, chainRest, storageRest, blockRpcConfig, blockPoolId, targetHeight, 0, 0, false, false, backupCfg); err != nil { - logger.Error().Msg(fmt.Sprintf("%s", err)) - - // stop binary process thread - if err := utils.StopProcessByProcessId(processId); err != nil { - return fmt.Errorf("failed to stop process by process id: %w", err) - } - - return fmt.Errorf("failed to start block-sync executor: %w", err) - } - - elapsed := time.Since(start).Seconds() - utils.TrackSyncCompletedEvent(0, targetHeight-currentHeight, targetHeight, elapsed, optOut) - - // stop binary process thread - if err := utils.StopProcessByProcessId(processId); err != nil { - return fmt.Errorf("failed to stop process by process id: %w", err) - } - - if err := engine.CloseDBs(); err != nil { - return fmt.Errorf("failed to close dbs in engine: %w", err) - } - - logger.Info().Msg(fmt.Sprintf("block-synced from %d to %d (%d blocks) in %.2f seconds", currentHeight, targetHeight, targetHeight-currentHeight, elapsed)) - logger.Info().Msg(fmt.Sprintf("successfully finished block-sync")) - return nil -} diff --git a/blocksync/executor.go b/blocksync/executor.go deleted file mode 100644 index 4d56623..0000000 --- a/blocksync/executor.go +++ /dev/null @@ -1,195 +0,0 @@ -package blocksync - -import ( - "fmt" - "github.com/KYVENetwork/ksync/backup" - "github.com/KYVENetwork/ksync/collectors/blocks" - "github.com/KYVENetwork/ksync/collectors/pool" - stateSyncHelpers "github.com/KYVENetwork/ksync/statesync/helpers" - "github.com/KYVENetwork/ksync/types" - "github.com/KYVENetwork/ksync/utils" - "time" -) - -var ( - itemCh = make(chan types.DataItem, utils.BlockBuffer) - errorCh = make(chan error) -) - -func StartBlockSyncExecutor(engine types.Engine, chainRest, storageRest string, blockRpcConfig *types.BlockRpcConfig, blockPoolId *int64, targetHeight int64, snapshotPoolId, snapshotInterval int64, pruning, skipWaiting bool, backupCfg *types.BackupConfig) error { - continuationHeight, err := engine.GetContinuationHeight() - if err != nil { - return fmt.Errorf("failed to get continuation height from engine: %w", err) - } - - appHeight, err := engine.GetAppHeight() - if err != nil { - return fmt.Errorf("failed to get app height from engine: %w", err) - } - - if err := engine.StartProxyApp(); err != nil { - return fmt.Errorf("failed to start proxy app: %w", err) - } - - if err := engine.DoHandshake(); err != nil { - return fmt.Errorf("failed to do handshake: %w", err) - } - - var poolResponse *types.PoolResponse - var runtime *string - if blockPoolId != nil { - poolResponse, err = pool.GetPoolInfo(chainRest, *blockPoolId) - if err != nil { - return fmt.Errorf("failed to get pool info: %w", err) - } - runtime = &poolResponse.Pool.Data.Runtime - } - - // start block collector. we must exit if snapshot interval is zero - go blocks.StartBlockCollector(itemCh, errorCh, chainRest, storageRest, blockRpcConfig, poolResponse, continuationHeight, targetHeight, snapshotInterval == 0) - - snapshotPoolHeight := int64(0) - - // if KSYNC has already fetched 3 * snapshot_interval ahead of the snapshot pool we wait - // in order to not bloat the KSYNC process - if snapshotInterval > 0 && !skipWaiting { - snapshotPoolHeight = stateSyncHelpers.GetSnapshotPoolHeight(chainRest, snapshotPoolId) - - if continuationHeight > snapshotPoolHeight+(utils.SnapshotPruningAheadFactor*snapshotInterval) { - logger.Info().Msg("synced too far ahead of snapshot pool. Waiting for snapshot pool to produce new bundles") - } - - for { - // if we are in that range we wait until the snapshot pool moved on - if continuationHeight > snapshotPoolHeight+(utils.SnapshotPruningAheadFactor*snapshotInterval) { - time.Sleep(10 * time.Second) - - // refresh snapshot pool height - snapshotPoolHeight = stateSyncHelpers.GetSnapshotPoolHeight(chainRest, snapshotPoolId) - continue - } - - break - } - } - - for { - select { - case err := <-errorCh: - return fmt.Errorf("error in block collector: %w", err) - case item := <-itemCh: - // parse block height from item key - height, err := utils.ParseBlockHeightFromKey(item.Key) - if err != nil { - return fmt.Errorf("failed parse block height from key %s: %w", item.Key, err) - } - - prevHeight := height - 1 - - if err := engine.ApplyBlock(runtime, item.Value); err != nil { - return fmt.Errorf("failed to apply block in engine: %w", err) - } - - // if we have reached a height where a snapshot should be created by the app - // we wait until it is created, else if KSYNC moves to fast the snapshot can - // not be properly written to disk. We check if the initial app height is smaller - // than the current applied height since in this case the app has not created the - // snapshot yet. - if snapshotInterval > 0 && prevHeight%snapshotInterval == 0 && appHeight < prevHeight { - for { - logger.Info().Msg(fmt.Sprintf("waiting until snapshot at height %d is created by app", prevHeight)) - - found, err := engine.IsSnapshotAvailable(prevHeight) - if err != nil { - logger.Error().Msg(fmt.Sprintf("check snapshot availability failed at height %d", prevHeight)) - time.Sleep(10 * time.Second) - continue - } - - if !found { - logger.Info().Msg(fmt.Sprintf("snapshot at height %d was not created yet. Waiting ...", prevHeight)) - time.Sleep(10 * time.Second) - continue - } - - logger.Info().Msg(fmt.Sprintf("snapshot at height %d was created. Continuing ...", prevHeight)) - break - } - - // refresh snapshot pool height here, because we don't want to fetch this on every block - snapshotPoolHeight = stateSyncHelpers.GetSnapshotPoolHeight(chainRest, snapshotPoolId) - } - - // skip below operations because we don't want to execute them already - // on the first block - if height == continuationHeight { - continue - } - - if pruning && prevHeight%utils.PruningInterval == 0 { - // Because we sync 3 * snapshot_interval ahead we keep the latest - // 6 * snapshot_interval blocks and prune everything before that - height := engine.GetHeight() - (utils.SnapshotPruningWindowFactor * snapshotInterval) - - if height < engine.GetBaseHeight() { - height = engine.GetBaseHeight() - } - - if err := engine.PruneBlocks(height); err != nil { - logger.Error().Msg(fmt.Sprintf("failed to prune blocks up to %d: %s", height, err)) - } - - logger.Info().Msg(fmt.Sprintf("pruned blocks to height %d", height)) - } - - // create backup of entire data directory if backup interval is reached - if backupCfg != nil && backupCfg.Interval > 0 && prevHeight%backupCfg.Interval == 0 { - logger.Info().Msg("reached backup interval height, starting to create backup") - - time.Sleep(time.Second * 15) - - chainId, err := engine.GetChainId() - if err != nil { - return fmt.Errorf("failed to get chain id from genesis: %w") - } - - if err = backup.CreateBackup(backupCfg, chainId, prevHeight, false); err != nil { - logger.Error().Msg(fmt.Sprintf("failed to create backup: %v", err)) - } - - logger.Info().Msg(fmt.Sprintf("finished backup at block height: %d", prevHeight)) - } - - // if KSYNC has already fetched 3 * snapshot_interval ahead of the snapshot pool we wait - // in order to not bloat the KSYNC process. If skipWaiting is true we sync as far as possible - if snapshotInterval > 0 && !skipWaiting { - // only log this message once - if height > snapshotPoolHeight+(utils.SnapshotPruningAheadFactor*snapshotInterval) { - logger.Info().Msg("synced too far ahead of snapshot pool. Waiting for snapshot pool to produce new bundles") - } - - for { - // if we are in that range we wait until the snapshot pool moved on - if height > snapshotPoolHeight+(utils.SnapshotPruningAheadFactor*snapshotInterval) { - time.Sleep(10 * time.Second) - - // refresh snapshot pool height - snapshotPoolHeight = stateSyncHelpers.GetSnapshotPoolHeight(chainRest, snapshotPoolId) - continue - } - - break - } - } - - // stop with block execution if we have reached our target height - if targetHeight > 0 && height >= targetHeight+1 { - if err := engine.StopProxyApp(); err != nil { - return fmt.Errorf("failed to stop proxy app: %w", err) - } - - return nil - } - } - } -} diff --git a/blocksync/helpers/helpers.go b/blocksync/helpers/helpers.go deleted file mode 100644 index 792aac9..0000000 --- a/blocksync/helpers/helpers.go +++ /dev/null @@ -1,51 +0,0 @@ -package helpers - -import ( - "fmt" - "github.com/KYVENetwork/ksync/collectors/pool" - "github.com/KYVENetwork/ksync/types" - "github.com/KYVENetwork/ksync/utils" -) - -func GetBlockBoundaries(restEndpoint string, blockRpcConfig *types.BlockRpcConfig, poolId *int64) (*types.PoolResponse, int64, int64, error) { - if poolId != nil { - return getBlockBoundariesFromPool(restEndpoint, *poolId) - } - if blockRpcConfig != nil { - return getBlockBoundariesFromRpc(*blockRpcConfig) - } - return nil, 0, 0, fmt.Errorf("both block rpc and pool id are nil") -} - -func getBlockBoundariesFromPool(restEndpoint string, poolId int64) (*types.PoolResponse, int64, int64, error) { - // load start and latest height - poolResponse, err := pool.GetPoolInfo(restEndpoint, poolId) - if err != nil { - return nil, 0, 0, fmt.Errorf("failed to get pool info: %w", err) - } - - if poolResponse.Pool.Data.Runtime != utils.KSyncRuntimeTendermint && poolResponse.Pool.Data.Runtime != utils.KSyncRuntimeTendermintBsync { - return nil, 0, 0, fmt.Errorf("found invalid runtime on pool %d: Expected = %s,%s Found = %s", poolId, utils.KSyncRuntimeTendermint, utils.KSyncRuntimeTendermintBsync, poolResponse.Pool.Data.Runtime) - } - - startHeight, err := utils.ParseBlockHeightFromKey(poolResponse.Pool.Data.StartKey) - if err != nil { - return nil, 0, 0, fmt.Errorf("could not parse int from %s", poolResponse.Pool.Data.StartKey) - } - - endHeight, err := utils.ParseBlockHeightFromKey(poolResponse.Pool.Data.CurrentKey) - if err != nil { - return nil, 0, 0, fmt.Errorf("could not parse int from %s", poolResponse.Pool.Data.CurrentKey) - } - - return poolResponse, startHeight, endHeight, nil -} - -func getBlockBoundariesFromRpc(blockRpcConfig types.BlockRpcConfig) (*types.PoolResponse, int64, int64, error) { - status, err := utils.GetStatusFromRpc(blockRpcConfig) - if err != nil { - return nil, 0, 0, fmt.Errorf("failed to get status from rpc: %w", err) - } - - return nil, status.Result.SyncInfo.EarliestBlockHeight, status.Result.SyncInfo.LatestBlockHeight, nil -} diff --git a/bootstrap/bootstrap.go b/bootstrap/bootstrap.go deleted file mode 100644 index 85e850d..0000000 --- a/bootstrap/bootstrap.go +++ /dev/null @@ -1,138 +0,0 @@ -package bootstrap - -import ( - "fmt" - blocksyncHelpers "github.com/KYVENetwork/ksync/blocksync/helpers" - "github.com/KYVENetwork/ksync/bootstrap/helpers" - "github.com/KYVENetwork/ksync/collectors/blocks" - "github.com/KYVENetwork/ksync/types" - "github.com/KYVENetwork/ksync/utils" - "strings" - "time" -) - -var ( - logger = utils.KsyncLogger("bootstrap") -) - -func StartBootstrapWithBinary(engine types.Engine, binaryPath, homePath, chainRest, storageRest string, blockRpcConfig *types.BlockRpcConfig, poolId *int64, appFlags string, debug bool) error { - logger.Info().Msg("starting bootstrap") - - if err := engine.OpenDBs(); err != nil { - return fmt.Errorf("failed to open dbs in engine: %w", err) - } - - defer func() { - err := engine.CloseDBs() - _ = err - }() - - gt100, err := utils.IsFileGreaterThanOrEqualTo100MB(engine.GetGenesisPath()) - if err != nil { - return err - } - - // if genesis file is smaller than 100MB we can skip further bootstrapping - if !gt100 { - logger.Info().Msg("KSYNC is successfully bootstrapped!") - return nil - } - - genesisHeight, err := engine.GetGenesisHeight() - if err != nil { - return err - } - - // if the app already has mined at least one block we can skip further bootstrapping - if engine.GetHeight() > genesisHeight { - logger.Info().Msg("KSYNC is successfully bootstrapped!") - return nil - } - - // if we reached this point we have to sync over p2p - poolResponse, startHeight, endHeight, err := blocksyncHelpers.GetBlockBoundaries(chainRest, blockRpcConfig, poolId) - if err != nil { - return fmt.Errorf("failed to get block boundaries: %w", err) - } - - if genesisHeight < startHeight { - return fmt.Errorf(fmt.Sprintf("genesis height %d smaller than pool start height %d", genesisHeight, startHeight)) - } - - if genesisHeight+1 > endHeight { - return fmt.Errorf(fmt.Sprintf("genesis height %d bigger than latest pool height %d", genesisHeight+1, endHeight)) - } - - item, err := blocks.RetrieveBlock(chainRest, storageRest, blockRpcConfig, poolResponse, genesisHeight) - if err != nil { - return fmt.Errorf("failed to retrieve block %d from pool", genesisHeight) - } - - nextItem, err := blocks.RetrieveBlock(chainRest, storageRest, blockRpcConfig, poolResponse, genesisHeight+1) - if err != nil { - return fmt.Errorf("failed to retrieve block %d from pool", genesisHeight+1) - } - - if err := engine.CloseDBs(); err != nil { - return fmt.Errorf("failed to close dbs in engine: %w", err) - } - - // start binary process thread - processId, err := utils.StartBinaryProcessForP2P(engine, binaryPath, debug, strings.Split(appFlags, ",")) - if err != nil { - return err - } - - logger.Info().Msg("bootstrapping node. Depending on the size of the genesis file, this step can take several minutes") - - // wait until binary has properly started by testing if the /abci - // endpoint is up - for { - if _, err := helpers.GetAppHeightFromRPC(homePath); err != nil { - time.Sleep(5 * time.Second) - continue - } - break - } - - logger.Info().Msg("loaded genesis file and completed ABCI handshake between app and tendermint") - - // start p2p executors and try to execute the first block on the app - if err := engine.ApplyFirstBlockOverP2P(poolResponse.Pool.Data.Runtime, item.Value, nextItem.Value); err != nil { - // stop binary process thread - if err := utils.StopProcessByProcessId(processId); err != nil { - panic(err) - } - - return fmt.Errorf("failed to start p2p executor: %w", err) - } - - // wait until block was properly executed by testing if the /abci - // endpoint returns the correct block height - for { - height, err := helpers.GetAppHeightFromRPC(homePath) - if err != nil { - return err - } - - if height != genesisHeight { - time.Sleep(5 * time.Second) - continue - } - - break - } - - logger.Info().Msg("node was bootstrapped. Cleaning up") - - // stop process by sending signal SIGTERM - if err := utils.StopProcessByProcessId(processId); err != nil { - return err - } - - // wait until process has properly shut down - time.Sleep(10 * time.Second) - - logger.Info().Msg("successfully bootstrapped node. Continuing with syncing blocks over DB") - return nil -} diff --git a/bootstrap/helpers/helpers.go b/bootstrap/helpers/helpers.go deleted file mode 100644 index 2fd03bb..0000000 --- a/bootstrap/helpers/helpers.go +++ /dev/null @@ -1,58 +0,0 @@ -package helpers - -import ( - "fmt" - "github.com/KYVENetwork/ksync/engines/tendermint-v34" - "github.com/KYVENetwork/ksync/types" - "github.com/KYVENetwork/ksync/utils" - "github.com/tendermint/tendermint/libs/json" - "strconv" - "strings" -) - -func GetAppHeightFromRPC(homePath string) (height int64, err error) { - config, err := tendermint_v34.LoadConfig(homePath) - if err != nil { - panic(fmt.Errorf("failed to load config.toml: %w", err)) - } - - rpc := fmt.Sprintf("%s/abci_info", strings.Replace(config.RPC.ListenAddress, "tcp", "http", 1)) - - responseData, err := utils.GetFromUrl(rpc) - if err != nil { - return height, err - } - - var response types.HeightResponse - if err := json.Unmarshal(responseData, &response); err != nil { - return height, err - } - - if response.Result.Response.LastBlockHeight == "" { - return 0, nil - } - - height, err = strconv.ParseInt(response.Result.Response.LastBlockHeight, 10, 64) - if err != nil { - return height, err - } - - return -} - -func GetBlockHeightFromDB(homePath string) (int64, error) { - config, err := tendermint_v34.LoadConfig(homePath) - if err != nil { - return 0, err - } - - blockStoreDB, blockStore, err := tendermint_v34.GetBlockstoreDBs(config) - defer blockStoreDB.Close() - - if err != nil { - return 0, err - } - - height := blockStore.Height() - return height, nil -} diff --git a/cmd/ksync/commands/backup.go b/cmd/ksync/commands/backup.go deleted file mode 100644 index 67a6b46..0000000 --- a/cmd/ksync/commands/backup.go +++ /dev/null @@ -1,85 +0,0 @@ -package commands - -import ( - "fmt" - "github.com/KYVENetwork/ksync/backup" - "github.com/KYVENetwork/ksync/engines/tendermint-v34" - "github.com/KYVENetwork/ksync/utils" - "github.com/spf13/cobra" - nm "github.com/tendermint/tendermint/node" -) - -func init() { - backupCmd.Flags().StringVarP(&binaryPath, "binary", "b", "", "binary path of node to be synced") - if err := backupCmd.MarkFlagRequired("binary"); err != nil { - panic(fmt.Errorf("flag 'binary' should be required: %w", err)) - } - - backupCmd.Flags().StringVarP(&homePath, "home", "h", "", "home directory") - - backupCmd.Flags().StringVar(&backupDest, "backup-dest", "", fmt.Sprintf("path where backups should be stored (default = %s)", utils.DefaultBackupPath)) - - backupCmd.Flags().StringVar(&backupCompression, "backup-compression", "", "compression type to compress backup directory ['tar.gz', 'zip', '']") - - backupCmd.Flags().Int64Var(&backupKeepRecent, "backup-keep-recent", 0, "number of kept backups (0 to keep all)") - - backupCmd.Flags().BoolVar(&optOut, "opt-out", false, "disable the collection of anonymous usage data") - - RootCmd.AddCommand(backupCmd) -} - -var backupCmd = &cobra.Command{ - Use: "backup", - Short: "Backup data directory", - RunE: func(cmd *cobra.Command, args []string) error { - utils.TrackBackupEvent(backupCompression, backupKeepRecent, optOut) - - // if no home path was given get the default one - if homePath == "" { - homePath = utils.GetHomePathFromBinary(binaryPath) - } - - // load tendermint config - config, err := tendermint_v34.LoadConfig(homePath) - if err != nil { - return fmt.Errorf("failed to load config.toml: %w", err) - } - - // load block store - blockStoreDB, blockStore, err := tendermint_v34.GetBlockstoreDBs(config) - defer blockStoreDB.Close() - - if err != nil { - return fmt.Errorf("fail to load blockstore db: %w", err) - } - - // load state store - stateDB, _, err := tendermint_v34.GetStateDBs(config) - defer stateDB.Close() - - if err != nil { - return fmt.Errorf("fail to load state db: %w", err) - } - - // load genesis file - defaultDocProvider := nm.DefaultGenesisDocProviderFunc(config) - _, genDoc, err := nm.LoadStateFromDBOrGenesisDocProvider(stateDB, defaultDocProvider) - if err != nil { - return fmt.Errorf("fail to load state from database: %w", err) - } - - // create backup config - backupCfg, err := backup.GetBackupConfig(homePath, 2, backupKeepRecent, backupCompression, backupDest) - if err != nil { - return fmt.Errorf("fail to load backup config: %w", err) - } - - // create backup - if err = backup.CreateBackup(backupCfg, genDoc.ChainID, blockStore.Height(), false); err != nil { - return fmt.Errorf("fail to create backup: %w", err) - } - - logger.Info().Int64("height", blockStore.Height()).Msg("finished backup at block height") - return nil - }, -} diff --git a/cmd/ksync/commands/blocksync.go b/cmd/ksync/commands/blocksync.go index 8fdc980..00b3973 100644 --- a/cmd/ksync/commands/blocksync.go +++ b/cmd/ksync/commands/blocksync.go @@ -1,51 +1,41 @@ package commands import ( - "errors" "fmt" - "github.com/KYVENetwork/ksync/backup" - "github.com/KYVENetwork/ksync/blocksync" - "github.com/KYVENetwork/ksync/engines" - "github.com/KYVENetwork/ksync/sources" + "github.com/KYVENetwork/ksync/flags" + "github.com/KYVENetwork/ksync/sync/blocksync" "github.com/KYVENetwork/ksync/utils" "github.com/spf13/cobra" - "strings" ) func init() { - blockSyncCmd.Flags().StringVarP(&engine, "engine", "e", "", fmt.Sprintf("consensus engine of the binary by default %s is used, list all engines with \"ksync engines\"", utils.DefaultEngine)) + blockSyncCmd.Flags().StringVarP(&flags.BinaryPath, "binary", "b", "", "binary path to the cosmos app") + if err := blockSyncCmd.MarkFlagRequired("binary"); err != nil { + panic(fmt.Errorf("flag 'binary' should be required: %w", err)) + } - blockSyncCmd.Flags().StringVarP(&binaryPath, "binary", "b", "", "binary path of node to be synced, if not provided the binary has to be started externally with --with-tendermint=false") + blockSyncCmd.Flags().StringVarP(&flags.HomePath, "home", "h", "", "home directory") - blockSyncCmd.Flags().StringVarP(&homePath, "home", "h", "", "home directory") + blockSyncCmd.Flags().StringVarP(&flags.ChainId, "chain-id", "c", utils.DefaultChainId, fmt.Sprintf("KYVE chain id [\"%s\",\"%s\",\"%s\"]", utils.ChainIdMainnet, utils.ChainIdKaon, utils.ChainIdKorellia)) - blockSyncCmd.Flags().StringVarP(&chainId, "chain-id", "c", utils.DefaultChainId, fmt.Sprintf("KYVE chain id [\"%s\",\"%s\",\"%s\"]", utils.ChainIdMainnet, utils.ChainIdKaon, utils.ChainIdKorellia)) + blockSyncCmd.Flags().StringVar(&flags.ChainRest, "chain-rest", "", "rest endpoint for KYVE chain") + blockSyncCmd.Flags().StringVar(&flags.StorageRest, "storage-rest", "", "storage endpoint for requesting bundle data") - blockSyncCmd.Flags().StringVar(&chainRest, "chain-rest", "", "rest endpoint for KYVE chain") - blockSyncCmd.Flags().StringVar(&storageRest, "storage-rest", "", "storage endpoint for requesting bundle data") + blockSyncCmd.Flags().StringVar(&flags.BlockPoolId, "block-pool-id", "", "pool-id of the block-sync pool") - blockSyncCmd.Flags().StringVarP(&source, "source", "s", "", "chain-id of the source") - blockSyncCmd.Flags().StringVar(®istryUrl, "registry-url", utils.DefaultRegistryURL, "URL to fetch latest KYVE Source-Registry") + blockSyncCmd.Flags().Int64VarP(&flags.TargetHeight, "target-height", "t", 0, "target height (including)") - blockSyncCmd.Flags().StringVar(&blockPoolId, "block-pool-id", "", "pool-id of the block-sync pool") + blockSyncCmd.Flags().BoolVar(&flags.RpcServer, "rpc-server", false, "rpc server serving /status, /block and /block_results") + blockSyncCmd.Flags().Int64Var(&flags.RpcServerPort, "rpc-server-port", utils.DefaultRpcServerPort, fmt.Sprintf("port for rpc server")) - blockSyncCmd.Flags().Int64VarP(&targetHeight, "target-height", "t", 0, "target height (including)") + blockSyncCmd.Flags().StringVarP(&flags.AppFlags, "app-flags", "f", "", "custom flags which are applied to the app binary start command. Example: --app-flags=\"--x-crisis-skip-assert-invariants,--iavl-disable-fastnode\"") - blockSyncCmd.Flags().BoolVar(&rpcServer, "rpc-server", false, "rpc server serving /status, /block and /block_results") - blockSyncCmd.Flags().Int64Var(&rpcServerPort, "rpc-server-port", utils.DefaultRpcServerPort, fmt.Sprintf("port for rpc server")) - - blockSyncCmd.Flags().Int64Var(&backupInterval, "backup-interval", 0, "block interval to write backups of data directory") - blockSyncCmd.Flags().Int64Var(&backupKeepRecent, "backup-keep-recent", 3, "number of latest backups to be keep (0 to keep all backups)") - blockSyncCmd.Flags().StringVar(&backupCompression, "backup-compression", "", "compression type used for backups (\"tar.gz\",\"zip\")") - blockSyncCmd.Flags().StringVar(&backupDest, "backup-dest", "", fmt.Sprintf("path where backups should be stored (default = %s)", utils.DefaultBackupPath)) - - blockSyncCmd.Flags().StringVarP(&appFlags, "app-flags", "f", "", "custom flags which are applied to the app binary start command. Example: --app-flags=\"--x-crisis-skip-assert-invariants,--iavl-disable-fastnode\"") - - blockSyncCmd.Flags().BoolVarP(&autoselectBinaryVersion, "autoselect-binary-version", "a", false, "if provided binary is cosmovisor KSYNC will automatically change the \"current\" symlink to the correct upgrade version") - blockSyncCmd.Flags().BoolVarP(&reset, "reset-all", "r", false, "reset this node's validator to genesis state") - blockSyncCmd.Flags().BoolVar(&optOut, "opt-out", false, "disable the collection of anonymous usage data") - blockSyncCmd.Flags().BoolVarP(&debug, "debug", "d", false, "show logs from tendermint app") - blockSyncCmd.Flags().BoolVarP(&y, "yes", "y", false, "automatically answer yes for all questions") + blockSyncCmd.Flags().BoolVarP(&flags.AutoSelectBinaryVersion, "auto-select-binary-version", "a", false, "if provided binary is cosmovisor KSYNC will automatically change the \"current\" symlink to the correct upgrade version") + blockSyncCmd.Flags().BoolVarP(&flags.Reset, "reset-all", "r", false, "reset this node's validator to genesis state") + blockSyncCmd.Flags().BoolVar(&flags.OptOut, "opt-out", false, "disable the collection of anonymous usage data") + blockSyncCmd.Flags().BoolVarP(&flags.Debug, "debug", "d", false, "run KSYNC in debug mode") + blockSyncCmd.Flags().BoolVarP(&flags.AppLogs, "app-logs", "l", false, "show logs from cosmos app") + blockSyncCmd.Flags().BoolVarP(&flags.Y, "yes", "y", false, "automatically answer yes for all questions") RootCmd.AddCommand(blockSyncCmd) } @@ -53,89 +43,7 @@ func init() { var blockSyncCmd = &cobra.Command{ Use: "block-sync", Short: "Start fast syncing blocks with KSYNC", - RunE: func(cmd *cobra.Command, args []string) error { - chainRest = utils.GetChainRest(chainId, chainRest) - storageRest = strings.TrimSuffix(storageRest, "/") - - // if no binary was provided at least the home path needs to be defined - if binaryPath == "" && homePath == "" { - return errors.New("flag 'home' is required") - } - - if binaryPath == "" { - logger.Info().Msg("to start the syncing process, start your chain binary with --with-tendermint=false") - } - - if homePath == "" { - homePath = utils.GetHomePathFromBinary(binaryPath) - logger.Info().Msgf("loaded home path \"%s\" from binary path", homePath) - } - - defaultEngine := engines.EngineFactory(engine, homePath, rpcServerPort) - - if source == "" && blockPoolId == "" { - s, err := defaultEngine.GetChainId() - if err != nil { - return fmt.Errorf("failed to load chain-id from engine: %w", err) - } - source = s - logger.Info().Msgf("loaded source \"%s\" from genesis file", source) - } - - bId, _, err := sources.GetPoolIds(chainId, source, blockPoolId, "", registryUrl, true, false) - if err != nil { - return fmt.Errorf("failed to load pool-ids: %w", err) - } - - backupCfg, err := backup.GetBackupConfig(homePath, backupInterval, backupKeepRecent, backupCompression, backupDest) - if err != nil { - return fmt.Errorf("could not get backup config: %w", err) - } - - if reset { - if err := defaultEngine.ResetAll(true); err != nil { - return fmt.Errorf("could not reset tendermint application: %w", err) - } - } - - if err := defaultEngine.OpenDBs(); err != nil { - return fmt.Errorf("failed to open dbs in engine: %w", err) - } - - continuationHeight, err := defaultEngine.GetContinuationHeight() - if err != nil { - return fmt.Errorf("failed to get continuation height: %w", err) - } - - // perform validation checks before booting state-sync process - if err := blocksync.PerformBlockSyncValidationChecks(chainRest, nil, &bId, continuationHeight, targetHeight, true, !y); err != nil { - return fmt.Errorf("block-sync validation checks failed: %w", err) - } - - if err := defaultEngine.CloseDBs(); err != nil { - return fmt.Errorf("failed to close dbs in engine: %w", err) - } - - if autoselectBinaryVersion { - if err := sources.SelectCosmovisorVersion(binaryPath, homePath, registryUrl, source, continuationHeight); err != nil { - return fmt.Errorf("failed to autoselect binary version: %w", err) - } - } - - if err := sources.IsBinaryRecommendedVersion(binaryPath, registryUrl, source, continuationHeight, !y); err != nil { - return fmt.Errorf("failed to check if binary has the recommended version: %w", err) - } - - if engine == "" && binaryPath != "" { - engine = utils.GetEnginePathFromBinary(binaryPath) - logger.Info().Msgf("loaded engine \"%s\" from binary path", engine) - } - - consensusEngine, err := engines.EngineSourceFactory(engine, homePath, registryUrl, source, rpcServerPort, continuationHeight) - if err != nil { - return fmt.Errorf("failed to create consensus engine for source: %w", err) - } - - return blocksync.StartBlockSyncWithBinary(consensusEngine, binaryPath, homePath, chainId, chainRest, storageRest, nil, &bId, targetHeight, backupCfg, appFlags, rpcServer, optOut, debug) + RunE: func(_ *cobra.Command, _ []string) error { + return blocksync.Start() }, } diff --git a/cmd/ksync/commands/engines.go b/cmd/ksync/commands/engines.go deleted file mode 100644 index 8da2006..0000000 --- a/cmd/ksync/commands/engines.go +++ /dev/null @@ -1,26 +0,0 @@ -package commands - -import ( - "fmt" - "github.com/KYVENetwork/ksync/utils" - "github.com/spf13/cobra" -) - -func init() { - enginesCmd.Flags().BoolVar(&optOut, "opt-out", false, "disable the collection of anonymous usage data") - - RootCmd.AddCommand(enginesCmd) -} - -var enginesCmd = &cobra.Command{ - Use: "engines", - Short: "Print all available engines for KSYNC", - RunE: func(cmd *cobra.Command, args []string) error { - utils.TrackEnginesEvent(optOut) - fmt.Printf("%s - %s\n", utils.EngineTendermintV34, "github.com/tendermint/tendermint v0.34.x") - fmt.Printf("%s - %s\n", utils.EngineCometBFTV37, "github.com/cometbft/cometbft v0.37.x") - fmt.Printf("%s - %s\n", utils.EngineCometBFTV38, "github.com/cometbft/cometbft v0.38.x") - fmt.Printf("%s - %s\n", utils.EngineCelestiaCoreV34, "github.com/celestiaorg/celestia-core v0.34.x-celestia") - return nil - }, -} diff --git a/cmd/ksync/commands/heightsync.go b/cmd/ksync/commands/heightsync.go index 075ce17..f5538fe 100644 --- a/cmd/ksync/commands/heightsync.go +++ b/cmd/ksync/commands/heightsync.go @@ -1,45 +1,39 @@ package commands import ( - "errors" "fmt" - "github.com/KYVENetwork/ksync/blocksync" - blocksyncHelpers "github.com/KYVENetwork/ksync/blocksync/helpers" - "github.com/KYVENetwork/ksync/engines" - "github.com/KYVENetwork/ksync/heightsync" - "github.com/KYVENetwork/ksync/sources" + "github.com/KYVENetwork/ksync/flags" + "github.com/KYVENetwork/ksync/sync/heightsync" "github.com/KYVENetwork/ksync/utils" "github.com/spf13/cobra" - "strings" ) func init() { - heightSyncCmd.Flags().StringVarP(&engine, "engine", "e", "", fmt.Sprintf("consensus engine of the binary by default %s is used, list all engines with \"ksync engines\"", utils.DefaultEngine)) + heightSyncCmd.Flags().StringVarP(&flags.BinaryPath, "binary", "b", "", "binary path to the cosmos app") + if err := blockSyncCmd.MarkFlagRequired("binary"); err != nil { + panic(fmt.Errorf("flag 'binary' should be required: %w", err)) + } - heightSyncCmd.Flags().StringVarP(&binaryPath, "binary", "b", "", "binary path of node to be synced, if not provided the binary has to be started externally with --with-tendermint=false") + heightSyncCmd.Flags().StringVarP(&flags.HomePath, "home", "h", "", "home directory") - heightSyncCmd.Flags().StringVarP(&homePath, "home", "h", "", "home directory") + heightSyncCmd.Flags().StringVarP(&flags.ChainId, "chain-id", "c", utils.DefaultChainId, fmt.Sprintf("KYVE chain id [\"%s\",\"%s\",\"%s\"]", utils.ChainIdMainnet, utils.ChainIdKaon, utils.ChainIdKorellia)) - heightSyncCmd.Flags().StringVarP(&chainId, "chain-id", "c", utils.DefaultChainId, fmt.Sprintf("KYVE chain id [\"%s\",\"%s\",\"%s\"]", utils.ChainIdMainnet, utils.ChainIdKaon, utils.ChainIdKorellia)) + heightSyncCmd.Flags().StringVar(&flags.ChainRest, "chain-rest", "", "rest endpoint for KYVE chain") + heightSyncCmd.Flags().StringVar(&flags.StorageRest, "storage-rest", "", "storage endpoint for requesting bundle data") - heightSyncCmd.Flags().StringVar(&chainRest, "chain-rest", "", "rest endpoint for KYVE chain") - heightSyncCmd.Flags().StringVar(&storageRest, "storage-rest", "", "storage endpoint for requesting bundle data") + heightSyncCmd.Flags().StringVar(&flags.SnapshotPoolId, "snapshot-pool-id", "", "pool-id of the state-sync pool") + heightSyncCmd.Flags().StringVar(&flags.BlockPoolId, "block-pool-id", "", "pool-id of the block-sync pool") - heightSyncCmd.Flags().StringVarP(&source, "source", "s", "", "chain-id of the source") - heightSyncCmd.Flags().StringVar(®istryUrl, "registry-url", utils.DefaultRegistryURL, "URL to fetch latest KYVE Source-Registry") + heightSyncCmd.Flags().StringVarP(&flags.AppFlags, "app-flags", "f", "", "custom flags which are applied to the app binary start command. Example: --app-flags=\"--x-crisis-skip-assert-invariants,--iavl-disable-fastnode\"") - heightSyncCmd.Flags().StringVar(&snapshotPoolId, "snapshot-pool-id", "", "pool-id of the state-sync pool") - heightSyncCmd.Flags().StringVar(&blockPoolId, "block-pool-id", "", "pool-id of the block-sync pool") + heightSyncCmd.Flags().Int64VarP(&flags.TargetHeight, "target-height", "t", 0, "target height (including), if not specified it will sync to the latest available block height") - heightSyncCmd.Flags().StringVarP(&appFlags, "app-flags", "f", "", "custom flags which are applied to the app binary start command. Example: --app-flags=\"--x-crisis-skip-assert-invariants,--iavl-disable-fastnode\"") - - heightSyncCmd.Flags().Int64VarP(&targetHeight, "target-height", "t", 0, "target height (including), if not specified it will sync to the latest available block height") - - heightSyncCmd.Flags().BoolVarP(&autoselectBinaryVersion, "autoselect-binary-version", "a", false, "if provided binary is cosmovisor KSYNC will automatically change the \"current\" symlink to the correct upgrade version") - heightSyncCmd.Flags().BoolVarP(&reset, "reset-all", "r", false, "reset this node's validator to genesis state") - heightSyncCmd.Flags().BoolVar(&optOut, "opt-out", false, "disable the collection of anonymous usage data") - heightSyncCmd.Flags().BoolVarP(&debug, "debug", "d", false, "show logs from tendermint app") - heightSyncCmd.Flags().BoolVarP(&y, "assumeyes", "y", false, "automatically answer yes for all questions") + heightSyncCmd.Flags().BoolVarP(&flags.AutoSelectBinaryVersion, "auto-select-binary-version", "a", false, "if provided binary is cosmovisor KSYNC will automatically change the \"current\" symlink to the correct upgrade version") + heightSyncCmd.Flags().BoolVarP(&flags.Reset, "reset-all", "r", false, "reset this node's validator to genesis state") + heightSyncCmd.Flags().BoolVar(&flags.OptOut, "opt-out", false, "disable the collection of anonymous usage data") + heightSyncCmd.Flags().BoolVarP(&flags.Debug, "debug", "d", false, "run KSYNC in debug mode") + heightSyncCmd.Flags().BoolVarP(&flags.AppLogs, "app-logs", "l", false, "show logs from cosmos app") + heightSyncCmd.Flags().BoolVarP(&flags.Y, "assumeyes", "y", false, "automatically answer yes for all questions") RootCmd.AddCommand(heightSyncCmd) } @@ -47,104 +41,7 @@ func init() { var heightSyncCmd = &cobra.Command{ Use: "height-sync", Short: "Sync fast to any height with state- and block-sync", - RunE: func(cmd *cobra.Command, args []string) error { - chainRest = utils.GetChainRest(chainId, chainRest) - storageRest = strings.TrimSuffix(storageRest, "/") - - // if no binary was provided at least the home path needs to be defined - if binaryPath == "" && homePath == "" { - return errors.New("flag 'home' is required") - } - - if binaryPath == "" { - logger.Info().Msg("To start the syncing process, start your chain binary with --with-tendermint=false") - } - - // if no home path was given get the default one - if homePath == "" { - homePath = utils.GetHomePathFromBinary(binaryPath) - } - - defaultEngine := engines.EngineFactory(engine, homePath, rpcServerPort) - - if source == "" && blockPoolId == "" && snapshotPoolId == "" { - s, err := defaultEngine.GetChainId() - if err != nil { - return fmt.Errorf("failed to load chain-id from engine: %w", err) - } - source = s - logger.Info().Msgf("Loaded source \"%s\" from genesis file", source) - } - - bId, sId, err := sources.GetPoolIds(chainId, source, blockPoolId, snapshotPoolId, registryUrl, true, true) - if err != nil { - return fmt.Errorf("failed to load pool-ids: %w", err) - } - - if reset { - if err := defaultEngine.ResetAll(true); err != nil { - return fmt.Errorf("could not reset tendermint application: %w", err) - } - } - - if err := defaultEngine.OpenDBs(); err != nil { - return fmt.Errorf("failed to open dbs in engine: %w", err) - } - - _, _, blockEndHeight, err := blocksyncHelpers.GetBlockBoundaries(chainRest, nil, &bId) - if err != nil { - return fmt.Errorf("failed to get block boundaries: %w", err) - } - - // if target height was not specified we sync to the latest available height - if targetHeight == 0 { - targetHeight = blockEndHeight - logger.Info().Msg(fmt.Sprintf("target height not specified, searching for latest available block height")) - } - - // perform validation checks before booting state-sync process - snapshotBundleId, snapshotHeight, err := heightsync.PerformHeightSyncValidationChecks(defaultEngine, chainRest, sId, &bId, targetHeight, !y) - if err != nil { - return fmt.Errorf("height-sync validation checks failed: %w", err) - } - - continuationHeight := snapshotHeight - if continuationHeight == 0 { - c, err := defaultEngine.GetContinuationHeight() - if err != nil { - return fmt.Errorf("failed to get continuation height: %w", err) - } - continuationHeight = c - } - - if err := blocksync.PerformBlockSyncValidationChecks(chainRest, nil, &bId, continuationHeight, targetHeight, true, false); err != nil { - return fmt.Errorf("block-sync validation checks failed: %w", err) - } - - if err := defaultEngine.CloseDBs(); err != nil { - return fmt.Errorf("failed to close dbs in engine: %w", err) - } - - if autoselectBinaryVersion { - if err := sources.SelectCosmovisorVersion(binaryPath, homePath, registryUrl, source, continuationHeight); err != nil { - return fmt.Errorf("failed to autoselect binary version: %w", err) - } - } - - if err := sources.IsBinaryRecommendedVersion(binaryPath, registryUrl, source, continuationHeight, !y); err != nil { - return fmt.Errorf("failed to check if binary has the recommended version: %w", err) - } - - if engine == "" && binaryPath != "" { - engine = utils.GetEnginePathFromBinary(binaryPath) - logger.Info().Msgf("Loaded engine \"%s\" from binary path", engine) - } - - consensusEngine, err := engines.EngineSourceFactory(engine, homePath, registryUrl, source, rpcServerPort, continuationHeight) - if err != nil { - return fmt.Errorf("failed to create consensus engine for source: %w", err) - } - - return heightsync.StartHeightSyncWithBinary(consensusEngine, binaryPath, homePath, chainId, chainRest, storageRest, sId, &bId, targetHeight, snapshotBundleId, snapshotHeight, appFlags, optOut, debug) + RunE: func(_ *cobra.Command, _ []string) error { + return heightsync.Start() }, } diff --git a/cmd/ksync/commands/info.go b/cmd/ksync/commands/info.go index 45cfefb..7e4673d 100644 --- a/cmd/ksync/commands/info.go +++ b/cmd/ksync/commands/info.go @@ -3,8 +3,8 @@ package commands import ( _ "embed" "fmt" - "github.com/KYVENetwork/ksync/sources" - "github.com/KYVENetwork/ksync/sources/helpers" + "github.com/KYVENetwork/ksync/app/source" + "github.com/KYVENetwork/ksync/flags" "github.com/KYVENetwork/ksync/utils" "github.com/jedib0t/go-pretty/v6/table" "github.com/spf13/cobra" @@ -12,14 +12,11 @@ import ( "sort" ) -var registryUrl string - func init() { - infoCmd.Flags().StringVarP(&chainId, "chain-id", "c", utils.DefaultChainId, fmt.Sprintf("KYVE chain id [\"%s\",\"%s\"]", utils.ChainIdMainnet, utils.ChainIdKaon)) - - infoCmd.Flags().StringVar(®istryUrl, "registry-url", utils.DefaultRegistryURL, "URL to fetch latest KYVE Source-Registry") + infoCmd.Flags().StringVarP(&flags.ChainId, "chain-id", "c", utils.DefaultChainId, fmt.Sprintf("KYVE chain id [\"%s\",\"%s\"]", utils.ChainIdMainnet, utils.ChainIdKaon)) - infoCmd.Flags().BoolVar(&optOut, "opt-out", false, "disable the collection of anonymous usage data") + infoCmd.Flags().BoolVar(&flags.OptOut, "opt-out", false, "disable the collection of anonymous usage data") + infoCmd.Flags().BoolVarP(&flags.Debug, "debug", "d", false, "run KSYNC in debug mode") RootCmd.AddCommand(infoCmd) } @@ -28,13 +25,11 @@ var infoCmd = &cobra.Command{ Use: "info", Short: "Get KSYNC chain support information", RunE: func(cmd *cobra.Command, args []string) error { - utils.TrackInfoEvent(chainId, optOut) - - if chainId != utils.ChainIdMainnet && chainId != utils.ChainIdKaon { - return fmt.Errorf("chain-id %s not supported", chainId) + if flags.ChainId != utils.ChainIdMainnet && flags.ChainId != utils.ChainIdKaon { + return fmt.Errorf("chain-id %s not supported", flags.ChainId) } - sourceRegistry, err := helpers.GetSourceRegistry(registryUrl) + sourceRegistry, err := source.GetSourceRegistry(utils.DefaultRegistryURL) if err != nil { return fmt.Errorf("failed to get source registry: %w", err) } @@ -48,7 +43,7 @@ var infoCmd = &cobra.Command{ var keys []string for key, entry := range sourceRegistry.Entries { - if chainId == utils.ChainIdMainnet { + if flags.ChainId == utils.ChainIdMainnet { if entry.Networks.Kyve != nil { if entry.Networks.Kyve.Integrations != nil { if entry.Networks.Kyve.Integrations.KSYNC != nil { @@ -57,7 +52,7 @@ var infoCmd = &cobra.Command{ } } } - if chainId == utils.ChainIdKaon { + if flags.ChainId == utils.ChainIdKaon { if entry.Networks.Kaon != nil { if entry.Networks.Kaon.Integrations != nil { if entry.Networks.Kaon.Integrations.KSYNC != nil { @@ -78,7 +73,7 @@ var infoCmd = &cobra.Command{ var title string - if chainId == utils.ChainIdMainnet { + if flags.ChainId == utils.ChainIdMainnet { if entry.Networks.Kyve != nil { if entry.Networks.Kyve.Integrations != nil { if entry.Networks.Kyve.Integrations.KSYNC == nil { @@ -89,7 +84,7 @@ var infoCmd = &cobra.Command{ } else { continue } - } else if chainId == utils.ChainIdKaon { + } else if flags.ChainId == utils.ChainIdKaon { if entry.Networks.Kaon != nil { if entry.Networks.Kaon.Integrations != nil { if entry.Networks.Kaon.Integrations.KSYNC == nil { @@ -102,7 +97,7 @@ var infoCmd = &cobra.Command{ } } - blockSync, stateSync, heightSync := sources.FormatOutput(&entry, chainId) + blockSync, stateSync, heightSync := source.FormatOutput(&entry, flags.ChainId) t.AppendRows([]table.Row{ { title, diff --git a/cmd/ksync/commands/prune.go b/cmd/ksync/commands/prune.go deleted file mode 100644 index b971062..0000000 --- a/cmd/ksync/commands/prune.go +++ /dev/null @@ -1,67 +0,0 @@ -package commands - -import ( - "fmt" - "github.com/KYVENetwork/ksync/engines/tendermint-v34" - "github.com/KYVENetwork/ksync/utils" - "github.com/spf13/cobra" - "os" -) - -var ( - untilHeight int64 -) - -func init() { - pruneCmd.Flags().StringVarP(&homePath, "home", "h", "", "home directory") - - pruneCmd.Flags().Int64Var(&untilHeight, "until-height", 0, "prune blocks until this height (excluding)") - if err := pruneCmd.MarkFlagRequired("until-height"); err != nil { - panic(fmt.Errorf("flag 'until-height' should be required: %w", err)) - } - - pruneCmd.Flags().BoolVar(&optOut, "opt-out", false, "disable the collection of anonymous usage data") - - // Disable pruning for now until we find a way to properly prune - // blockstore.db, state.db and application.db - //rootCmd.AddCommand(pruneCmd) -} - -var pruneCmd = &cobra.Command{ - Use: "prune-blocks", - Short: "Prune blocks until a specific height", - Run: func(cmd *cobra.Command, args []string) { - utils.TrackPruningEvent(untilHeight, optOut) - - // if no home path was given get the default one - if homePath == "" { - homePath = utils.GetHomePathFromBinary(binaryPath) - } - - config, err := tendermint_v34.LoadConfig(homePath) - if err != nil { - panic(fmt.Errorf("failed to load config: %w", err)) - } - - blockStoreDB, blockStore, err := tendermint_v34.GetBlockstoreDBs(config) - defer blockStoreDB.Close() - - if err != nil { - panic(fmt.Errorf("failed to load blockstore db: %w", err)) - } - - base := blockStore.Base() - - if untilHeight < base { - fmt.Printf("Error: base height %d is higher than prune height %d\n", base, untilHeight) - os.Exit(0) - } - - blocks, err := blockStore.PruneBlocks(untilHeight) - if err != nil { - panic(err) - } - - fmt.Printf("Pruned %d blocks, new base height is %d\n", blocks, blockStore.Base()) - }, -} diff --git a/cmd/ksync/commands/resetall.go b/cmd/ksync/commands/resetall.go index f9d2885..ab316c1 100644 --- a/cmd/ksync/commands/resetall.go +++ b/cmd/ksync/commands/resetall.go @@ -2,22 +2,22 @@ package commands import ( "fmt" - "github.com/KYVENetwork/ksync/engines" - "github.com/KYVENetwork/ksync/utils" + "github.com/KYVENetwork/ksync/app" + "github.com/KYVENetwork/ksync/flags" + "github.com/KYVENetwork/ksync/logger" "github.com/spf13/cobra" ) func init() { - resetCmd.Flags().StringVarP(&engine, "engine", "e", "", fmt.Sprintf("consensus engine of the binary by default %s is used, list all engines with \"ksync engines\"", utils.DefaultEngine)) - - resetCmd.Flags().StringVar(&homePath, "home", "", "home directory") + resetCmd.Flags().StringVar(&flags.HomePath, "home", "", "home directory") if err := resetCmd.MarkFlagRequired("home"); err != nil { panic(fmt.Errorf("flag 'home' should be required: %w", err)) } - resetCmd.Flags().BoolVar(&keepAddrBook, "keep-addr-book", true, "keep the address book intact") + resetCmd.Flags().BoolVar(&flags.KeepAddrBook, "keep-addr-book", true, "keep the address book intact") - resetCmd.Flags().BoolVar(&optOut, "opt-out", false, "disable the collection of anonymous usage data") + resetCmd.Flags().BoolVar(&flags.OptOut, "opt-out", false, "disable the collection of anonymous usage data") + resetCmd.Flags().BoolVarP(&flags.Debug, "debug", "d", false, "run KSYNC in debug mode") RootCmd.AddCommand(resetCmd) } @@ -26,13 +26,16 @@ var resetCmd = &cobra.Command{ Use: "reset-all", Short: "Removes all the data and WAL, reset this node's validator to genesis state", RunE: func(cmd *cobra.Command, args []string) error { - utils.TrackResetEvent(optOut) + app, err := app.NewCosmosApp() + if err != nil { + return fmt.Errorf("failed to init cosmos app: %w", err) + } - if err := engines.EngineFactory(engine, homePath, rpcServerPort).ResetAll(keepAddrBook); err != nil { - return fmt.Errorf("failed to reset tendermint application: %w", err) + if err := app.ConsensusEngine.ResetAll(true); err != nil { + return fmt.Errorf("failed to reset cosmos app: %w", err) } - logger.Info().Msg("successfully reset tendermint application") + logger.Logger.Info().Msg("successfully reset cosmos app") return nil }, } diff --git a/cmd/ksync/commands/root.go b/cmd/ksync/commands/root.go index c20a155..e100fb8 100644 --- a/cmd/ksync/commands/root.go +++ b/cmd/ksync/commands/root.go @@ -1,69 +1,46 @@ package commands import ( - "github.com/KYVENetwork/ksync/utils" + "github.com/KYVENetwork/ksync/flags" + "github.com/KYVENetwork/ksync/metrics" + "github.com/rs/zerolog" "github.com/spf13/cobra" "os" ) -var ( - engine string - binaryPath string - homePath string - chainId string - chainRest string - storageRest string - blockRpc string - snapshotPoolId string - blockPoolId string - startHeight int64 - targetHeight int64 - rpcServer bool - rpcServerPort int64 - snapshotPort int64 - blockRpcReqTimeout int64 - source string - pruning bool - keepSnapshots bool - skipWaiting bool - backupInterval int64 - backupKeepRecent int64 - backupCompression string - backupDest string - appFlags string - autoselectBinaryVersion bool - reset bool - keepAddrBook bool - optOut bool - debug bool - y bool -) - -var ( - logger = utils.KsyncLogger("commands") -) - // RootCmd is the root command for KSYNC. var RootCmd = &cobra.Command{ Use: "ksync", Short: "Fast Sync validated and archived blocks from KYVE to every Tendermint based Blockchain Application", + PersistentPreRun: func(cmd *cobra.Command, args []string) { + if flags.Debug { + zerolog.SetGlobalLevel(zerolog.DebugLevel) + } + + metrics.SetCommand(cmd.Use) + }, } func Execute() { - backupCmd.Flags().SortFlags = false + metrics.CatchInterrupt() + blockSyncCmd.Flags().SortFlags = false heightSyncCmd.Flags().SortFlags = false - pruneCmd.Flags().SortFlags = false resetCmd.Flags().SortFlags = false servesnapshotsCmd.Flags().SortFlags = false serveBlocksCmd.Flags().SortFlags = false stateSyncCmd.Flags().SortFlags = false versionCmd.Flags().SortFlags = false - // overwrite help command so we can use -h as a shortcut + // overwrite help command so we can use -h as a shortcut for home RootCmd.PersistentFlags().BoolP("help", "", false, "help for this command") - if err := RootCmd.Execute(); err != nil { + errorRuntime := RootCmd.Execute() + + metrics.SendTrack(errorRuntime) + metrics.WaitForInterrupt() + + if errorRuntime != nil { os.Exit(1) } } diff --git a/cmd/ksync/commands/serveblocks.go b/cmd/ksync/commands/serveblocks.go index 880874a..91ff95d 100644 --- a/cmd/ksync/commands/serveblocks.go +++ b/cmd/ksync/commands/serveblocks.go @@ -2,48 +2,40 @@ package commands import ( "fmt" - "github.com/KYVENetwork/ksync/backup" - "github.com/KYVENetwork/ksync/blocksync" - "github.com/KYVENetwork/ksync/engines" - "github.com/KYVENetwork/ksync/sources" - "github.com/KYVENetwork/ksync/types" + "github.com/KYVENetwork/ksync/flags" + "github.com/KYVENetwork/ksync/sync/blocksync" "github.com/KYVENetwork/ksync/utils" "github.com/spf13/cobra" - "time" ) func init() { - serveBlocksCmd.Flags().StringVarP(&engine, "engine", "e", "", fmt.Sprintf("consensus engine of the binary by default %s is used, list all engines with \"ksync engines\"", utils.DefaultEngine)) - - serveBlocksCmd.Flags().StringVarP(&binaryPath, "binary", "b", "", "binary path of node to be synced") + serveBlocksCmd.Flags().StringVarP(&flags.BinaryPath, "binary", "b", "", "binary path to the cosmos app") if err := serveBlocksCmd.MarkFlagRequired("binary"); err != nil { panic(fmt.Errorf("flag 'binary' should be required: %w", err)) } - serveBlocksCmd.Flags().StringVarP(&homePath, "home", "h", "", "home directory") + serveBlocksCmd.Flags().StringVarP(&flags.HomePath, "home", "h", "", "home directory") - serveBlocksCmd.Flags().StringVar(&blockRpc, "block-rpc", "", "rpc endpoint of the source node to sync blocks from") + serveBlocksCmd.Flags().StringVar(&flags.BlockRpc, "block-rpc", "", "rpc endpoint of the source node to sync blocks from") if err := serveBlocksCmd.MarkFlagRequired("block-rpc"); err != nil { panic(fmt.Errorf("flag 'block-rpc' should be required: %w", err)) } - serveBlocksCmd.Flags().StringVarP(&appFlags, "app-flags", "f", "", "custom flags which are applied to the app binary start command. Example: --app-flags=\"--x-crisis-skip-assert-invariants,--iavl-disable-fastnode\"") - - serveBlocksCmd.Flags().Int64VarP(&targetHeight, "target-height", "t", 0, "the height at which KSYNC will exit once reached") + serveBlocksCmd.Flags().StringVarP(&flags.AppFlags, "app-flags", "f", "", "custom flags which are applied to the app binary start command. Example: --app-flags=\"--x-crisis-skip-assert-invariants,--iavl-disable-fastnode\"") - serveBlocksCmd.Flags().Int64Var(&blockRpcReqTimeout, "block-rpc-req-timeout", utils.RequestBlocksTimeoutMS, "port where the block api server will be started") + serveBlocksCmd.Flags().Int64VarP(&flags.TargetHeight, "target-height", "t", 0, "the height at which KSYNC will exit once reached") - serveBlocksCmd.Flags().BoolVar(&rpcServer, "rpc-server", true, "rpc server serving /status, /block and /block_results") - serveBlocksCmd.Flags().Int64Var(&rpcServerPort, "rpc-server-port", utils.DefaultRpcServerPort, "port where the rpc server will be started") + serveBlocksCmd.Flags().Int64Var(&flags.BlockRpcReqTimeout, "block-rpc-req-timeout", utils.RequestBlocksTimeoutMS, "port where the block api server will be started") - serveBlocksCmd.Flags().StringVarP(&source, "source", "s", "", "chain-id of the source") - serveBlocksCmd.Flags().StringVar(®istryUrl, "registry-url", utils.DefaultRegistryURL, "URL to fetch latest KYVE Source-Registry") + serveBlocksCmd.Flags().BoolVar(&flags.RpcServer, "rpc-server", true, "rpc server serving /status, /block and /block_results") + serveBlocksCmd.Flags().Int64Var(&flags.RpcServerPort, "rpc-server-port", utils.DefaultRpcServerPort, "port where the rpc server will be started") - serveBlocksCmd.Flags().BoolVarP(&autoselectBinaryVersion, "autoselect-binary-version", "a", false, "if provided binary is cosmovisor KSYNC will automatically change the \"current\" symlink to the correct upgrade version") - serveBlocksCmd.Flags().BoolVarP(&reset, "reset-all", "r", false, "reset this node's validator to genesis state") - serveBlocksCmd.Flags().BoolVar(&optOut, "opt-out", false, "disable the collection of anonymous usage data") - serveBlocksCmd.Flags().BoolVarP(&debug, "debug", "d", false, "show logs from tendermint app") - serveBlocksCmd.Flags().BoolVarP(&y, "yes", "y", false, "automatically answer yes for all questions") + serveBlocksCmd.Flags().BoolVarP(&flags.AutoSelectBinaryVersion, "auto-select-binary-version", "a", false, "if provided binary is cosmovisor KSYNC will automatically change the \"current\" symlink to the correct upgrade version") + serveBlocksCmd.Flags().BoolVarP(&flags.Reset, "reset-all", "r", false, "reset this node's validator to genesis state") + serveBlocksCmd.Flags().BoolVar(&flags.OptOut, "opt-out", false, "disable the collection of anonymous usage data") + serveBlocksCmd.Flags().BoolVarP(&flags.Debug, "debug", "d", false, "run KSYNC in debug mode") + serveBlocksCmd.Flags().BoolVarP(&flags.AppLogs, "app-logs", "l", false, "show logs from cosmos app") + serveBlocksCmd.Flags().BoolVarP(&flags.Y, "yes", "y", false, "automatically answer yes for all questions") RootCmd.AddCommand(serveBlocksCmd) } @@ -51,80 +43,7 @@ func init() { var serveBlocksCmd = &cobra.Command{ Use: "serve-blocks", Short: "Start fast syncing blocks from RPC endpoints with KSYNC", - RunE: func(cmd *cobra.Command, args []string) error { - chainRest = "" - storageRest = "" - - blockRpcConfig := types.BlockRpcConfig{ - Endpoint: blockRpc, - RequestTimeout: time.Duration(blockRpcReqTimeout * int64(time.Millisecond)), - } - - // if no home path was given get the default one - if homePath == "" { - homePath = utils.GetHomePathFromBinary(binaryPath) - } - - defaultEngine := engines.EngineFactory(engine, homePath, rpcServerPort) - - if source == "" && blockPoolId == "" { - s, err := defaultEngine.GetChainId() - if err != nil { - return fmt.Errorf("failed to load chain-id from engine: %w", err) - } - source = s - logger.Info().Msgf("Loaded source \"%s\" from genesis file", source) - } - - backupCfg, err := backup.GetBackupConfig(homePath, backupInterval, backupKeepRecent, backupCompression, backupDest) - if err != nil { - return fmt.Errorf("could not get backup config: %w", err) - } - - if reset { - if err := defaultEngine.ResetAll(true); err != nil { - return fmt.Errorf("could not reset tendermint application: %w", err) - } - } - - if err := defaultEngine.OpenDBs(); err != nil { - return fmt.Errorf("failed to open dbs in engine: %w", err) - } - - continuationHeight, err := defaultEngine.GetContinuationHeight() - if err != nil { - return fmt.Errorf("failed to get continuation height: %w", err) - } - - // perform validation checks before booting block-sync process - if err := blocksync.PerformBlockSyncValidationChecks(chainRest, &blockRpcConfig, nil, continuationHeight, targetHeight, true, !y); err != nil { - return fmt.Errorf("block-sync validation checks failed: %w", err) - } - - if err := defaultEngine.CloseDBs(); err != nil { - return fmt.Errorf("failed to close dbs in engine: %w", err) - } - - if autoselectBinaryVersion { - if err := sources.SelectCosmovisorVersion(binaryPath, homePath, registryUrl, source, continuationHeight); err != nil { - return fmt.Errorf("failed to autoselect binary version: %w", err) - } - } - - if err := sources.IsBinaryRecommendedVersion(binaryPath, registryUrl, source, continuationHeight, !y); err != nil { - return fmt.Errorf("failed to check if binary has the recommended version: %w", err) - } - - if engine == "" && binaryPath != "" { - engine = utils.GetEnginePathFromBinary(binaryPath) - logger.Info().Msgf("Loaded engine \"%s\" from binary path", engine) - } - - consensusEngine, err := engines.EngineSourceFactory(engine, homePath, registryUrl, source, rpcServerPort, continuationHeight) - if err != nil { - return fmt.Errorf("failed to create consensus engine for source: %w", err) - } - - return blocksync.StartBlockSyncWithBinary(consensusEngine, binaryPath, homePath, chainId, chainRest, storageRest, &blockRpcConfig, nil, targetHeight, backupCfg, appFlags, rpcServer, optOut, debug) + RunE: func(_ *cobra.Command, _ []string) error { + return blocksync.Start() }, } diff --git a/cmd/ksync/commands/servesnapshots.go b/cmd/ksync/commands/servesnapshots.go index 44e7236..122d3d5 100644 --- a/cmd/ksync/commands/servesnapshots.go +++ b/cmd/ksync/commands/servesnapshots.go @@ -2,54 +2,47 @@ package commands import ( "fmt" - "github.com/KYVENetwork/ksync/blocksync" - "github.com/KYVENetwork/ksync/engines" - "github.com/KYVENetwork/ksync/servesnapshots" - "github.com/KYVENetwork/ksync/sources" + "github.com/KYVENetwork/ksync/flags" + "github.com/KYVENetwork/ksync/sync/servesnapshots" "github.com/KYVENetwork/ksync/utils" "github.com/spf13/cobra" - "strings" ) func init() { - servesnapshotsCmd.Flags().StringVarP(&engine, "engine", "e", "", fmt.Sprintf("consensus engine of the binary by default %s is used, list all engines with \"ksync engines\"", utils.DefaultEngine)) - - servesnapshotsCmd.Flags().StringVarP(&binaryPath, "binary", "b", "", "binary path of node to be synced") + servesnapshotsCmd.Flags().StringVarP(&flags.BinaryPath, "binary", "b", "", "binary path to the cosmos app") if err := servesnapshotsCmd.MarkFlagRequired("binary"); err != nil { panic(fmt.Errorf("flag 'binary' should be required: %w", err)) } - servesnapshotsCmd.Flags().StringVarP(&homePath, "home", "h", "", "home directory") - - servesnapshotsCmd.Flags().StringVarP(&chainId, "chain-id", "c", utils.DefaultChainId, fmt.Sprintf("KYVE chain id [\"%s\",\"%s\",\"%s\"]", utils.ChainIdMainnet, utils.ChainIdKaon, utils.ChainIdKorellia)) + servesnapshotsCmd.Flags().StringVarP(&flags.HomePath, "home", "h", "", "home directory") - servesnapshotsCmd.Flags().StringVar(&chainRest, "chain-rest", "", "rest endpoint for KYVE chain") - servesnapshotsCmd.Flags().StringVar(&storageRest, "storage-rest", "", "storage endpoint for requesting bundle data") + servesnapshotsCmd.Flags().StringVarP(&flags.ChainId, "chain-id", "c", utils.DefaultChainId, fmt.Sprintf("KYVE chain id [\"%s\",\"%s\",\"%s\"]", utils.ChainIdMainnet, utils.ChainIdKaon, utils.ChainIdKorellia)) - servesnapshotsCmd.Flags().StringVarP(&source, "source", "s", "", "chain-id of the source") - servesnapshotsCmd.Flags().StringVar(®istryUrl, "registry-url", utils.DefaultRegistryURL, "URL to fetch latest KYVE Source-Registry") + servesnapshotsCmd.Flags().StringVar(&flags.ChainRest, "chain-rest", "", "rest endpoint for KYVE chain") + servesnapshotsCmd.Flags().StringVar(&flags.StorageRest, "storage-rest", "", "storage endpoint for requesting bundle data") - servesnapshotsCmd.Flags().StringVar(&snapshotPoolId, "snapshot-pool-id", "", "pool-id of the state-sync pool") - servesnapshotsCmd.Flags().StringVar(&blockPoolId, "block-pool-id", "", "pool-id of the block-sync pool") + servesnapshotsCmd.Flags().StringVar(&flags.SnapshotPoolId, "snapshot-pool-id", "", "pool-id of the state-sync pool") + servesnapshotsCmd.Flags().StringVar(&flags.BlockPoolId, "block-pool-id", "", "pool-id of the block-sync pool") - servesnapshotsCmd.Flags().Int64Var(&snapshotPort, "snapshot-port", utils.DefaultSnapshotServerPort, "port for snapshot server") + servesnapshotsCmd.Flags().Int64Var(&flags.SnapshotPort, "snapshot-port", utils.DefaultSnapshotServerPort, "port for snapshot server") - servesnapshotsCmd.Flags().BoolVar(&rpcServer, "rpc-server", false, "rpc server serving /status, /block and /block_results") - servesnapshotsCmd.Flags().Int64Var(&rpcServerPort, "rpc-server-port", utils.DefaultRpcServerPort, "port for rpc server") + servesnapshotsCmd.Flags().BoolVar(&flags.RpcServer, "rpc-server", false, "rpc server serving /status, /block and /block_results") + servesnapshotsCmd.Flags().Int64Var(&flags.RpcServerPort, "rpc-server-port", utils.DefaultRpcServerPort, "port for rpc server") - servesnapshotsCmd.Flags().Int64Var(&startHeight, "start-height", 0, "start creating snapshots at this height. note that pruning should be false when using start height") - servesnapshotsCmd.Flags().Int64VarP(&targetHeight, "target-height", "t", 0, "the height at which KSYNC will exit once reached") + servesnapshotsCmd.Flags().Int64Var(&flags.StartHeight, "start-height", 0, "start creating snapshots at this height. note that pruning should be false when using start height") + servesnapshotsCmd.Flags().Int64VarP(&flags.TargetHeight, "target-height", "t", 0, "the height at which KSYNC will exit once reached") - servesnapshotsCmd.Flags().BoolVar(&pruning, "pruning", true, "prune application.db, state.db, blockstore db and snapshots") - servesnapshotsCmd.Flags().BoolVar(&keepSnapshots, "keep-snapshots", false, "keep snapshots, although pruning might be enabled") - servesnapshotsCmd.Flags().BoolVar(&skipWaiting, "skip-waiting", false, "do not wait if synced to far ahead of pool, pruning has to be disabled for this option") + servesnapshotsCmd.Flags().BoolVar(&flags.Pruning, "pruning", true, "prune application.db, state.db, blockstore db and snapshots") + servesnapshotsCmd.Flags().BoolVar(&flags.KeepSnapshots, "keep-snapshots", false, "keep snapshots, although pruning might be enabled") + servesnapshotsCmd.Flags().BoolVar(&flags.SkipWaiting, "skip-waiting", false, "do not wait if synced to far ahead of pool, pruning has to be disabled for this option") - servesnapshotsCmd.Flags().StringVarP(&appFlags, "app-flags", "f", "", "custom flags which are applied to the app binary start command. Example: --app-flags=\"--x-crisis-skip-assert-invariants,--iavl-disable-fastnode\"") + servesnapshotsCmd.Flags().StringVarP(&flags.AppFlags, "app-flags", "f", "", "custom flags which are applied to the app binary start command. Example: --app-flags=\"--x-crisis-skip-assert-invariants,--iavl-disable-fastnode\"") - servesnapshotsCmd.Flags().BoolVarP(&autoselectBinaryVersion, "autoselect-binary-version", "a", false, "if provided binary is cosmovisor KSYNC will automatically change the \"current\" symlink to the correct upgrade version") - servesnapshotsCmd.Flags().BoolVarP(&reset, "reset-all", "r", false, "reset this node's validator to genesis state") - servesnapshotsCmd.Flags().BoolVar(&optOut, "opt-out", false, "disable the collection of anonymous usage data") - servesnapshotsCmd.Flags().BoolVarP(&debug, "debug", "d", false, "show logs from tendermint app") + servesnapshotsCmd.Flags().BoolVarP(&flags.AutoSelectBinaryVersion, "auto-select-binary-version", "a", false, "if provided binary is cosmovisor KSYNC will automatically change the \"current\" symlink to the correct upgrade version") + servesnapshotsCmd.Flags().BoolVarP(&flags.Reset, "reset-all", "r", false, "reset this node's validator to genesis state") + servesnapshotsCmd.Flags().BoolVar(&flags.OptOut, "opt-out", false, "disable the collection of anonymous usage data") + servesnapshotsCmd.Flags().BoolVarP(&flags.Debug, "debug", "d", false, "run KSYNC in debug mode") + servesnapshotsCmd.Flags().BoolVarP(&flags.AppLogs, "app-logs", "l", false, "show logs from cosmos app") RootCmd.AddCommand(servesnapshotsCmd) } @@ -57,87 +50,7 @@ func init() { var servesnapshotsCmd = &cobra.Command{ Use: "serve-snapshots", Short: "Serve snapshots for running KYVE state-sync pools", - RunE: func(cmd *cobra.Command, args []string) error { - chainRest = utils.GetChainRest(chainId, chainRest) - storageRest = strings.TrimSuffix(storageRest, "/") - - // if no home path was given get the default one - if homePath == "" { - homePath = utils.GetHomePathFromBinary(binaryPath) - } - - defaultEngine := engines.EngineFactory(engine, homePath, rpcServerPort) - - if source == "" && blockPoolId == "" && snapshotPoolId == "" { - s, err := defaultEngine.GetChainId() - if err != nil { - return fmt.Errorf("failed to close dbs in engine: %w", err) - } - source = s - logger.Info().Msgf("Loaded source \"%s\" from genesis file", source) - } - - bId, sId, err := sources.GetPoolIds(chainId, source, blockPoolId, snapshotPoolId, registryUrl, true, true) - if err != nil { - return fmt.Errorf("failed to load pool-ids: %w", err) - } - - if reset { - if err := defaultEngine.ResetAll(true); err != nil { - return fmt.Errorf("could not reset tendermint application: %w", err) - } - } - - if err := defaultEngine.OpenDBs(); err != nil { - return fmt.Errorf("failed to open dbs in engine: %w", err) - } - - // perform validation checks before booting state-sync process - snapshotBundleId, snapshotHeight, err := servesnapshots.PerformServeSnapshotsValidationChecks(defaultEngine, chainRest, sId, bId, startHeight, targetHeight) - if err != nil { - return fmt.Errorf("serve-snapshots validation checks failed: %w", err) - } - - height := defaultEngine.GetHeight() - continuationHeight := snapshotHeight - if continuationHeight == 0 { - c, err := defaultEngine.GetContinuationHeight() - if err != nil { - return fmt.Errorf("failed to get continuation height: %w", err) - } - continuationHeight = c - } - - if err := blocksync.PerformBlockSyncValidationChecks(chainRest, nil, &bId, continuationHeight, targetHeight, true, false); err != nil { - return fmt.Errorf("block-sync validation checks failed: %w", err) - } - - utils.TrackServeSnapshotsEvent(defaultEngine, chainId, chainRest, storageRest, snapshotPort, rpcServer, rpcServerPort, startHeight, pruning, keepSnapshots, debug, optOut) - - if err := defaultEngine.CloseDBs(); err != nil { - return fmt.Errorf("failed to close dbs in engine: %w", err) - } - - if autoselectBinaryVersion { - if err := sources.SelectCosmovisorVersion(binaryPath, homePath, registryUrl, source, snapshotHeight); err != nil { - return fmt.Errorf("failed to autoselect binary version: %w", err) - } - } - - if err := sources.IsBinaryRecommendedVersion(binaryPath, registryUrl, source, continuationHeight, !y); err != nil { - return fmt.Errorf("failed to check if binary has the recommended version: %w", err) - } - - if engine == "" && binaryPath != "" { - engine = utils.GetEnginePathFromBinary(binaryPath) - logger.Info().Msgf("Loaded engine \"%s\" from binary path", engine) - } - - consensusEngine, err := engines.EngineSourceFactory(engine, homePath, registryUrl, source, rpcServerPort, continuationHeight) - if err != nil { - return fmt.Errorf("failed to create consensus engine for source: %w", err) - } - - return servesnapshots.StartServeSnapshotsWithBinary(consensusEngine, binaryPath, homePath, chainRest, storageRest, &bId, sId, targetHeight, height, snapshotBundleId, snapshotHeight, snapshotPort, appFlags, rpcServer, pruning, keepSnapshots, skipWaiting, debug) + RunE: func(_ *cobra.Command, _ []string) error { + return servesnapshots.Start() }, } diff --git a/cmd/ksync/commands/statesync.go b/cmd/ksync/commands/statesync.go index d226983..696449f 100644 --- a/cmd/ksync/commands/statesync.go +++ b/cmd/ksync/commands/statesync.go @@ -1,115 +1,46 @@ package commands import ( - "errors" "fmt" - "github.com/KYVENetwork/ksync/engines" - "github.com/KYVENetwork/ksync/sources" - "github.com/KYVENetwork/ksync/statesync" + "github.com/KYVENetwork/ksync/flags" + "github.com/KYVENetwork/ksync/sync/statesync" "github.com/KYVENetwork/ksync/utils" "github.com/spf13/cobra" - "strings" ) func init() { - stateSyncCmd.Flags().StringVarP(&engine, "engine", "e", "", fmt.Sprintf("consensus engine of the binary by default %s is used, list all engines with \"ksync engines\"", utils.DefaultEngine)) + stateSyncCmd.Flags().StringVarP(&flags.BinaryPath, "binary", "b", "", "binary path to the cosmos app") + if err := blockSyncCmd.MarkFlagRequired("binary"); err != nil { + panic(fmt.Errorf("flag 'binary' should be required: %w", err)) + } - stateSyncCmd.Flags().StringVarP(&binaryPath, "binary", "b", "", "binary path of node to be synced, if not provided the binary has to be started externally with --with-tendermint=false") + stateSyncCmd.Flags().StringVarP(&flags.HomePath, "home", "h", "", "home directory") - stateSyncCmd.Flags().StringVarP(&homePath, "home", "h", "", "home directory") + stateSyncCmd.Flags().StringVarP(&flags.ChainId, "chain-id", "c", utils.DefaultChainId, fmt.Sprintf("KYVE chain id [\"%s\",\"%s\",\"%s\"]", utils.ChainIdMainnet, utils.ChainIdKaon, utils.ChainIdKorellia)) - stateSyncCmd.Flags().StringVarP(&chainId, "chain-id", "c", utils.DefaultChainId, fmt.Sprintf("KYVE chain id [\"%s\",\"%s\",\"%s\"]", utils.ChainIdMainnet, utils.ChainIdKaon, utils.ChainIdKorellia)) + stateSyncCmd.Flags().StringVar(&flags.ChainRest, "chain-rest", "", "rest endpoint for KYVE chain") + stateSyncCmd.Flags().StringVar(&flags.StorageRest, "storage-rest", "", "storage endpoint for requesting bundle data") - stateSyncCmd.Flags().StringVar(&chainRest, "chain-rest", "", "rest endpoint for KYVE chain") - stateSyncCmd.Flags().StringVar(&storageRest, "storage-rest", "", "storage endpoint for requesting bundle data") + stateSyncCmd.Flags().StringVar(&flags.SnapshotPoolId, "snapshot-pool-id", "", "pool-id of the state-sync pool") - stateSyncCmd.Flags().StringVarP(&source, "source", "s", "", "chain-id of the source") - stateSyncCmd.Flags().StringVar(®istryUrl, "registry-url", utils.DefaultRegistryURL, "URL to fetch latest KYVE Source-Registry") + stateSyncCmd.Flags().StringVarP(&flags.AppFlags, "app-flags", "f", "", "custom flags which are applied to the app binary start command. Example: --app-flags=\"--x-crisis-skip-assert-invariants,--iavl-disable-fastnode\"") - stateSyncCmd.Flags().StringVar(&snapshotPoolId, "snapshot-pool-id", "", "pool-id of the state-sync pool") + stateSyncCmd.Flags().Int64VarP(&flags.TargetHeight, "target-height", "t", 0, "snapshot height, if not specified it will use the latest available snapshot height") - stateSyncCmd.Flags().StringVarP(&appFlags, "app-flags", "f", "", "custom flags which are applied to the app binary start command. Example: --app-flags=\"--x-crisis-skip-assert-invariants,--iavl-disable-fastnode\"") - - stateSyncCmd.Flags().Int64VarP(&targetHeight, "target-height", "t", 0, "snapshot height, if not specified it will use the latest available snapshot height") - - stateSyncCmd.Flags().BoolVarP(&autoselectBinaryVersion, "autoselect-binary-version", "a", false, "if provided binary is cosmovisor KSYNC will automatically change the \"current\" symlink to the correct upgrade version") - stateSyncCmd.Flags().BoolVarP(&reset, "reset-all", "r", false, "reset this node's validator to genesis state") - stateSyncCmd.Flags().BoolVar(&optOut, "opt-out", false, "disable the collection of anonymous usage data") - stateSyncCmd.Flags().BoolVarP(&debug, "debug", "d", false, "show logs from tendermint app") - stateSyncCmd.Flags().BoolVarP(&y, "yes", "y", false, "automatically answer yes for all questions") + stateSyncCmd.Flags().BoolVarP(&flags.AutoSelectBinaryVersion, "auto-select-binary-version", "a", false, "if provided binary is cosmovisor KSYNC will automatically change the \"current\" symlink to the correct upgrade version") + stateSyncCmd.Flags().BoolVarP(&flags.Reset, "reset-all", "r", false, "reset this node's validator to genesis state") + stateSyncCmd.Flags().BoolVar(&flags.OptOut, "opt-out", false, "disable the collection of anonymous usage data") + stateSyncCmd.Flags().BoolVarP(&flags.Debug, "debug", "d", false, "run KSYNC in debug mode") + stateSyncCmd.Flags().BoolVarP(&flags.AppLogs, "app-logs", "l", false, "show logs from cosmos app") + stateSyncCmd.Flags().BoolVarP(&flags.Y, "yes", "y", false, "automatically answer yes for all questions") RootCmd.AddCommand(stateSyncCmd) } var stateSyncCmd = &cobra.Command{ Use: "state-sync", - Short: "Apply a state-sync snapshot", - RunE: func(cmd *cobra.Command, args []string) error { - chainRest = utils.GetChainRest(chainId, chainRest) - storageRest = strings.TrimSuffix(storageRest, "/") - - // if no binary was provided at least the home path needs to be defined - if binaryPath == "" && homePath == "" { - return errors.New("flag 'home' is required") - } - - if binaryPath == "" { - logger.Info().Msg("To start the syncing process, start your chain binary with --with-tendermint=false") - } - - // if no home path was given get the default one - if homePath == "" { - homePath = utils.GetHomePathFromBinary(binaryPath) - } - - defaultEngine := engines.EngineFactory(engine, homePath, rpcServerPort) - - if source == "" && snapshotPoolId == "" { - s, err := defaultEngine.GetChainId() - if err != nil { - return fmt.Errorf("failed to load chain-id from engine: %w", err) - } - source = s - logger.Info().Msgf("Loaded source \"%s\" from genesis file", source) - } - - _, sId, err := sources.GetPoolIds(chainId, source, "", snapshotPoolId, registryUrl, false, true) - if err != nil { - return fmt.Errorf("failed to load pool-ids: %w", err) - } - - if reset { - if err := defaultEngine.ResetAll(true); err != nil { - return fmt.Errorf("could not reset tendermint application: %w", err) - } - } - - // perform validation checks before booting state-sync process - snapshotBundleId, snapshotHeight, err := statesync.PerformStateSyncValidationChecks(chainRest, sId, targetHeight, !y) - if err != nil { - return fmt.Errorf("state-sync validation checks failed: %w", err) - } - - if autoselectBinaryVersion { - if err := sources.SelectCosmovisorVersion(binaryPath, homePath, registryUrl, source, snapshotHeight); err != nil { - return fmt.Errorf("failed to autoselect binary version: %w", err) - } - } - - if err := sources.IsBinaryRecommendedVersion(binaryPath, registryUrl, source, snapshotHeight, !y); err != nil { - return fmt.Errorf("failed to check if binary has the recommended version: %w", err) - } - - if engine == "" && binaryPath != "" { - engine = utils.GetEnginePathFromBinary(binaryPath) - logger.Info().Msgf("Loaded engine \"%s\" from binary path", engine) - } - - consensusEngine, err := engines.EngineSourceFactory(engine, homePath, registryUrl, source, rpcServerPort, snapshotHeight) - if err != nil { - return fmt.Errorf("failed to create consensus engine for source: %w", err) - } - - return statesync.StartStateSyncWithBinary(consensusEngine, binaryPath, chainId, chainRest, storageRest, sId, targetHeight, snapshotBundleId, snapshotHeight, appFlags, optOut, debug) + Short: "Apply state-sync snapshots", + RunE: func(_ *cobra.Command, _ []string) error { + return statesync.Start() }, } diff --git a/cmd/ksync/commands/version.go b/cmd/ksync/commands/version.go index 859f1af..4db5e20 100644 --- a/cmd/ksync/commands/version.go +++ b/cmd/ksync/commands/version.go @@ -2,12 +2,14 @@ package commands import ( "fmt" + "github.com/KYVENetwork/ksync/flags" "github.com/KYVENetwork/ksync/utils" "github.com/spf13/cobra" ) func init() { - versionCmd.Flags().BoolVar(&optOut, "opt-out", false, "disable the collection of anonymous usage data") + versionCmd.Flags().BoolVar(&flags.OptOut, "opt-out", false, "disable the collection of anonymous usage data") + versionCmd.Flags().BoolVarP(&flags.Debug, "debug", "d", false, "run KSYNC in debug mode") RootCmd.AddCommand(versionCmd) } @@ -16,7 +18,6 @@ var versionCmd = &cobra.Command{ Use: "version", Short: "Print the version of KSYNC", RunE: func(cmd *cobra.Command, args []string) error { - utils.TrackVersionEvent(optOut) fmt.Println(utils.GetVersion()) return nil }, diff --git a/collectors/blocks/blocks.go b/collectors/blocks/blocks.go deleted file mode 100644 index 5b92d36..0000000 --- a/collectors/blocks/blocks.go +++ /dev/null @@ -1,219 +0,0 @@ -package blocks - -import ( - "encoding/json" - "fmt" - "github.com/KYVENetwork/ksync/collectors/bundles" - "github.com/KYVENetwork/ksync/types" - "github.com/KYVENetwork/ksync/utils" - tmjson "github.com/tendermint/tendermint/libs/json" - "strconv" - "time" -) - -var ( - logger = utils.KsyncLogger("collector") -) - -// getPaginationKeyForBlockHeight gets the pagination key right for the bundle so the StartBlockCollector can -// directly start at the correct bundle. Therefore, it does not need to search through all the bundles until -// it finds the correct one -func getPaginationKeyForBlockHeight(chainRest string, blockPool types.PoolResponse, height int64) (string, error) { - finalizedBundle, err := bundles.GetFinalizedBundleForBlockHeight(chainRest, blockPool, height) - if err != nil { - return "", fmt.Errorf("failed to get finalized bundle for block height %d: %w", height, err) - } - - bundleId, err := strconv.ParseInt(finalizedBundle.Id, 10, 64) - if err != nil { - return "", fmt.Errorf("failed to parse bundle id %s: %w", finalizedBundle.Id, err) - } - - // if bundleId is zero we start from the beginning, meaning the paginationKey should be empty - if bundleId == 0 { - return "", nil - } - - _, paginationKey, err := bundles.GetFinalizedBundlesPageWithOffset(chainRest, blockPool.Pool.Id, 1, bundleId-1, "", false) - if err != nil { - return "", fmt.Errorf("failed to get finalized bundles: %w", err) - } - - return paginationKey, nil -} - -func StartBlockCollector(itemCh chan<- types.DataItem, errorCh chan<- error, chainRest string, storageRest string, blockRpcConfig *types.BlockRpcConfig, blockPool *types.PoolResponse, continuationHeight, targetHeight int64, mustExit bool) { - if blockRpcConfig == nil { - startBlockCollectorFromBundles(itemCh, errorCh, chainRest, storageRest, *blockPool, continuationHeight, targetHeight, mustExit) - } else { - startBlockCollectorFromRpc(itemCh, errorCh, *blockRpcConfig, continuationHeight, targetHeight, mustExit) - } -} - -func startBlockCollectorFromBundles(itemCh chan<- types.DataItem, errorCh chan<- error, chainRest, storageRest string, blockPool types.PoolResponse, continuationHeight, targetHeight int64, mustExit bool) { - paginationKey, err := getPaginationKeyForBlockHeight(chainRest, blockPool, continuationHeight) - if err != nil { - errorCh <- fmt.Errorf("failed to get pagination key for continuation height %d: %w", continuationHeight, err) - return - } - -BundleCollector: - for { - bundlesPage, nextKey, err := bundles.GetFinalizedBundlesPage(chainRest, blockPool.Pool.Id, utils.BundlesPageLimit, paginationKey, false) - if err != nil { - errorCh <- fmt.Errorf("failed to get finalized bundles page: %w", err) - return - } - - for _, finalizedBundle := range bundlesPage { - height, err := strconv.ParseInt(finalizedBundle.ToKey, 10, 64) - if err != nil { - errorCh <- fmt.Errorf("failed to parse bundle to key to int64: %w", err) - return - } - - if height < continuationHeight { - continue - } else { - logger.Info().Msg(fmt.Sprintf("downloading bundle with storage id %s", finalizedBundle.StorageId)) - } - - deflated, err := bundles.GetDataFromFinalizedBundle(finalizedBundle, storageRest) - if err != nil { - errorCh <- fmt.Errorf("failed to get data from finalized bundle: %w", err) - return - } - - // parse bundle - var bundle types.Bundle - - if err := json.Unmarshal(deflated, &bundle); err != nil { - errorCh <- fmt.Errorf("failed to unmarshal tendermint bundle: %w", err) - return - } - - for _, dataItem := range bundle { - itemHeight, err := utils.ParseBlockHeightFromKey(dataItem.Key) - if err != nil { - errorCh <- fmt.Errorf("failed parse block height from key %s: %w", dataItem.Key, err) - return - } - - // skip blocks until we reach start height - if itemHeight < continuationHeight { - continue - } - - // send raw data item executor - itemCh <- dataItem - - // keep track of latest retrieved height - continuationHeight = itemHeight + 1 - - // exit if mustExit is true and target height is reached - if mustExit && targetHeight > 0 && itemHeight >= targetHeight+1 { - break BundleCollector - } - } - } - - if nextKey == "" { - if mustExit { - // if there is no new page we do not continue - logger.Info().Msg("reached latest block on pool. Stopping block collector") - break - } else { - // if we are at the end of the page we continue and wait for - // new finalized bundles - time.Sleep(30 * time.Second) - continue - } - } - - time.Sleep(utils.RequestTimeoutMS) - paginationKey = nextKey - } -} - -// startBlockCollectorFromRpc starts the block collector from the block rpc (must be an archive node which has all blocks) -func startBlockCollectorFromRpc(itemCh chan<- types.DataItem, errorCh chan<- error, blockRpcConfig types.BlockRpcConfig, continuationHeight, targetHeight int64, mustExit bool) { - // make a for loop starting with the continuation height - // - get the block from the block rpc - // - send the block to the item channel - // - if mustExit is true and target height is reached, break the loop - // - increment the continuation height - for { - dataItem, err := retrieveBlockFromRpc(blockRpcConfig, continuationHeight) - if err != nil { - errorCh <- fmt.Errorf("failed to get block from rpc: %w", err) - return - } - - itemCh <- *dataItem - - if mustExit && targetHeight > 0 && continuationHeight >= targetHeight+1 { - break - } - - continuationHeight++ - - time.Sleep(blockRpcConfig.RequestTimeout) - } -} - -func retrieveBlockFromBundle(chainRest, storageRest string, blockPool types.PoolResponse, height int64) (*types.DataItem, error) { - finalizedBundle, err := bundles.GetFinalizedBundleForBlockHeight(chainRest, blockPool, height) - if err != nil { - return nil, fmt.Errorf("failed to get finalized bundle for block height %d: %w", height, err) - } - - deflated, err := bundles.GetDataFromFinalizedBundle(*finalizedBundle, storageRest) - if err != nil { - return nil, fmt.Errorf("failed to get data from finalized bundle: %w", err) - } - - // parse bundle - var bundle types.Bundle - - if err := tmjson.Unmarshal(deflated, &bundle); err != nil { - return nil, fmt.Errorf("failed to unmarshal tendermint bundle: %w", err) - } - - for _, dataItem := range bundle { - itemHeight, err := utils.ParseBlockHeightFromKey(dataItem.Key) - if err != nil { - return nil, fmt.Errorf("failed parse block height from key %s: %w", dataItem.Key, err) - } - - // skip blocks until we reach start height - if itemHeight < height { - continue - } - - return &dataItem, nil - } - - return nil, fmt.Errorf("failed to find bundle with block height %d", height) -} - -func retrieveBlockFromRpc(blockRpcConfig types.BlockRpcConfig, height int64) (*types.DataItem, error) { - logger.Info().Msg(fmt.Sprintf("downloading block with height %d", height)) - result, err := utils.GetFromUrlWithOptions(fmt.Sprintf("%s/block?height=%d", blockRpcConfig.Endpoint, height), - utils.GetFromUrlOptions{SkipTLSVerification: true, WithBackoff: true}, - ) - if err != nil { - return nil, err - } - - return &types.DataItem{ - Key: strconv.FormatInt(height, 10), - Value: result, - }, nil -} - -func RetrieveBlock(chainRest, storageRest string, blockRpcConfig *types.BlockRpcConfig, blockPool *types.PoolResponse, height int64) (*types.DataItem, error) { - if blockRpcConfig == nil { - return retrieveBlockFromBundle(chainRest, storageRest, *blockPool, height) - } - return retrieveBlockFromRpc(*blockRpcConfig, height) -} diff --git a/collectors/pool/pool.go b/collectors/pool/pool.go deleted file mode 100644 index 8edfb4a..0000000 --- a/collectors/pool/pool.go +++ /dev/null @@ -1,23 +0,0 @@ -package pool - -import ( - "fmt" - "github.com/KYVENetwork/ksync/types" - "github.com/KYVENetwork/ksync/utils" - "github.com/tendermint/tendermint/libs/json" -) - -func GetPoolInfo(restEndpoint string, poolId int64) (*types.PoolResponse, error) { - data, err := utils.GetFromUrlWithBackoff(fmt.Sprintf("%s/kyve/query/v1beta1/pool/%d", restEndpoint, poolId)) - if err != nil { - return nil, fmt.Errorf("failed to query pool %d", poolId) - } - - var poolResponse types.PoolResponse - - if err = json.Unmarshal(data, &poolResponse); err != nil { - return nil, fmt.Errorf("failed to unmarshal pool response: %w", err) - } - - return &poolResponse, nil -} diff --git a/collectors/snapshots/snapshots.go b/collectors/snapshots/snapshots.go deleted file mode 100644 index 5868bc8..0000000 --- a/collectors/snapshots/snapshots.go +++ /dev/null @@ -1,66 +0,0 @@ -package snapshots - -import ( - "fmt" - "github.com/KYVENetwork/ksync/collectors/bundles" - "github.com/KYVENetwork/ksync/utils" - "strconv" - "time" -) - -// FindNearestSnapshotBundleIdByHeight takes a targetHeight and returns the bundle id with the according snapshot -// height of the available snapshot. If no complete snapshot is available at the targetHeight this method returns -// the bundleId and snapshotHeight of the nearest snapshot below the targetHeight. -func FindNearestSnapshotBundleIdByHeight(restEndpoint string, poolId int64, targetHeight int64) (snapshotBundleId int64, snapshotHeight int64, err error) { - paginationKey := "" - - for { - // we iterate in reverse through the pages since mostly live snapshots at the end of the bundles range are used - bundlesPage, nextKey, pageErr := bundles.GetFinalizedBundlesPage(restEndpoint, poolId, utils.BundlesPageLimit, paginationKey, true) - if pageErr != nil { - return snapshotBundleId, snapshotHeight, fmt.Errorf("failed to retrieve finalized bundles: %w", pageErr) - } - - bundle := bundlesPage[len(bundlesPage)-1] - height, chunkIndex, keyErr := utils.ParseSnapshotFromKey(bundle.ToKey) - if keyErr != nil { - return snapshotBundleId, snapshotHeight, fmt.Errorf("failed to parse snapshot from to_key %s: %w", bundle.ToKey, keyErr) - } - - // if we find that the last bundle in the page is still greater than the target height - // we skip iterating though it and directly continue searching on the next bundles page - if height <= targetHeight { - for _, bundle = range bundlesPage { - height, chunkIndex, keyErr = utils.ParseSnapshotFromKey(bundle.ToKey) - if keyErr != nil { - return snapshotBundleId, snapshotHeight, fmt.Errorf("failed to parse snapshot from to_key %s: %w", bundle.ToKey, keyErr) - } - - if height <= targetHeight && chunkIndex == 0 { - snapshotBundleId, err = strconv.ParseInt(bundle.Id, 10, 64) - if err != nil { - return - } - - snapshotHeight = height - return - } - } - } - - // if there is no new page we do not continue - if nextKey == "" { - break - } - - time.Sleep(utils.RequestTimeoutMS) - paginationKey = nextKey - } - - // if snapshot height is zero it means that we have not found any complete snapshot for the target height - if snapshotHeight == 0 { - err = fmt.Errorf("could not find nearest bundle for target height %d", targetHeight) - } - - return -} diff --git a/engines/celestia-core-v34/celestiacore.go b/engines/celestia-core-v34/celestiacore.go index c25978e..fe3044a 100644 --- a/engines/celestia-core-v34/celestiacore.go +++ b/engines/celestia-core-v34/celestiacore.go @@ -2,7 +2,6 @@ package celestia_core_v34 import ( "fmt" - abciClient "github.com/KYVENetwork/celestia-core/abci/client" abciTypes "github.com/KYVENetwork/celestia-core/abci/types" cfg "github.com/KYVENetwork/celestia-core/config" cs "github.com/KYVENetwork/celestia-core/consensus" @@ -32,15 +31,10 @@ import ( "time" ) -var ( - tmLogger = TmLogger() -) - type Engine struct { - HomePath string - RpcServerPort int64 - areDBsOpen bool - config *cfg.Config + homePath string + areDBsOpen bool + config *cfg.Config blockDB db.DB blockStore *tmStore.BlockStore @@ -48,17 +42,35 @@ type Engine struct { stateDB db.DB stateStore tmState.Store + evidenceDB db.DB + genDoc *GenesisDoc privValidatorKey crypto.PubKey + nodeKey *tmP2P.NodeKey state tmState.State - prevBlock *Block proxyApp proxy.AppConns mempool *mempool.Mempool evidencePool *evidence.Pool blockExecutor *tmState.BlockExecutor } +func NewEngine(homePath string) (*Engine, error) { + engine := &Engine{ + homePath: homePath, + } + + if err := engine.LoadConfig(); err != nil { + return nil, err + } + + if err := engine.OpenDBs(); err != nil { + return nil, err + } + + return engine, nil +} + func (engine *Engine) GetName() string { return utils.EngineCelestiaCoreV34 } @@ -68,32 +80,18 @@ func (engine *Engine) LoadConfig() error { return nil } - config, err := LoadConfig(engine.HomePath) + config, err := LoadConfig(engine.homePath) if err != nil { return fmt.Errorf("failed to load config.toml: %w", err) } engine.config = config - return nil -} - -func (engine *Engine) OpenDBs() error { - if engine.areDBsOpen { - return nil - } - - if err := engine.LoadConfig(); err != nil { - return err - } - - if err := utils.FormatGenesisFile(engine.config.GenesisFile()); err != nil { - return fmt.Errorf("failed to format genesis file: %w", err) - } genDoc, err := nm.DefaultGenesisDocProviderFunc(engine.config)() if err != nil { return fmt.Errorf("failed to load state and genDoc: %w", err) } + engine.genDoc = genDoc privValidatorKey, err := privval.LoadFilePVEmptyState( @@ -105,6 +103,21 @@ func (engine *Engine) OpenDBs() error { } engine.privValidatorKey = privValidatorKey + nodeKey, err := tmP2P.LoadNodeKey(engine.config.NodeKeyFile()) + if err != nil { + return fmt.Errorf("loading node key file failed: %w", err) + } + engine.nodeKey = nodeKey + + engineLogger.Debug("loaded config", "configPath", fmt.Sprintf("%s/config.toml", engine.homePath)) + return nil +} + +func (engine *Engine) OpenDBs() error { + if engine.areDBsOpen { + return nil + } + blockDB, blockStore, err := GetBlockstoreDBs(engine.config) if err != nil { return fmt.Errorf("failed to open blockDB: %w", err) @@ -121,7 +134,23 @@ func (engine *Engine) OpenDBs() error { engine.stateDB = stateDB engine.stateStore = stateStore + evidenceDB, err := DefaultDBProvider(&DBContext{ID: "evidence", Config: engine.config}) + if err != nil { + return fmt.Errorf("failed to open evidenceDB: %w", err) + } + + engine.evidenceDB = evidenceDB + engine.areDBsOpen = true + engineLogger.Debug( + "opened dbs", + "blockDB", + fmt.Sprintf("%s/%s/blockstore.db", engine.homePath, engine.config.DBPath), + "stateDB", + fmt.Sprintf("%s/%s/state.db", engine.homePath, engine.config.DBPath), + "evidenceDB", + fmt.Sprintf("%s/%s/evidence.db", engine.homePath, engine.config.DBPath), + ) return nil } @@ -138,12 +167,25 @@ func (engine *Engine) CloseDBs() error { return fmt.Errorf("failed to close stateDB: %w", err) } + if err := engine.evidenceDB.Close(); err != nil { + return fmt.Errorf("failed to close evidenceDB: %w", err) + } + engine.areDBsOpen = false + engineLogger.Debug( + "closed dbs", + "blockDB", + fmt.Sprintf("%s/%s/blockstore.db", engine.homePath, engine.config.DBPath), + "stateDB", + fmt.Sprintf("%s/%s/state.db", engine.homePath, engine.config.DBPath), + "evidenceDB", + fmt.Sprintf("%s/%s/evidence.db", engine.homePath, engine.config.DBPath), + ) return nil } -func (engine *Engine) GetHomePath() string { - return engine.HomePath +func (engine *Engine) GetRpcListenAddress() string { + return engine.config.RPC.ListenAddress } func (engine *Engine) GetProxyAppAddress() string { @@ -155,12 +197,12 @@ func (engine *Engine) StartProxyApp() error { return fmt.Errorf("proxy app already started") } - proxyApp, err := CreateAndStartProxyAppConns(engine.config) - if err != nil { - return err + engine.proxyApp = proxy.NewAppConns(proxy.NewRemoteClientCreator(engine.config.ProxyApp, engine.config.ABCI, false)) + if err := engine.proxyApp.Start(); err != nil { + return fmt.Errorf("failed to start proxy app: %w", err) } - engine.proxyApp = proxyApp + engineLogger.Debug("started proxy app connections", "address", engine.GetProxyAppAddress()) return nil } @@ -174,39 +216,10 @@ func (engine *Engine) StopProxyApp() error { } engine.proxyApp = nil + engineLogger.Debug("stopped proxy app connections", "address", engine.GetProxyAppAddress()) return nil } -func (engine *Engine) GetChainId() (string, error) { - if err := engine.LoadConfig(); err != nil { - return "", fmt.Errorf("failed to load config: %w", err) - } - - genDoc, err := nm.DefaultGenesisDocProviderFunc(engine.config)() - if err != nil { - return "", fmt.Errorf("failed to load genDoc: %w", err) - } - - return genDoc.ChainID, nil -} - -func (engine *Engine) GetContinuationHeight() (int64, error) { - height := engine.blockStore.Height() - - initialHeight, err := utils.GetInitialHeightFromGenesisFile(engine.GetGenesisPath()) - if err != nil { - return 0, fmt.Errorf("failed to load initial height from genesis file: %w", err) - } - - continuationHeight := height + 1 - - if continuationHeight < initialHeight { - continuationHeight = initialHeight - } - - return continuationHeight, nil -} - func (engine *Engine) DoHandshake() error { state, err := tmState.NewStore(engine.stateDB, tmState.StoreOptions{ DiscardABCIResponses: false, @@ -215,13 +228,17 @@ func (engine *Engine) DoHandshake() error { return fmt.Errorf("failed to load state from genDoc: %w", err) } - eventBus, err := CreateAndStartEventBus() - if err != nil { + eventBus := tmTypes.NewEventBus() + eventBus.SetLogger(engineLogger.With("module", "events")) + if err := eventBus.Start(); err != nil { return fmt.Errorf("failed to start event bus: %w", err) } - if err := DoHandshake(engine.stateStore, state, engine.blockStore, engine.genDoc, eventBus, engine.proxyApp); err != nil { - return fmt.Errorf("failed to do handshake: %w", err) + handshaker := cs.NewHandshaker(engine.stateStore, state, engine.blockStore, engine.genDoc) + handshaker.SetLogger(engineLogger.With("module", "consensus")) + handshaker.SetEventBus(eventBus) + if _, err := handshaker.Handshake(engine.proxyApp); err != nil { + return fmt.Errorf("error during handshake: %v", err) } state, err = engine.stateStore.Load() @@ -231,119 +248,77 @@ func (engine *Engine) DoHandshake() error { engine.state = state - mempool := CreateMempoolAndMempoolReactor(engine.config, engine.proxyApp, state) + mp := CreateMempoolAndMempoolReactor(engine.config, engine.proxyApp, state) - _, evidencePool, err := CreateEvidenceReactor(engine.config, engine.stateStore, engine.blockStore) + evidencePool, err := evidence.NewPool(engine.evidenceDB, engine.stateStore, engine.blockStore) if err != nil { - return fmt.Errorf("failed to create evidence reactor: %w", err) + return fmt.Errorf("failed to create evidence pool: %w", err) } - engine.mempool = &mempool + engine.mempool = &mp engine.evidencePool = evidencePool engine.blockExecutor = tmState.NewBlockExecutor( engine.stateStore, - tmLogger.With("module", "state"), + engineLogger.With("module", "state"), engine.proxyApp.Consensus(), - mempool, + mp, evidencePool, ) return nil } -func (engine *Engine) ApplyBlock(runtime *string, value []byte) error { - var block *Block - - if runtime == nil { - // if runtime is nil we sync from another celestia-core node - var blockResponse BlockResponse - err := json.Unmarshal(value, &blockResponse) - if err != nil { - return fmt.Errorf("failed to unmarshal block response: %w", err) - } - block = &blockResponse.Result.Block - } else if *runtime == utils.KSyncRuntimeTendermint { - var parsed TendermintValue - - if err := json.Unmarshal(value, &parsed); err != nil { - return fmt.Errorf("failed to unmarshal value: %w", err) - } +func (engine *Engine) ApplyBlock(rawBlock, nextRawBlock []byte) error { + var block, nextBlock *Block - block = parsed.Block.Block - } else if *runtime == utils.KSyncRuntimeTendermintBsync { - if err := json.Unmarshal(value, &block); err != nil { - return fmt.Errorf("failed to unmarshal value: %w", err) - } - } else { - return fmt.Errorf("runtime %s unknown", runtime) + if err := json.Unmarshal(rawBlock, &block); err != nil { + return fmt.Errorf("failed to unmarshal block: %w", err) } - // if the previous block is not defined we continue - if engine.prevBlock == nil { - engine.prevBlock = block - return nil + if err := json.Unmarshal(nextRawBlock, &nextBlock); err != nil { + return fmt.Errorf("failed to unmarshal next block: %w", err) } // get block data - blockParts := engine.prevBlock.MakePartSet(tmTypes.BlockPartSizeBytes) - blockId := block.LastBlockID + blockParts := block.MakePartSet(tmTypes.BlockPartSizeBytes) + blockId := nextBlock.LastBlockID // verify block - if err := engine.blockExecutor.ValidateBlock(engine.state, engine.prevBlock); err != nil { - return fmt.Errorf("block validation failed at height %d: %w", engine.prevBlock.Height, err) + if err := engine.blockExecutor.ValidateBlock(engine.state, block); err != nil { + return fmt.Errorf("block validation failed at height %d: %w", block.Height, err) } // verify commits - if err := engine.state.Validators.VerifyCommitLight(engine.state.ChainID, blockId, engine.prevBlock.Height, block.LastCommit); err != nil { - return fmt.Errorf("light commit verification failed at height %d: %w", engine.prevBlock.Height, err) + if err := engine.state.Validators.VerifyCommitLight(engine.state.ChainID, blockId, block.Height, nextBlock.LastCommit); err != nil { + return fmt.Errorf("light commit verification failed at height %d: %w", block.Height, err) } // execute block against app - state, _, err := engine.blockExecutor.ApplyBlock(engine.state, blockId, engine.prevBlock, block.LastCommit) + state, _, err := engine.blockExecutor.ApplyBlock(engine.state, blockId, block, nextBlock.LastCommit) if err != nil { - return fmt.Errorf("failed to apply block at height %d: %w", engine.prevBlock.Height, err) + return fmt.Errorf("failed to apply block at height %d: %w", block.Height, err) } - // TODO: why does the returned state of ApplyBlock contain zero as app version? // set app version in state to the app version found on the block - state.Version.Consensus.App = engine.prevBlock.Version.App + state.Version.Consensus.App = block.Version.App // store block - engine.blockStore.SaveBlock(engine.prevBlock, blockParts, block.LastCommit) + engine.blockStore.SaveBlock(block, blockParts, nextBlock.LastCommit) - // update values for next round + // update state for next round engine.state = state - engine.prevBlock = block - return nil } -func (engine *Engine) ApplyFirstBlockOverP2P(runtime string, value, nextValue []byte) error { +func (engine *Engine) ApplyFirstBlockOverP2P(rawBlock, nextRawBlock []byte) error { var block, nextBlock *Block - if runtime == utils.KSyncRuntimeTendermint { - var parsed, nextParsed TendermintValue - - if err := json.Unmarshal(value, &parsed); err != nil { - return fmt.Errorf("failed to unmarshal value: %w", err) - } - - if err := json.Unmarshal(nextValue, &nextParsed); err != nil { - return fmt.Errorf("failed to unmarshal next value: %w", err) - } - - block = parsed.Block.Block - nextBlock = nextParsed.Block.Block - } else if runtime == utils.KSyncRuntimeTendermintBsync { - if err := json.Unmarshal(value, &block); err != nil { - return fmt.Errorf("failed to unmarshal value: %w", err) - } + if err := json.Unmarshal(rawBlock, &block); err != nil { + return fmt.Errorf("failed to unmarshal block: %w", err) + } - if err := json.Unmarshal(nextValue, &nextBlock); err != nil { - return fmt.Errorf("failed to unmarshal next value: %w", err) - } - } else { - return fmt.Errorf("runtime %s unknown", runtime) + if err := json.Unmarshal(nextRawBlock, &nextBlock); err != nil { + return fmt.Errorf("failed to unmarshal next block: %w", err) } genDoc, err := nm.DefaultGenesisDocProviderFunc(engine.config)() @@ -378,7 +353,7 @@ func (engine *Engine) ApplyFirstBlockOverP2P(runtime string, value, nextValue [] nodeInfo, err := MakeNodeInfo(engine.config, ksyncNodeKey, genDoc) transport := tmP2P.NewMultiplexTransport(nodeInfo, *ksyncNodeKey, tmP2P.MConnConfig(engine.config.P2P), trace.NoOpTracer()) bcR := NewBlockchainReactor(block, nextBlock) - sw := CreateSwitch(engine.config, transport, bcR, nodeInfo, ksyncNodeKey, tmLogger) + sw := CreateSwitch(engine.config, transport, bcR, nodeInfo, ksyncNodeKey, engineLogger) // start the transport addr, err := tmP2P.NewNetAddressString(tmP2P.IDAddressString(ksyncNodeKey.ID(), engine.config.P2P.ListenAddress)) @@ -415,20 +390,6 @@ func (engine *Engine) ApplyFirstBlockOverP2P(runtime string, value, nextValue [] return nil } -func (engine *Engine) GetGenesisPath() string { - return engine.config.GenesisFile() -} - -func (engine *Engine) GetGenesisHeight() (int64, error) { - defaultDocProvider := nm.DefaultGenesisDocProviderFunc(engine.config) - genDoc, err := defaultDocProvider() - if err != nil { - return 0, err - } - - return genDoc.InitialHeight, nil -} - func (engine *Engine) GetHeight() int64 { return engine.blockStore.Height() } @@ -438,40 +399,20 @@ func (engine *Engine) GetBaseHeight() int64 { } func (engine *Engine) GetAppHeight() (int64, error) { - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) - - if err := socketClient.Start(); err != nil { - return 0, fmt.Errorf("failed to start socket client: %w", err) - } - - info, err := socketClient.InfoSync(abciTypes.RequestInfo{}) + info, err := engine.proxyApp.Query().InfoSync(abciTypes.RequestInfo{}) if err != nil { return 0, fmt.Errorf("failed to query info: %w", err) } - if err := socketClient.Stop(); err != nil { - return 0, fmt.Errorf("failed to stop socket client: %w", err) - } - return info.LastBlockHeight, nil } func (engine *Engine) GetSnapshots() ([]byte, error) { - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) - - if err := socketClient.Start(); err != nil { - return nil, fmt.Errorf("failed to start socket client: %w", err) - } - - res, err := socketClient.ListSnapshotsSync(abciTypes.RequestListSnapshots{}) + res, err := engine.proxyApp.Snapshot().ListSnapshotsSync(abciTypes.RequestListSnapshots{}) if err != nil { return nil, fmt.Errorf("failed to list snapshots: %w", err) } - if err := socketClient.Stop(); err != nil { - return nil, fmt.Errorf("failed to stop socket client: %w", err) - } - if len(res.Snapshots) == 0 { return json.Marshal([]Snapshot{}) } @@ -480,21 +421,11 @@ func (engine *Engine) GetSnapshots() ([]byte, error) { } func (engine *Engine) IsSnapshotAvailable(height int64) (bool, error) { - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) - - if err := socketClient.Start(); err != nil { - return false, fmt.Errorf("failed to start socket client: %w", err) - } - - res, err := socketClient.ListSnapshotsSync(abciTypes.RequestListSnapshots{}) + res, err := engine.proxyApp.Snapshot().ListSnapshotsSync(abciTypes.RequestListSnapshots{}) if err != nil { return false, fmt.Errorf("failed to list snapshots: %w", err) } - if err := socketClient.Stop(); err != nil { - return false, fmt.Errorf("failed to stop socket client: %w", err) - } - for _, snapshot := range res.Snapshots { if snapshot.Height == uint64(height) { return true, nil @@ -505,13 +436,7 @@ func (engine *Engine) IsSnapshotAvailable(height int64) (bool, error) { } func (engine *Engine) GetSnapshotChunk(height, format, chunk int64) ([]byte, error) { - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) - - if err := socketClient.Start(); err != nil { - return nil, fmt.Errorf("failed to start socket client: %w", err) - } - - res, err := socketClient.LoadSnapshotChunkSync(abciTypes.RequestLoadSnapshotChunk{ + res, err := engine.proxyApp.Snapshot().LoadSnapshotChunkSync(abciTypes.RequestLoadSnapshotChunk{ Height: uint64(height), Format: uint32(format), Chunk: uint32(chunk), @@ -520,10 +445,6 @@ func (engine *Engine) GetSnapshotChunk(height, format, chunk int64) ([]byte, err return nil, fmt.Errorf("failed to load snapshot chunk: %w", err) } - if err := socketClient.Stop(); err != nil { - return nil, fmt.Errorf("failed to stop socket client: %w", err) - } - return json.Marshal(res.Chunk) } @@ -532,13 +453,13 @@ func (engine *Engine) GetBlock(height int64) ([]byte, error) { return json.Marshal(block) } -func (engine *Engine) StartRPCServer() { +func (engine *Engine) StartRPCServer(port int64) { // wait until all reactors have been booted for engine.blockExecutor == nil { time.Sleep(1000) } - rpcLogger := tmLogger.With("module", "rpc-server") + rpcLogger := engineLogger.With("module", "rpc-server") consensusReactor := cs.NewReactor(cs.NewState( engine.config.Consensus, @@ -551,12 +472,12 @@ func (engine *Engine) StartRPCServer() { nodeKey, err := tmP2P.LoadNodeKey(engine.config.NodeKeyFile()) if err != nil { - tmLogger.Error(fmt.Sprintf("failed to get nodeKey: %s", err)) + engineLogger.Error(fmt.Sprintf("failed to get nodeKey: %s", err)) return } nodeInfo, err := MakeNodeInfo(engine.config, nodeKey, engine.genDoc) if err != nil { - tmLogger.Error(fmt.Sprintf("failed to get nodeInfo: %s", err)) + engineLogger.Error(fmt.Sprintf("failed to get nodeInfo: %s", err)) return } @@ -590,14 +511,14 @@ func (engine *Engine) StartRPCServer() { config := rpcserver.DefaultConfig() rpcserver.RegisterRPCFuncs(mux, routes, rpcLogger) - listener, err := rpcserver.Listen(fmt.Sprintf("tcp://127.0.0.1:%d", engine.RpcServerPort), config) + listener, err := rpcserver.Listen(fmt.Sprintf("tcp://127.0.0.1:%d", port), config) if err != nil { - tmLogger.Error(fmt.Sprintf("failed to get rpc listener: %s", err)) + engineLogger.Error(fmt.Sprintf("failed to get rpc listener: %s", err)) return } if err := rpcserver.Serve(listener, mux, rpcLogger, config); err != nil { - tmLogger.Error(fmt.Sprintf("failed to start rpc server: %s", err)) + engineLogger.Error(fmt.Sprintf("failed to start rpc server: %s", err)) return } } @@ -659,89 +580,82 @@ func (engine *Engine) GetSeenCommit(height int64) ([]byte, error) { return json.Marshal(block.LastCommit) } -func (engine *Engine) OfferSnapshot(value []byte) (string, uint32, error) { - var bundle TendermintSsyncBundle +func (engine *Engine) OfferSnapshot(rawSnapshot, rawState []byte) error { + var snapshot *abciTypes.Snapshot - if err := json.Unmarshal(value, &bundle); err != nil { - return abciTypes.ResponseOfferSnapshot_UNKNOWN.String(), 0, fmt.Errorf("failed to unmarshal tendermint-ssync bundle: %w", err) + if err := json.Unmarshal(rawSnapshot, &snapshot); err != nil { + return fmt.Errorf("failed to unmarshal snapshot: %w", err) } - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) + var state *tmState.State - if err := socketClient.Start(); err != nil { - return abciTypes.ResponseOfferSnapshot_UNKNOWN.String(), 0, fmt.Errorf("failed to start socket client: %w", err) + if err := json.Unmarshal(rawState, &state); err != nil { + return fmt.Errorf("failed to unmarshal state: %w", err) } - res, err := socketClient.OfferSnapshotSync(abciTypes.RequestOfferSnapshot{ - Snapshot: bundle[0].Value.Snapshot, - AppHash: bundle[0].Value.State.AppHash, + res, err := engine.proxyApp.Snapshot().OfferSnapshotSync(abciTypes.RequestOfferSnapshot{ + Snapshot: snapshot, + AppHash: state.AppHash, }) - if err != nil { - return abciTypes.ResponseOfferSnapshot_UNKNOWN.String(), 0, err + return err } - if err := socketClient.Stop(); err != nil { - return abciTypes.ResponseOfferSnapshot_UNKNOWN.String(), 0, fmt.Errorf("failed to stop socket client: %w", err) + if res.Result.String() != abciTypes.ResponseOfferSnapshot_ACCEPT.String() { + return fmt.Errorf(res.Result.String()) } - return res.Result.String(), bundle[0].Value.Snapshot.Chunks, nil + return nil } -func (engine *Engine) ApplySnapshotChunk(chunkIndex uint32, value []byte) (string, error) { - var bundle TendermintSsyncBundle - - if err := json.Unmarshal(value, &bundle); err != nil { - return abciTypes.ResponseApplySnapshotChunk_UNKNOWN.String(), fmt.Errorf("failed to unmarshal tendermint-ssync bundle: %w", err) - } - - nodeKey, err := tmP2P.LoadNodeKey(engine.config.NodeKeyFile()) +func (engine *Engine) ApplySnapshotChunk(chunkIndex int64, chunk []byte) error { + res, err := engine.proxyApp.Snapshot().ApplySnapshotChunkSync(abciTypes.RequestApplySnapshotChunk{ + Index: uint32(chunkIndex), + Chunk: chunk, + Sender: string(engine.nodeKey.ID()), + }) if err != nil { - return abciTypes.ResponseApplySnapshotChunk_UNKNOWN.String(), fmt.Errorf("loading node key file failed: %w", err) + return err } - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) - - if err := socketClient.Start(); err != nil { - return abciTypes.ResponseApplySnapshotChunk_UNKNOWN.String(), fmt.Errorf("failed to start socket client: %w", err) + if res.Result.String() != abciTypes.ResponseApplySnapshotChunk_ACCEPT.String() { + return fmt.Errorf(res.Result.String()) } - res, err := socketClient.ApplySnapshotChunkSync(abciTypes.RequestApplySnapshotChunk{ - Index: chunkIndex, - Chunk: bundle[0].Value.Chunk, - Sender: string(nodeKey.ID()), - }) + return nil +} - if err != nil { - return abciTypes.ResponseApplySnapshotChunk_UNKNOWN.String(), err - } +func (engine *Engine) BootstrapState(rawState, rawSeenCommit, rawBlock []byte) error { + var state *tmState.State - if err := socketClient.Stop(); err != nil { - return abciTypes.ResponseApplySnapshotChunk_UNKNOWN.String(), fmt.Errorf("failed to stop socket client: %w", err) + if err := json.Unmarshal(rawState, &state); err != nil { + return fmt.Errorf("failed to unmarshal state: %w", err) } - return res.Result.String(), nil -} + var seenCommit *tmTypes.Commit + + if err := json.Unmarshal(rawSeenCommit, &seenCommit); err != nil { + return fmt.Errorf("failed to unmarshal seen commit: %w", err) + } -func (engine *Engine) BootstrapState(value []byte) error { - var bundle TendermintSsyncBundle + var block *tmTypes.Block - if err := json.Unmarshal(value, &bundle); err != nil { - return fmt.Errorf("failed to unmarshal tendermint-ssync bundle: %w", err) + if err := json.Unmarshal(rawBlock, &block); err != nil { + return fmt.Errorf("failed to unmarshal block: %w", err) } - err := engine.stateStore.Bootstrap(*bundle[0].Value.State) + err := engine.stateStore.Bootstrap(*state) if err != nil { - return fmt.Errorf("failed to bootstrap state: %s\"", err) + return fmt.Errorf("failed to bootstrap state: %w", err) } - err = engine.blockStore.SaveSeenCommit(bundle[0].Value.State.LastBlockHeight, bundle[0].Value.SeenCommit) + err = engine.blockStore.SaveSeenCommit(state.LastBlockHeight, seenCommit) if err != nil { return fmt.Errorf("failed to save seen commit: %s\"", err) } - blockParts := bundle[0].Value.Block.MakePartSet(tmTypes.BlockPartSizeBytes) - engine.blockStore.SaveBlock(bundle[0].Value.Block, blockParts, bundle[0].Value.SeenCommit) + blockParts := block.MakePartSet(tmTypes.BlockPartSizeBytes) + engine.blockStore.SaveBlock(block, blockParts, seenCommit) return nil } @@ -764,28 +678,23 @@ func (engine *Engine) PruneBlocks(toHeight int64) error { } func (engine *Engine) ResetAll(keepAddrBook bool) error { - config, err := LoadConfig(engine.HomePath) - if err != nil { - return fmt.Errorf("failed to load config.toml: %w", err) - } - - dbDir := config.DBDir() - addrBookFile := config.P2P.AddrBookFile() - privValKeyFile := config.PrivValidatorKeyFile() - privValStateFile := config.PrivValidatorStateFile() + dbDir := engine.config.DBDir() + addrBookFile := engine.config.P2P.AddrBookFile() + privValKeyFile := engine.config.PrivValidatorKeyFile() + privValStateFile := engine.config.PrivValidatorStateFile() if keepAddrBook { - tmLogger.Info("the address book remains intact") + engineLogger.Info("the address book remains intact") } else { if err := os.Remove(addrBookFile); err == nil { - tmLogger.Info("removed existing address book", "file", addrBookFile) + engineLogger.Info("removed existing address book", "file", addrBookFile) } else if !os.IsNotExist(err) { return fmt.Errorf("error removing address book, file: %s, err: %w", addrBookFile, err) } } if err := os.RemoveAll(dbDir); err == nil { - tmLogger.Info("removed all blockchain history", "dir", dbDir) + engineLogger.Info("removed all blockchain history", "dir", dbDir) } else { return fmt.Errorf("error removing all blockchain history, dir: %s, err: %w", dbDir, err) } @@ -798,7 +707,7 @@ func (engine *Engine) ResetAll(keepAddrBook bool) error { if _, err := os.Stat(privValKeyFile); err == nil { pv := privval.LoadFilePVEmptyState(privValKeyFile, privValStateFile) pv.Reset() - tmLogger.Info( + engineLogger.Info( "Reset private validator file to genesis state", "keyFile", privValKeyFile, "stateFile", privValStateFile, @@ -806,12 +715,20 @@ func (engine *Engine) ResetAll(keepAddrBook bool) error { } else { pv := privval.GenFilePV(privValKeyFile, privValStateFile) pv.Save() - tmLogger.Info( + engineLogger.Info( "Generated private validator file", "keyFile", privValKeyFile, "stateFile", privValStateFile, ) } + if err := engine.CloseDBs(); err != nil { + return fmt.Errorf("failed to close dbs: %w", err) + } + + if err := engine.OpenDBs(); err != nil { + return fmt.Errorf("failed to open dbs: %w", err) + } + return nil } diff --git a/engines/celestia-core-v34/helpers.go b/engines/celestia-core-v34/helpers.go index 2efbb72..f2e36ad 100644 --- a/engines/celestia-core-v34/helpers.go +++ b/engines/celestia-core-v34/helpers.go @@ -1,17 +1,13 @@ package celestia_core_v34 import ( - "fmt" cfg "github.com/KYVENetwork/celestia-core/config" - cs "github.com/KYVENetwork/celestia-core/consensus" - "github.com/KYVENetwork/celestia-core/evidence" mempl "github.com/KYVENetwork/celestia-core/mempool" memplv0 "github.com/KYVENetwork/celestia-core/mempool/v0" "github.com/KYVENetwork/celestia-core/proxy" "github.com/KYVENetwork/celestia-core/state" sm "github.com/KYVENetwork/celestia-core/state" "github.com/KYVENetwork/celestia-core/store" - tmTypes "github.com/KYVENetwork/celestia-core/types" dbm "github.com/cometbft/cometbft-db" "github.com/spf13/viper" "path/filepath" @@ -72,45 +68,10 @@ func GetBlockstoreDBs(config *Config) (dbm.DB, *store.BlockStore, error) { return blockStoreDB, blockStore, nil } -func CreateAndStartProxyAppConns(config *Config) (proxy.AppConns, error) { - proxyApp := proxy.NewAppConns(proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir())) - proxyApp.SetLogger(tmLogger.With("module", "proxy")) - if err := proxyApp.Start(); err != nil { - return nil, fmt.Errorf("error starting proxy app connections: %v", err) - } - return proxyApp, nil -} - -func CreateAndStartEventBus() (*tmTypes.EventBus, error) { - eventBus := tmTypes.NewEventBus() - eventBus.SetLogger(tmLogger.With("module", "events")) - if err := eventBus.Start(); err != nil { - return nil, err - } - return eventBus, nil -} - -func DoHandshake( - stateStore sm.Store, - state sm.State, - blockStore sm.BlockStore, - genDoc *GenesisDoc, - eventBus tmTypes.BlockEventPublisher, - proxyApp proxy.AppConns, -) error { - handshaker := cs.NewHandshaker(stateStore, state, blockStore, genDoc) - handshaker.SetLogger(tmLogger.With("module", "consensus")) - handshaker.SetEventBus(eventBus) - if _, err := handshaker.Handshake(proxyApp); err != nil { - return fmt.Errorf("error during handshake: %v", err) - } - return nil -} - func CreateMempoolAndMempoolReactor(config *Config, proxyApp proxy.AppConns, state sm.State) mempl.Mempool { - logger := tmLogger.With("module", "mempool") + logger := engineLogger.With("module", "mempool") mp := memplv0.NewCListMempool( config.Mempool, proxyApp.Mempool(), @@ -127,18 +88,3 @@ func CreateMempoolAndMempoolReactor(config *Config, proxyApp proxy.AppConns, return mp } - -func CreateEvidenceReactor(config *Config, stateStore sm.Store, blockStore *store.BlockStore) (*evidence.Reactor, *evidence.Pool, error) { - evidenceDB, err := DefaultDBProvider(&DBContext{ID: "evidence", Config: config}) - if err != nil { - return nil, nil, err - } - evidenceLogger := tmLogger.With("module", "evidence") - evidencePool, err := evidence.NewPool(evidenceDB, stateStore, blockStore) - if err != nil { - return nil, nil, err - } - evidenceReactor := evidence.NewReactor(evidencePool) - evidenceReactor.SetLogger(evidenceLogger) - return evidenceReactor, evidencePool, nil -} diff --git a/engines/celestia-core-v34/logger.go b/engines/celestia-core-v34/logger.go index ae618d2..aa65944 100644 --- a/engines/celestia-core-v34/logger.go +++ b/engines/celestia-core-v34/logger.go @@ -3,46 +3,53 @@ package celestia_core_v34 import ( "fmt" "github.com/KYVENetwork/celestia-core/libs/log" - klogger "github.com/KYVENetwork/ksync/utils" + "github.com/KYVENetwork/ksync/logger" + "github.com/KYVENetwork/ksync/utils" "github.com/rs/zerolog" ) -func TmLogger() (logger log.Logger) { - logger = KsyncTmLogger{logger: klogger.LogFormatter("")} - return -} +var ( + engineLogger = EngineLogger{logger: logger.NewLogger(utils.EngineCelestiaCoreV34)} +) -type KsyncTmLogger struct { +type EngineLogger struct { logger zerolog.Logger } -func (l KsyncTmLogger) Debug(msg string, keyvals ...interface{}) {} +func (l EngineLogger) Debug(msg string, keyvals ...interface{}) { + logger := l.logger.Debug() + + for i := 0; i < len(keyvals); i = i + 2 { + logger = logger.Any(fmt.Sprintf("%s", keyvals[i]), keyvals[i+1]) + } + + logger.Msg(msg) +} -func (l KsyncTmLogger) Info(msg string, keyvals ...interface{}) { +func (l EngineLogger) Info(msg string, keyvals ...interface{}) { logger := l.logger.Info() for i := 0; i < len(keyvals); i = i + 2 { if keyvals[i] == "hash" || keyvals[i] == "appHash" { - logger = logger.Str(fmt.Sprintf("%v", keyvals[i]), fmt.Sprintf("%x", keyvals[i+1])) + logger = logger.Str(fmt.Sprintf("%v", keyvals[i]), fmt.Sprintf("%X", keyvals[i+1])) } else { - logger = logger.Str(fmt.Sprintf("%v", keyvals[i]), fmt.Sprintf("%v", keyvals[i+1])) + logger = logger.Any(fmt.Sprintf("%s", keyvals[i]), keyvals[i+1]) } } logger.Msg(msg) } -func (l KsyncTmLogger) Error(msg string, keyvals ...interface{}) { +func (l EngineLogger) Error(msg string, keyvals ...interface{}) { logger := l.logger.Error() for i := 0; i < len(keyvals); i = i + 2 { - logger = logger.Str(fmt.Sprintf("%v", keyvals[i]), fmt.Sprintf("%v", keyvals[i+1])) + logger = logger.Any(fmt.Sprintf("%s", keyvals[i]), keyvals[i+1]) } logger.Msg(msg) } -func (l KsyncTmLogger) With(keyvals ...interface{}) (logger log.Logger) { - logger = KsyncTmLogger{logger: klogger.LogFormatter(keyvals)} - return +func (l EngineLogger) With(keyvals ...interface{}) log.Logger { + return EngineLogger{logger: logger.NewLogger(utils.EngineCelestiaCoreV34, keyvals)} } diff --git a/engines/celestia-core-v34/p2p.go b/engines/celestia-core-v34/p2p.go index 9c8cb3a..4779920 100644 --- a/engines/celestia-core-v34/p2p.go +++ b/engines/celestia-core-v34/p2p.go @@ -8,7 +8,6 @@ import ( "github.com/KYVENetwork/celestia-core/p2p" bcproto "github.com/KYVENetwork/celestia-core/proto/celestiacore/blockchain" "github.com/KYVENetwork/celestia-core/version" - log "github.com/KYVENetwork/ksync/utils" "reflect" ) @@ -16,10 +15,6 @@ const ( BlockchainChannel = byte(0x40) ) -var ( - logger = log.KsyncLogger("p2p") -) - type BlockchainReactor struct { p2p.BaseReactor @@ -54,11 +49,11 @@ func (bcR *BlockchainReactor) sendStatusToPeer(src p2p.Peer) (queued bool) { Base: bcR.block.Height, Height: bcR.block.Height + 1}) if err != nil { - logger.Error().Str("could not convert msg to protobuf", err.Error()) + bcR.Logger.Error("could not convert msg to protobuf", err.Error()) return } - logger.Info().Int64("base", bcR.block.Height).Int64("height", bcR.block.Height+1).Msg("Sent status to peer") + bcR.Logger.Info("Sent status to peer", "base", bcR.block.Height, "height", bcR.block.Height+1) return src.Send(BlockchainChannel, msgBytes) } @@ -67,17 +62,17 @@ func (bcR *BlockchainReactor) sendBlockToPeer(msg *bcproto.BlockRequest, src p2p if msg.Height == bcR.block.Height { bl, err := bcR.block.ToProto() if err != nil { - logger.Error().Str("could not convert msg to protobuf", err.Error()) + bcR.Logger.Error("could not convert msg to protobuf", err.Error()) return false } msgBytes, err := bc.EncodeMsg(&bcproto.BlockResponse{Block: bl}) if err != nil { - logger.Error().Str("could not marshal msg", err.Error()) + bcR.Logger.Error("could not marshal msg", err.Error()) return false } - logger.Info().Msg(fmt.Sprintf("sent block with height %d to peer", bcR.block.Height)) + bcR.Logger.Info(fmt.Sprintf("sent block with height %d to peer", bcR.block.Height)) return src.TrySend(BlockchainChannel, msgBytes) } @@ -85,44 +80,44 @@ func (bcR *BlockchainReactor) sendBlockToPeer(msg *bcproto.BlockRequest, src p2p if msg.Height == bcR.nextBlock.Height { bl, err := bcR.nextBlock.ToProto() if err != nil { - logger.Error().Str("could not convert msg to protobuf", err.Error()) + bcR.Logger.Error("could not convert msg to protobuf", err.Error()) return false } msgBytes, err := bc.EncodeMsg(&bcproto.BlockResponse{Block: bl}) if err != nil { - logger.Error().Str("could not marshal msg", err.Error()) + bcR.Logger.Error("could not marshal msg", err.Error()) return false } - logger.Info().Msg(fmt.Sprintf("sent block with height %d to peer", bcR.nextBlock.Height)) + bcR.Logger.Info(fmt.Sprintf("sent block with height %d to peer", bcR.nextBlock.Height)) return src.TrySend(BlockchainChannel, msgBytes) } - logger.Error().Msg(fmt.Sprintf("peer asked for different block, expected = %d,%d, requested %d", bcR.block.Height, bcR.nextBlock.Height, msg.Height)) + bcR.Logger.Error(fmt.Sprintf("peer asked for different block, expected = %d,%d, requested %d", bcR.block.Height, bcR.nextBlock.Height, msg.Height)) return false } func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) { msg, err := bc.DecodeMsg(msgBytes) if err != nil { - logger.Error().Msgf("Error decoding message", fmt.Sprintf("src: %s", src), fmt.Sprintf("chId: %b", chID), err) + bcR.Logger.Error("Error decoding message", fmt.Sprintf("src: %s", src), fmt.Sprintf("chId: %b", chID), err) bcR.Switch.StopPeerForError(src, err) return } switch msg := msg.(type) { case *bcproto.StatusRequest: - logger.Info().Msg("Incoming status request") + bcR.Logger.Info("Incoming status request") bcR.sendStatusToPeer(src) case *bcproto.BlockRequest: - logger.Info().Int64("height", msg.Height).Msg("Incoming block request") + bcR.Logger.Info("Incoming block request", "height", msg.Height) bcR.sendBlockToPeer(msg, src) case *bcproto.StatusResponse: - logger.Info().Int64("base", msg.Base).Int64("height", msg.Height).Msgf("Incoming status response") + bcR.Logger.Info("Incoming status response", "base", msg.Base, "height", msg.Height) default: - logger.Error().Msg(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg))) + bcR.Logger.Error(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg))) } } diff --git a/engines/celestia-core-v34/types.go b/engines/celestia-core-v34/types.go index 7b87cca..83bec33 100644 --- a/engines/celestia-core-v34/types.go +++ b/engines/celestia-core-v34/types.go @@ -4,56 +4,14 @@ import ( abciTypes "github.com/KYVENetwork/celestia-core/abci/types" tmCfg "github.com/KYVENetwork/celestia-core/config" tmP2P "github.com/KYVENetwork/celestia-core/p2p" - tmState "github.com/KYVENetwork/celestia-core/state" tmTypes "github.com/KYVENetwork/celestia-core/types" ) type Block = tmTypes.Block -type LightBlock = tmTypes.LightBlock type Snapshot = abciTypes.Snapshot type Config = tmCfg.Config type GenesisDoc = tmTypes.GenesisDoc -type TendermintValue struct { - Block struct { - Block *Block `json:"block"` - } `json:"block"` -} - -type TendermintDataItem struct { - Key string `json:"key"` - Value TendermintValue `json:"value"` -} - -type TendermintBsyncDataItem struct { - Key string `json:"key"` - Value *Block `json:"value"` -} - -type TendermintBundle = []TendermintDataItem - -type TendermintBsyncBundle = []TendermintBsyncDataItem - -type TendermintSsyncBundle = []TendermintSsyncDataItem - -type TendermintSsyncDataItem struct { - Key string `json:"key"` - Value struct { - Snapshot *abciTypes.Snapshot `json:"snapshot"` - Block *Block `json:"block"` - SeenCommit *tmTypes.Commit `json:"seenCommit"` - State *tmState.State `json:"state"` - ChunkIndex uint32 `json:"chunkIndex"` - Chunk []byte `json:"chunk"` - } `json:"value"` -} - -type BlockResponse struct { - Result struct { - Block tmTypes.Block `json:"block"` - } `json:"result"` -} - type Transport struct { nodeInfo tmP2P.NodeInfo } diff --git a/engines/cometbft-v37/cometbft.go b/engines/cometbft-v37/cometbft.go index 5a672db..024c3a9 100644 --- a/engines/cometbft-v37/cometbft.go +++ b/engines/cometbft-v37/cometbft.go @@ -2,7 +2,6 @@ package cometbft_v37 import ( "fmt" - abciClient "github.com/KYVENetwork/cometbft/v37/abci/client" abciTypes "github.com/KYVENetwork/cometbft/v37/abci/types" cfg "github.com/KYVENetwork/cometbft/v37/config" cs "github.com/KYVENetwork/cometbft/v37/consensus" @@ -21,6 +20,7 @@ import ( rpcserver "github.com/KYVENetwork/cometbft/v37/rpc/jsonrpc/server" tmState "github.com/KYVENetwork/cometbft/v37/state" tmStore "github.com/KYVENetwork/cometbft/v37/store" + cometTypes "github.com/KYVENetwork/cometbft/v37/types" tmTypes "github.com/KYVENetwork/cometbft/v37/types" "github.com/KYVENetwork/ksync/utils" db "github.com/cometbft/cometbft-db" @@ -31,15 +31,10 @@ import ( "time" ) -var ( - cometLogger = CometLogger() -) - type Engine struct { - HomePath string - RpcServerPort int64 - areDBsOpen bool - config *cfg.Config + homePath string + areDBsOpen bool + config *cfg.Config blockDB db.DB blockStore *tmStore.BlockStore @@ -47,17 +42,35 @@ type Engine struct { stateDB db.DB stateStore tmState.Store + evidenceDB db.DB + genDoc *GenesisDoc privValidatorKey crypto.PubKey + nodeKey *cometP2P.NodeKey state tmState.State - prevBlock *Block proxyApp proxy.AppConns mempool *mempool.Mempool evidencePool *evidence.Pool blockExecutor *tmState.BlockExecutor } +func NewEngine(homePath string) (*Engine, error) { + engine := &Engine{ + homePath: homePath, + } + + if err := engine.LoadConfig(); err != nil { + return nil, err + } + + if err := engine.OpenDBs(); err != nil { + return nil, err + } + + return engine, nil +} + func (engine *Engine) GetName() string { return utils.EngineCometBFTV37 } @@ -67,32 +80,18 @@ func (engine *Engine) LoadConfig() error { return nil } - config, err := LoadConfig(engine.HomePath) + config, err := LoadConfig(engine.homePath) if err != nil { return fmt.Errorf("failed to load config.toml: %w", err) } engine.config = config - return nil -} - -func (engine *Engine) OpenDBs() error { - if engine.areDBsOpen { - return nil - } - - if err := engine.LoadConfig(); err != nil { - return err - } - - if err := utils.FormatGenesisFile(engine.config.GenesisFile()); err != nil { - return fmt.Errorf("failed to format genesis file: %w", err) - } genDoc, err := nm.DefaultGenesisDocProviderFunc(engine.config)() if err != nil { return fmt.Errorf("failed to load state and genDoc: %w", err) } + engine.genDoc = genDoc privValidatorKey, err := privval.LoadFilePVEmptyState( @@ -104,6 +103,21 @@ func (engine *Engine) OpenDBs() error { } engine.privValidatorKey = privValidatorKey + nodeKey, err := cometP2P.LoadNodeKey(engine.config.NodeKeyFile()) + if err != nil { + return fmt.Errorf("loading node key file failed: %w", err) + } + engine.nodeKey = nodeKey + + engineLogger.Debug("loaded config", "configPath", fmt.Sprintf("%s/config.toml", engine.homePath)) + return nil +} + +func (engine *Engine) OpenDBs() error { + if engine.areDBsOpen { + return nil + } + blockDB, blockStore, err := GetBlockstoreDBs(engine.config) if err != nil { return fmt.Errorf("failed to open blockDB: %w", err) @@ -120,7 +134,23 @@ func (engine *Engine) OpenDBs() error { engine.stateDB = stateDB engine.stateStore = stateStore + evidenceDB, err := DefaultDBProvider(&DBContext{ID: "evidence", Config: engine.config}) + if err != nil { + return fmt.Errorf("failed to open evidenceDB: %w", err) + } + + engine.evidenceDB = evidenceDB + engine.areDBsOpen = true + engineLogger.Debug( + "opened dbs", + "blockDB", + fmt.Sprintf("%s/%s/blockstore.db", engine.homePath, engine.config.DBPath), + "stateDB", + fmt.Sprintf("%s/%s/state.db", engine.homePath, engine.config.DBPath), + "evidenceDB", + fmt.Sprintf("%s/%s/evidence.db", engine.homePath, engine.config.DBPath), + ) return nil } @@ -137,12 +167,25 @@ func (engine *Engine) CloseDBs() error { return fmt.Errorf("failed to close stateDB: %w", err) } + if err := engine.evidenceDB.Close(); err != nil { + return fmt.Errorf("failed to close evidenceDB: %w", err) + } + engine.areDBsOpen = false + engineLogger.Debug( + "closed dbs", + "blockDB", + fmt.Sprintf("%s/%s/blockstore.db", engine.homePath, engine.config.DBPath), + "stateDB", + fmt.Sprintf("%s/%s/state.db", engine.homePath, engine.config.DBPath), + "evidenceDB", + fmt.Sprintf("%s/%s/evidence.db", engine.homePath, engine.config.DBPath), + ) return nil } -func (engine *Engine) GetHomePath() string { - return engine.HomePath +func (engine *Engine) GetRpcListenAddress() string { + return engine.config.RPC.ListenAddress } func (engine *Engine) GetProxyAppAddress() string { @@ -154,12 +197,12 @@ func (engine *Engine) StartProxyApp() error { return fmt.Errorf("proxy app already started") } - proxyApp, err := CreateAndStartProxyAppConns(engine.config) - if err != nil { - return err + engine.proxyApp = proxy.NewAppConns(proxy.NewRemoteClientCreator(engine.config.ProxyApp, engine.config.ABCI, false), proxy.NopMetrics()) + if err := engine.proxyApp.Start(); err != nil { + return fmt.Errorf("failed to start proxy app: %w", err) } - engine.proxyApp = proxyApp + engineLogger.Debug("started proxy app connections", "address", engine.GetProxyAppAddress()) return nil } @@ -173,39 +216,10 @@ func (engine *Engine) StopProxyApp() error { } engine.proxyApp = nil + engineLogger.Debug("stopped proxy app connections", "address", engine.GetProxyAppAddress()) return nil } -func (engine *Engine) GetChainId() (string, error) { - if err := engine.LoadConfig(); err != nil { - return "", fmt.Errorf("failed to load config: %w", err) - } - - genDoc, err := nm.DefaultGenesisDocProviderFunc(engine.config)() - if err != nil { - return "", fmt.Errorf("failed to load genDoc: %w", err) - } - - return genDoc.ChainID, nil -} - -func (engine *Engine) GetContinuationHeight() (int64, error) { - height := engine.blockStore.Height() - - initialHeight, err := utils.GetInitialHeightFromGenesisFile(engine.GetGenesisPath()) - if err != nil { - return 0, fmt.Errorf("failed to load initial height from genesis file: %w", err) - } - - continuationHeight := height + 1 - - if continuationHeight < initialHeight { - continuationHeight = initialHeight - } - - return continuationHeight, nil -} - func (engine *Engine) DoHandshake() error { state, err := tmState.NewStore(engine.stateDB, tmState.StoreOptions{ DiscardABCIResponses: false, @@ -214,13 +228,17 @@ func (engine *Engine) DoHandshake() error { return fmt.Errorf("failed to load state from genDoc: %w", err) } - eventBus, err := CreateAndStartEventBus() - if err != nil { + eventBus := cometTypes.NewEventBus() + eventBus.SetLogger(engineLogger.With("module", "events")) + if err := eventBus.Start(); err != nil { return fmt.Errorf("failed to start event bus: %w", err) } - if err := DoHandshake(engine.stateStore, state, engine.blockStore, engine.genDoc, eventBus, engine.proxyApp); err != nil { - return fmt.Errorf("failed to do handshake: %w", err) + handshaker := cs.NewHandshaker(engine.stateStore, state, engine.blockStore, engine.genDoc) + handshaker.SetLogger(engineLogger.With("module", "consensus")) + handshaker.SetEventBus(eventBus) + if err := handshaker.Handshake(engine.proxyApp); err != nil { + return fmt.Errorf("error during handshake: %v", err) } state, err = engine.stateStore.Load() @@ -230,119 +248,78 @@ func (engine *Engine) DoHandshake() error { engine.state = state - mempool := CreateMempool(engine.config, engine.proxyApp, state) + mp := CreateMempool(engine.config, engine.proxyApp, state) - _, evidencePool, err := CreateEvidenceReactor(engine.config, engine.stateStore, engine.blockStore) + evidencePool, err := evidence.NewPool(engine.evidenceDB, engine.stateStore, engine.blockStore) if err != nil { - return fmt.Errorf("failed to create evidence reactor: %w", err) + return fmt.Errorf("failed to create evidence pool: %w", err) } - engine.mempool = &mempool + engine.mempool = &mp engine.evidencePool = evidencePool engine.blockExecutor = tmState.NewBlockExecutor( engine.stateStore, - cometLogger.With("module", "state"), + engineLogger.With("module", "state"), engine.proxyApp.Consensus(), - mempool, + mp, evidencePool, ) return nil } -func (engine *Engine) ApplyBlock(runtime *string, value []byte) error { - var block *Block - - if runtime == nil { - // if runtime is nil we sync from another cometbft node - var blockResponse BlockResponse - err := json.Unmarshal(value, &blockResponse) - if err != nil { - return fmt.Errorf("failed to unmarshal block response: %w", err) - } - block = &blockResponse.Result.Block - } else if *runtime == utils.KSyncRuntimeTendermint { - var parsed TendermintValue - - if err := json.Unmarshal(value, &parsed); err != nil { - return fmt.Errorf("failed to unmarshal value: %w", err) - } +func (engine *Engine) ApplyBlock(rawBlock, nextRawBlock []byte) error { + var block, nextBlock *Block - block = parsed.Block.Block - } else if *runtime == utils.KSyncRuntimeTendermintBsync { - if err := json.Unmarshal(value, &block); err != nil { - return fmt.Errorf("failed to unmarshal value: %w", err) - } - } else { - return fmt.Errorf("runtime %s unknown", runtime) + if err := json.Unmarshal(rawBlock, &block); err != nil { + return fmt.Errorf("failed to unmarshal block: %w", err) } - // if the previous block is not defined we continue - if engine.prevBlock == nil { - engine.prevBlock = block - return nil + if err := json.Unmarshal(nextRawBlock, &nextBlock); err != nil { + return fmt.Errorf("failed to unmarshal next block: %w", err) } // get block data - blockParts, err := engine.prevBlock.MakePartSet(tmTypes.BlockPartSizeBytes) + blockParts, err := block.MakePartSet(tmTypes.BlockPartSizeBytes) if err != nil { return fmt.Errorf("failed make part set of block: %w", err) } - blockId := tmTypes.BlockID{Hash: engine.prevBlock.Hash(), PartSetHeader: blockParts.Header()} + blockId := tmTypes.BlockID{Hash: block.Hash(), PartSetHeader: blockParts.Header()} // verify block - if err := engine.blockExecutor.ValidateBlock(engine.state, engine.prevBlock); err != nil { - return fmt.Errorf("block validation failed at height %d: %w", engine.prevBlock.Height, err) + if err := engine.blockExecutor.ValidateBlock(engine.state, block); err != nil { + return fmt.Errorf("block validation failed at height %d: %w", block.Height, err) } // verify commits - if err := engine.state.Validators.VerifyCommitLight(engine.state.ChainID, blockId, engine.prevBlock.Height, block.LastCommit); err != nil { - return fmt.Errorf("light commit verification failed at height %d: %w", engine.prevBlock.Height, err) + if err := engine.state.Validators.VerifyCommitLight(engine.state.ChainID, blockId, block.Height, nextBlock.LastCommit); err != nil { + return fmt.Errorf("light commit verification failed at height %d: %w", block.Height, err) } // store block - engine.blockStore.SaveBlock(engine.prevBlock, blockParts, block.LastCommit) + engine.blockStore.SaveBlock(block, blockParts, nextBlock.LastCommit) // execute block against app - state, _, err := engine.blockExecutor.ApplyBlock(engine.state, blockId, engine.prevBlock) + state, _, err := engine.blockExecutor.ApplyBlock(engine.state, blockId, block) if err != nil { - return fmt.Errorf("failed to apply block at height %d: %w", engine.prevBlock.Height, err) + return fmt.Errorf("failed to apply block at height %d: %w", block.Height, err) } - // update values for next round + // update state for next round engine.state = state - engine.prevBlock = block - return nil } -func (engine *Engine) ApplyFirstBlockOverP2P(runtime string, value, nextValue []byte) error { +func (engine *Engine) ApplyFirstBlockOverP2P(rawBlock, nextRawBlock []byte) error { var block, nextBlock *Block - if runtime == utils.KSyncRuntimeTendermint { - var parsed, nextParsed TendermintValue - - if err := json.Unmarshal(value, &parsed); err != nil { - return fmt.Errorf("failed to unmarshal value: %w", err) - } - - if err := json.Unmarshal(nextValue, &nextParsed); err != nil { - return fmt.Errorf("failed to unmarshal next value: %w", err) - } - - block = parsed.Block.Block - nextBlock = nextParsed.Block.Block - } else if runtime == utils.KSyncRuntimeTendermintBsync { - if err := json.Unmarshal(value, &block); err != nil { - return fmt.Errorf("failed to unmarshal value: %w", err) - } + if err := json.Unmarshal(rawBlock, &block); err != nil { + return fmt.Errorf("failed to unmarshal block: %w", err) + } - if err := json.Unmarshal(nextValue, &nextBlock); err != nil { - return fmt.Errorf("failed to unmarshal next value: %w", err) - } - } else { - return fmt.Errorf("runtime %s unknown", runtime) + if err := json.Unmarshal(nextRawBlock, &nextBlock); err != nil { + return fmt.Errorf("failed to unmarshal next block: %w", err) } peerAddress := engine.config.P2P.ListenAddress @@ -372,7 +349,7 @@ func (engine *Engine) ApplyFirstBlockOverP2P(runtime string, value, nextValue [] nodeInfo, err := MakeNodeInfo(engine.config, ksyncNodeKey, engine.genDoc) transport := cometP2P.NewMultiplexTransport(nodeInfo, *ksyncNodeKey, cometP2P.MConnConfig(engine.config.P2P)) bcR := NewBlockchainReactor(block, nextBlock) - sw := CreateSwitch(engine.config, transport, bcR, nodeInfo, ksyncNodeKey, cometLogger) + sw := CreateSwitch(engine.config, transport, bcR, nodeInfo, ksyncNodeKey, engineLogger) // start the transport addr, err := cometP2P.NewNetAddressString(cometP2P.IDAddressString(ksyncNodeKey.ID(), engine.config.P2P.ListenAddress)) @@ -409,20 +386,6 @@ func (engine *Engine) ApplyFirstBlockOverP2P(runtime string, value, nextValue [] return nil } -func (engine *Engine) GetGenesisPath() string { - return engine.config.GenesisFile() -} - -func (engine *Engine) GetGenesisHeight() (int64, error) { - defaultDocProvider := nm.DefaultGenesisDocProviderFunc(engine.config) - genDoc, err := defaultDocProvider() - if err != nil { - return 0, err - } - - return genDoc.InitialHeight, nil -} - func (engine *Engine) GetHeight() int64 { return engine.blockStore.Height() } @@ -432,40 +395,20 @@ func (engine *Engine) GetBaseHeight() int64 { } func (engine *Engine) GetAppHeight() (int64, error) { - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) - - if err := socketClient.Start(); err != nil { - return 0, fmt.Errorf("failed to start socket client: %w", err) - } - - info, err := socketClient.InfoSync(abciTypes.RequestInfo{}) + info, err := engine.proxyApp.Query().InfoSync(abciTypes.RequestInfo{}) if err != nil { return 0, fmt.Errorf("failed to query info: %w", err) } - if err := socketClient.Stop(); err != nil { - return 0, fmt.Errorf("failed to stop socket client: %w", err) - } - return info.LastBlockHeight, nil } func (engine *Engine) GetSnapshots() ([]byte, error) { - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) - - if err := socketClient.Start(); err != nil { - return nil, fmt.Errorf("failed to start socket client: %w", err) - } - - res, err := socketClient.ListSnapshotsSync(abciTypes.RequestListSnapshots{}) + res, err := engine.proxyApp.Snapshot().ListSnapshotsSync(abciTypes.RequestListSnapshots{}) if err != nil { return nil, fmt.Errorf("failed to list snapshots: %w", err) } - if err := socketClient.Stop(); err != nil { - return nil, fmt.Errorf("failed to stop socket client: %w", err) - } - if len(res.Snapshots) == 0 { return json.Marshal([]Snapshot{}) } @@ -474,21 +417,11 @@ func (engine *Engine) GetSnapshots() ([]byte, error) { } func (engine *Engine) IsSnapshotAvailable(height int64) (bool, error) { - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) - - if err := socketClient.Start(); err != nil { - return false, fmt.Errorf("failed to start socket client: %w", err) - } - - res, err := socketClient.ListSnapshotsSync(abciTypes.RequestListSnapshots{}) + res, err := engine.proxyApp.Snapshot().ListSnapshotsSync(abciTypes.RequestListSnapshots{}) if err != nil { return false, fmt.Errorf("failed to list snapshots: %w", err) } - if err := socketClient.Stop(); err != nil { - return false, fmt.Errorf("failed to stop socket client: %w", err) - } - for _, snapshot := range res.Snapshots { if snapshot.Height == uint64(height) { return true, nil @@ -499,13 +432,7 @@ func (engine *Engine) IsSnapshotAvailable(height int64) (bool, error) { } func (engine *Engine) GetSnapshotChunk(height, format, chunk int64) ([]byte, error) { - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) - - if err := socketClient.Start(); err != nil { - return nil, fmt.Errorf("failed to start socket client: %w", err) - } - - res, err := socketClient.LoadSnapshotChunkSync(abciTypes.RequestLoadSnapshotChunk{ + res, err := engine.proxyApp.Snapshot().LoadSnapshotChunkSync(abciTypes.RequestLoadSnapshotChunk{ Height: uint64(height), Format: uint32(format), Chunk: uint32(chunk), @@ -514,10 +441,6 @@ func (engine *Engine) GetSnapshotChunk(height, format, chunk int64) ([]byte, err return nil, fmt.Errorf("failed to load snapshot chunk: %w", err) } - if err := socketClient.Stop(); err != nil { - return nil, fmt.Errorf("failed to stop socket client: %w", err) - } - return json.Marshal(res.Chunk) } @@ -526,13 +449,13 @@ func (engine *Engine) GetBlock(height int64) ([]byte, error) { return json.Marshal(block) } -func (engine *Engine) StartRPCServer() { +func (engine *Engine) StartRPCServer(port int64) { // wait until all reactors have been booted for engine.blockExecutor == nil { time.Sleep(1000) } - rpcLogger := cometLogger.With("module", "rpc-server") + rpcLogger := engineLogger.With("module", "rpc-server") consensusReactor := cs.NewReactor(cs.NewState( engine.config.Consensus, @@ -545,12 +468,12 @@ func (engine *Engine) StartRPCServer() { nodeKey, err := cometP2P.LoadNodeKey(engine.config.NodeKeyFile()) if err != nil { - cometLogger.Error(fmt.Sprintf("failed to get nodeKey: %s", err)) + engineLogger.Error(fmt.Sprintf("failed to get nodeKey: %s", err)) return } nodeInfo, err := MakeNodeInfo(engine.config, nodeKey, engine.genDoc) if err != nil { - cometLogger.Error(fmt.Sprintf("failed to get nodeInfo: %s", err)) + engineLogger.Error(fmt.Sprintf("failed to get nodeInfo: %s", err)) return } @@ -584,14 +507,14 @@ func (engine *Engine) StartRPCServer() { config := rpcserver.DefaultConfig() rpcserver.RegisterRPCFuncs(mux, routes, rpcLogger) - listener, err := rpcserver.Listen(fmt.Sprintf("tcp://127.0.0.1:%d", engine.RpcServerPort), config) + listener, err := rpcserver.Listen(fmt.Sprintf("tcp://127.0.0.1:%d", port), config) if err != nil { - cometLogger.Error(fmt.Sprintf("failed to get rpc listener: %s", err)) + engineLogger.Error(fmt.Sprintf("failed to get rpc listener: %s", err)) return } if err := rpcserver.Serve(listener, mux, rpcLogger, config); err != nil { - cometLogger.Error(fmt.Sprintf("failed to start rpc server: %s", err)) + engineLogger.Error(fmt.Sprintf("failed to start rpc server: %s", err)) return } } @@ -653,93 +576,86 @@ func (engine *Engine) GetSeenCommit(height int64) ([]byte, error) { return json.Marshal(block.LastCommit) } -func (engine *Engine) OfferSnapshot(value []byte) (string, uint32, error) { - var bundle TendermintSsyncBundle +func (engine *Engine) OfferSnapshot(rawSnapshot, rawState []byte) error { + var snapshot *abciTypes.Snapshot - if err := json.Unmarshal(value, &bundle); err != nil { - return abciTypes.ResponseOfferSnapshot_UNKNOWN.String(), 0, fmt.Errorf("failed to unmarshal tendermint-ssync bundle: %w", err) + if err := json.Unmarshal(rawSnapshot, &snapshot); err != nil { + return fmt.Errorf("failed to unmarshal snapshot: %w", err) } - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) + var state *tmState.State - if err := socketClient.Start(); err != nil { - return abciTypes.ResponseOfferSnapshot_UNKNOWN.String(), 0, fmt.Errorf("failed to start socket client: %w", err) + if err := json.Unmarshal(rawState, &state); err != nil { + return fmt.Errorf("failed to unmarshal state: %w", err) } - res, err := socketClient.OfferSnapshotSync(abciTypes.RequestOfferSnapshot{ - Snapshot: bundle[0].Value.Snapshot, - AppHash: bundle[0].Value.State.AppHash, + res, err := engine.proxyApp.Snapshot().OfferSnapshotSync(abciTypes.RequestOfferSnapshot{ + Snapshot: snapshot, + AppHash: state.AppHash, }) - if err != nil { - return abciTypes.ResponseOfferSnapshot_UNKNOWN.String(), 0, err + return err } - if err := socketClient.Stop(); err != nil { - return abciTypes.ResponseOfferSnapshot_UNKNOWN.String(), 0, fmt.Errorf("failed to stop socket client: %w", err) + if res.Result.String() != abciTypes.ResponseOfferSnapshot_ACCEPT.String() { + return fmt.Errorf(res.Result.String()) } - return res.Result.String(), bundle[0].Value.Snapshot.Chunks, nil + return nil } -func (engine *Engine) ApplySnapshotChunk(chunkIndex uint32, value []byte) (string, error) { - var bundle TendermintSsyncBundle - - if err := json.Unmarshal(value, &bundle); err != nil { - return abciTypes.ResponseApplySnapshotChunk_UNKNOWN.String(), fmt.Errorf("failed to unmarshal tendermint-ssync bundle: %w", err) - } - - nodeKey, err := cometP2P.LoadNodeKey(engine.config.NodeKeyFile()) +func (engine *Engine) ApplySnapshotChunk(chunkIndex int64, chunk []byte) error { + res, err := engine.proxyApp.Snapshot().ApplySnapshotChunkSync(abciTypes.RequestApplySnapshotChunk{ + Index: uint32(chunkIndex), + Chunk: chunk, + Sender: string(engine.nodeKey.ID()), + }) if err != nil { - return abciTypes.ResponseApplySnapshotChunk_UNKNOWN.String(), fmt.Errorf("loading node key file failed: %w", err) + return err } - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) - - if err := socketClient.Start(); err != nil { - return abciTypes.ResponseApplySnapshotChunk_UNKNOWN.String(), fmt.Errorf("failed to start socket client: %w", err) + if res.Result.String() != abciTypes.ResponseApplySnapshotChunk_ACCEPT.String() { + return fmt.Errorf(res.Result.String()) } - res, err := socketClient.ApplySnapshotChunkSync(abciTypes.RequestApplySnapshotChunk{ - Index: chunkIndex, - Chunk: bundle[0].Value.Chunk, - Sender: string(nodeKey.ID()), - }) + return nil +} - if err != nil { - return abciTypes.ResponseApplySnapshotChunk_UNKNOWN.String(), err - } +func (engine *Engine) BootstrapState(rawState, rawSeenCommit, rawBlock []byte) error { + var state *tmState.State - if err := socketClient.Stop(); err != nil { - return abciTypes.ResponseApplySnapshotChunk_UNKNOWN.String(), fmt.Errorf("failed to stop socket client: %w", err) + if err := json.Unmarshal(rawState, &state); err != nil { + return fmt.Errorf("failed to unmarshal state: %w", err) } - return res.Result.String(), nil -} + var seenCommit *tmTypes.Commit + + if err := json.Unmarshal(rawSeenCommit, &seenCommit); err != nil { + return fmt.Errorf("failed to unmarshal seen commit: %w", err) + } -func (engine *Engine) BootstrapState(value []byte) error { - var bundle TendermintSsyncBundle + var block *tmTypes.Block - if err := json.Unmarshal(value, &bundle); err != nil { - return fmt.Errorf("failed to unmarshal tendermint-ssync bundle: %w", err) + if err := json.Unmarshal(rawBlock, &block); err != nil { + return fmt.Errorf("failed to unmarshal block: %w", err) } - err := engine.stateStore.Bootstrap(*bundle[0].Value.State) + err := engine.stateStore.Bootstrap(*state) if err != nil { return fmt.Errorf("failed to bootstrap state: %w", err) } - err = engine.blockStore.SaveSeenCommit(bundle[0].Value.State.LastBlockHeight, bundle[0].Value.SeenCommit) + err = engine.blockStore.SaveSeenCommit(state.LastBlockHeight, seenCommit) if err != nil { - return fmt.Errorf("failed to save seen commit: %w", err) + return fmt.Errorf("failed to save seen commit: %s\"", err) } - blockParts, err := bundle[0].Value.Block.MakePartSet(tmTypes.BlockPartSizeBytes) + blockParts, err := block.MakePartSet(tmTypes.BlockPartSizeBytes) if err != nil { - return fmt.Errorf("failed make part set of block: %w", err) + return fmt.Errorf("failed to make block parts: %w", err) } - engine.blockStore.SaveBlock(bundle[0].Value.Block, blockParts, bundle[0].Value.SeenCommit) + engine.blockStore.SaveBlock(block, blockParts, seenCommit) return nil } @@ -762,28 +678,23 @@ func (engine *Engine) PruneBlocks(toHeight int64) error { } func (engine *Engine) ResetAll(keepAddrBook bool) error { - config, err := LoadConfig(engine.HomePath) - if err != nil { - return fmt.Errorf("failed to load config.toml: %w", err) - } - - dbDir := config.DBDir() - addrBookFile := config.P2P.AddrBookFile() - privValKeyFile := config.PrivValidatorKeyFile() - privValStateFile := config.PrivValidatorStateFile() + dbDir := engine.config.DBDir() + addrBookFile := engine.config.P2P.AddrBookFile() + privValKeyFile := engine.config.PrivValidatorKeyFile() + privValStateFile := engine.config.PrivValidatorStateFile() if keepAddrBook { - cometLogger.Info("the address book remains intact") + engineLogger.Info("the address book remains intact") } else { if err := os.Remove(addrBookFile); err == nil { - cometLogger.Info("removed existing address book", "file", addrBookFile) + engineLogger.Info("removed existing address book", "file", addrBookFile) } else if !os.IsNotExist(err) { return fmt.Errorf("error removing address book, file: %s, err: %w", addrBookFile, err) } } if err := os.RemoveAll(dbDir); err == nil { - cometLogger.Info("removed all blockchain history", "dir", dbDir) + engineLogger.Info("removed all blockchain history", "dir", dbDir) } else { return fmt.Errorf("error removing all blockchain history, dir: %s, err: %w", dbDir, err) } @@ -796,7 +707,7 @@ func (engine *Engine) ResetAll(keepAddrBook bool) error { if _, err := os.Stat(privValKeyFile); err == nil { pv := privval.LoadFilePVEmptyState(privValKeyFile, privValStateFile) pv.Reset() - cometLogger.Info( + engineLogger.Info( "Reset private validator file to genesis state", "keyFile", privValKeyFile, "stateFile", privValStateFile, @@ -804,12 +715,20 @@ func (engine *Engine) ResetAll(keepAddrBook bool) error { } else { pv := privval.GenFilePV(privValKeyFile, privValStateFile) pv.Save() - cometLogger.Info( + engineLogger.Info( "Generated private validator file", "keyFile", privValKeyFile, "stateFile", privValStateFile, ) } + if err := engine.CloseDBs(); err != nil { + return fmt.Errorf("failed to close dbs: %w", err) + } + + if err := engine.OpenDBs(); err != nil { + return fmt.Errorf("failed to open dbs: %w", err) + } + return nil } diff --git a/engines/cometbft-v37/helpers.go b/engines/cometbft-v37/helpers.go index f0c8213..2261981 100644 --- a/engines/cometbft-v37/helpers.go +++ b/engines/cometbft-v37/helpers.go @@ -1,17 +1,13 @@ package cometbft_v37 import ( - "fmt" cfg "github.com/KYVENetwork/cometbft/v37/config" - cs "github.com/KYVENetwork/cometbft/v37/consensus" - "github.com/KYVENetwork/cometbft/v37/evidence" mempl "github.com/KYVENetwork/cometbft/v37/mempool" memplv0 "github.com/KYVENetwork/cometbft/v37/mempool/v0" "github.com/KYVENetwork/cometbft/v37/proxy" "github.com/KYVENetwork/cometbft/v37/state" sm "github.com/KYVENetwork/cometbft/v37/state" "github.com/KYVENetwork/cometbft/v37/store" - cometTypes "github.com/KYVENetwork/cometbft/v37/types" dbm "github.com/cometbft/cometbft-db" "github.com/spf13/viper" "path/filepath" @@ -72,43 +68,8 @@ func GetBlockstoreDBs(config *Config) (dbm.DB, *store.BlockStore, error) { return blockStoreDB, blockStore, nil } -func CreateAndStartProxyAppConns(config *Config) (proxy.AppConns, error) { - proxyApp := proxy.NewAppConns(proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()), proxy.NopMetrics()) - proxyApp.SetLogger(cometLogger.With("module", "proxy")) - if err := proxyApp.Start(); err != nil { - return nil, fmt.Errorf("error starting proxy app connections: %v", err) - } - return proxyApp, nil -} - -func CreateAndStartEventBus() (*cometTypes.EventBus, error) { - eventBus := cometTypes.NewEventBus() - eventBus.SetLogger(cometLogger.With("module", "events")) - if err := eventBus.Start(); err != nil { - return nil, err - } - return eventBus, nil -} - -func DoHandshake( - stateStore sm.Store, - state sm.State, - blockStore sm.BlockStore, - genDoc *GenesisDoc, - eventBus cometTypes.BlockEventPublisher, - proxyApp proxy.AppConns, -) error { - handshaker := cs.NewHandshaker(stateStore, state, blockStore, genDoc) - handshaker.SetLogger(cometLogger.With("module", "consensus")) - handshaker.SetEventBus(eventBus) - if err := handshaker.Handshake(proxyApp); err != nil { - return fmt.Errorf("error during handshake: %v", err) - } - return nil -} - func CreateMempool(config *Config, proxyApp proxy.AppConns, state sm.State) mempl.Mempool { - logger := cometLogger.With("module", "mempool") + logger := engineLogger.With("module", "mempool") mp := memplv0.NewCListMempool( config.Mempool, proxyApp.Mempool(), @@ -125,18 +86,3 @@ func CreateMempool(config *Config, proxyApp proxy.AppConns, state sm.State) memp return mp } - -func CreateEvidenceReactor(config *Config, stateStore sm.Store, blockStore *store.BlockStore) (*evidence.Reactor, *evidence.Pool, error) { - evidenceDB, err := DefaultDBProvider(&DBContext{ID: "evidence", Config: config}) - if err != nil { - return nil, nil, err - } - evidenceLogger := cometLogger.With("module", "evidence") - evidencePool, err := evidence.NewPool(evidenceDB, stateStore, blockStore) - if err != nil { - return nil, nil, err - } - evidenceReactor := evidence.NewReactor(evidencePool) - evidenceReactor.SetLogger(evidenceLogger) - return evidenceReactor, evidencePool, nil -} diff --git a/engines/cometbft-v37/logger.go b/engines/cometbft-v37/logger.go index 2cb14f3..a2fc68a 100644 --- a/engines/cometbft-v37/logger.go +++ b/engines/cometbft-v37/logger.go @@ -3,46 +3,53 @@ package cometbft_v37 import ( "fmt" "github.com/KYVENetwork/cometbft/v37/libs/log" - klogger "github.com/KYVENetwork/ksync/utils" + "github.com/KYVENetwork/ksync/logger" + "github.com/KYVENetwork/ksync/utils" "github.com/rs/zerolog" ) -func CometLogger() (logger log.Logger) { - logger = KsyncCometLogger{logger: klogger.LogFormatter("")} - return -} +var ( + engineLogger = EngineLogger{logger: logger.NewLogger(utils.EngineCometBFTV37)} +) -type KsyncCometLogger struct { +type EngineLogger struct { logger zerolog.Logger } -func (l KsyncCometLogger) Debug(msg string, keyvals ...interface{}) {} +func (l EngineLogger) Debug(msg string, keyvals ...interface{}) { + logger := l.logger.Debug() + + for i := 0; i < len(keyvals); i = i + 2 { + logger = logger.Any(fmt.Sprintf("%s", keyvals[i]), keyvals[i+1]) + } + + logger.Msg(msg) +} -func (l KsyncCometLogger) Info(msg string, keyvals ...interface{}) { +func (l EngineLogger) Info(msg string, keyvals ...interface{}) { logger := l.logger.Info() for i := 0; i < len(keyvals); i = i + 2 { if keyvals[i] == "hash" || keyvals[i] == "appHash" { - logger = logger.Str(fmt.Sprintf("%v", keyvals[i]), fmt.Sprintf("%x", keyvals[i+1])) + logger = logger.Str(fmt.Sprintf("%v", keyvals[i]), fmt.Sprintf("%X", keyvals[i+1])) } else { - logger = logger.Str(fmt.Sprintf("%v", keyvals[i]), fmt.Sprintf("%v", keyvals[i+1])) + logger = logger.Any(fmt.Sprintf("%s", keyvals[i]), keyvals[i+1]) } } logger.Msg(msg) } -func (l KsyncCometLogger) Error(msg string, keyvals ...interface{}) { +func (l EngineLogger) Error(msg string, keyvals ...interface{}) { logger := l.logger.Error() for i := 0; i < len(keyvals); i = i + 2 { - logger = logger.Str(fmt.Sprintf("%v", keyvals[i]), fmt.Sprintf("%v", keyvals[i+1])) + logger = logger.Any(fmt.Sprintf("%s", keyvals[i]), keyvals[i+1]) } logger.Msg(msg) } -func (l KsyncCometLogger) With(keyvals ...interface{}) (logger log.Logger) { - logger = KsyncCometLogger{logger: klogger.LogFormatter(keyvals)} - return +func (l EngineLogger) With(keyvals ...interface{}) log.Logger { + return EngineLogger{logger: logger.NewLogger(utils.EngineCometBFTV37, keyvals)} } diff --git a/engines/cometbft-v37/p2p.go b/engines/cometbft-v37/p2p.go index f3b4474..9b198a8 100644 --- a/engines/cometbft-v37/p2p.go +++ b/engines/cometbft-v37/p2p.go @@ -9,7 +9,6 @@ import ( bcproto "github.com/KYVENetwork/cometbft/v37/proto/cometbft/v37/blocksync" sm "github.com/KYVENetwork/cometbft/v37/state" "github.com/KYVENetwork/cometbft/v37/version" - log "github.com/KYVENetwork/ksync/utils" "reflect" ) @@ -17,10 +16,6 @@ const ( BlocksyncChannel = byte(0x40) ) -var ( - logger = log.KsyncLogger("p2p") -) - type BlockchainReactor struct { p2p.BaseReactor @@ -51,7 +46,7 @@ func (bcR *BlockchainReactor) GetChannels() []*p2p.ChannelDescriptor { } func (bcR *BlockchainReactor) sendStatusToPeer(src p2p.Peer) (queued bool) { - logger.Info().Int64("base", bcR.block.Height).Int64("height", bcR.block.Height+1).Msg("Sent status to peer") + bcR.Logger.Info("Sent status to peer", "base", bcR.block.Height, "height", bcR.block.Height+1) return src.SendEnvelope(p2p.Envelope{ ChannelID: BlocksyncChannel, @@ -66,11 +61,11 @@ func (bcR *BlockchainReactor) sendBlockToPeer(msg *bcproto.BlockRequest, src p2p if msg.Height == bcR.block.Height { bl, err := bcR.block.ToProto() if err != nil { - logger.Error().Str("could not convert msg to protobuf", err.Error()) + bcR.Logger.Error("could not convert msg to protobuf", err.Error()) return false } - logger.Info().Msg(fmt.Sprintf("sent block with height %d to peer", bcR.block.Height)) + bcR.Logger.Info(fmt.Sprintf("sent block with height %d to peer", bcR.block.Height)) return src.TrySendEnvelope(p2p.Envelope{ ChannelID: BlocksyncChannel, @@ -81,11 +76,11 @@ func (bcR *BlockchainReactor) sendBlockToPeer(msg *bcproto.BlockRequest, src p2p if msg.Height == bcR.nextBlock.Height { bl, err := bcR.nextBlock.ToProto() if err != nil { - logger.Error().Str("could not convert msg to protobuf", err.Error()) + bcR.Logger.Error("could not convert msg to protobuf", err.Error()) return false } - logger.Info().Msg(fmt.Sprintf("sent block with height %d to peer", bcR.nextBlock.Height)) + bcR.Logger.Info(fmt.Sprintf("sent block with height %d to peer", bcR.nextBlock.Height)) return src.TrySendEnvelope(p2p.Envelope{ ChannelID: BlocksyncChannel, @@ -93,7 +88,7 @@ func (bcR *BlockchainReactor) sendBlockToPeer(msg *bcproto.BlockRequest, src p2p }) } - logger.Error().Msg(fmt.Sprintf("peer asked for different block, expected = %d,%d, requested %d", bcR.block.Height, bcR.nextBlock.Height, msg.Height)) + bcR.Logger.Error(fmt.Sprintf("peer asked for different block, expected = %d,%d, requested %d", bcR.block.Height, bcR.nextBlock.Height, msg.Height)) return false } @@ -106,15 +101,15 @@ func (bcR *BlockchainReactor) ReceiveEnvelope(e p2p.Envelope) { switch msg := e.Message.(type) { case *bcproto.StatusRequest: - logger.Info().Msg("Incoming status request") + bcR.Logger.Info("Incoming status request") bcR.sendStatusToPeer(e.Src) case *bcproto.BlockRequest: - logger.Info().Int64("height", msg.Height).Msg("Incoming block request") + bcR.Logger.Info("Incoming block request", "height", msg.Height) bcR.sendBlockToPeer(msg, e.Src) case *bcproto.StatusResponse: - logger.Info().Int64("base", msg.Base).Int64("height", msg.Height).Msgf("Incoming status response") + bcR.Logger.Info("Incoming status response", "base", msg.Base, "height", msg.Height) default: - logger.Error().Msg(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg))) + bcR.Logger.Error(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg))) } } diff --git a/engines/cometbft-v37/types.go b/engines/cometbft-v37/types.go index 2f4802c..d9bf959 100644 --- a/engines/cometbft-v37/types.go +++ b/engines/cometbft-v37/types.go @@ -4,56 +4,14 @@ import ( abciTypes "github.com/KYVENetwork/cometbft/v37/abci/types" cometCfg "github.com/KYVENetwork/cometbft/v37/config" cometP2P "github.com/KYVENetwork/cometbft/v37/p2p" - cometState "github.com/KYVENetwork/cometbft/v37/state" cometTypes "github.com/KYVENetwork/cometbft/v37/types" ) type Block = cometTypes.Block -type LightBlock = cometTypes.LightBlock type Snapshot = abciTypes.Snapshot type Config = cometCfg.Config type GenesisDoc = cometTypes.GenesisDoc -type TendermintValue struct { - Block struct { - Block *Block `json:"block"` - } `json:"block"` -} - -type TendermintDataItem struct { - Key string `json:"key"` - Value TendermintValue `json:"value"` -} - -type TendermintBsyncDataItem struct { - Key string `json:"key"` - Value *Block `json:"value"` -} - -type TendermintBundle = []TendermintDataItem - -type TendermintBsyncBundle = []TendermintBsyncDataItem - -type TendermintSsyncBundle = []TendermintSsyncDataItem - -type TendermintSsyncDataItem struct { - Key string `json:"key"` - Value struct { - Snapshot *abciTypes.Snapshot `json:"snapshot"` - Block *Block `json:"block"` - SeenCommit *cometTypes.Commit `json:"seenCommit"` - State *cometState.State `json:"state"` - ChunkIndex uint32 `json:"chunkIndex"` - Chunk []byte `json:"chunk"` - } `json:"value"` -} - -type BlockResponse struct { - Result struct { - Block cometTypes.Block `json:"block"` - } `json:"result"` -} - type Transport struct { nodeInfo cometP2P.NodeInfo } diff --git a/engines/cometbft-v38/cometbft.go b/engines/cometbft-v38/cometbft.go index 94fcfb0..a205f8e 100644 --- a/engines/cometbft-v38/cometbft.go +++ b/engines/cometbft-v38/cometbft.go @@ -3,7 +3,6 @@ package cometbft_v38 import ( "context" "fmt" - abciClient "github.com/KYVENetwork/cometbft/v38/abci/client" abciTypes "github.com/KYVENetwork/cometbft/v38/abci/types" cfg "github.com/KYVENetwork/cometbft/v38/config" cs "github.com/KYVENetwork/cometbft/v38/consensus" @@ -14,7 +13,6 @@ import ( cmtos "github.com/KYVENetwork/cometbft/v38/libs/os" "github.com/KYVENetwork/cometbft/v38/mempool" nm "github.com/KYVENetwork/cometbft/v38/node" - "github.com/KYVENetwork/cometbft/v38/p2p" cometP2P "github.com/KYVENetwork/cometbft/v38/p2p" "github.com/KYVENetwork/cometbft/v38/privval" tmProtoState "github.com/KYVENetwork/cometbft/v38/proto/cometbft/v38/state" @@ -23,6 +21,7 @@ import ( rpcserver "github.com/KYVENetwork/cometbft/v38/rpc/jsonrpc/server" tmState "github.com/KYVENetwork/cometbft/v38/state" tmStore "github.com/KYVENetwork/cometbft/v38/store" + cometTypes "github.com/KYVENetwork/cometbft/v38/types" tmTypes "github.com/KYVENetwork/cometbft/v38/types" "github.com/KYVENetwork/ksync/utils" db "github.com/cometbft/cometbft-db" @@ -33,15 +32,10 @@ import ( "time" ) -var ( - cometLogger = CometLogger() -) - type Engine struct { - HomePath string - RpcServerPort int64 - areDBsOpen bool - config *cfg.Config + homePath string + areDBsOpen bool + config *cfg.Config blockDB db.DB blockStore *tmStore.BlockStore @@ -49,17 +43,35 @@ type Engine struct { stateDB db.DB stateStore tmState.Store + evidenceDB db.DB + genDoc *GenesisDoc privValidatorKey crypto.PubKey + nodeKey *cometP2P.NodeKey state tmState.State - prevBlock *Block proxyApp proxy.AppConns mempool *mempool.Mempool evidencePool *evidence.Pool blockExecutor *tmState.BlockExecutor } +func NewEngine(homePath string) (*Engine, error) { + engine := &Engine{ + homePath: homePath, + } + + if err := engine.LoadConfig(); err != nil { + return nil, err + } + + if err := engine.OpenDBs(); err != nil { + return nil, err + } + + return engine, nil +} + func (engine *Engine) GetName() string { return utils.EngineCometBFTV38 } @@ -69,32 +81,18 @@ func (engine *Engine) LoadConfig() error { return nil } - config, err := LoadConfig(engine.HomePath) + config, err := LoadConfig(engine.homePath) if err != nil { return fmt.Errorf("failed to load config.toml: %w", err) } engine.config = config - return nil -} - -func (engine *Engine) OpenDBs() error { - if engine.areDBsOpen { - return nil - } - - if err := engine.LoadConfig(); err != nil { - return err - } - - if err := utils.FormatGenesisFile(engine.config.GenesisFile()); err != nil { - return fmt.Errorf("failed to format genesis file: %w", err) - } genDoc, err := nm.DefaultGenesisDocProviderFunc(engine.config)() if err != nil { return fmt.Errorf("failed to load state and genDoc: %w", err) } + engine.genDoc = genDoc privValidatorKey, err := privval.LoadFilePVEmptyState( @@ -106,6 +104,21 @@ func (engine *Engine) OpenDBs() error { } engine.privValidatorKey = privValidatorKey + nodeKey, err := cometP2P.LoadNodeKey(engine.config.NodeKeyFile()) + if err != nil { + return fmt.Errorf("loading node key file failed: %w", err) + } + engine.nodeKey = nodeKey + + engineLogger.Debug("loaded config", "configPath", fmt.Sprintf("%s/config.toml", engine.homePath)) + return nil +} + +func (engine *Engine) OpenDBs() error { + if engine.areDBsOpen { + return nil + } + blockDB, blockStore, err := GetBlockstoreDBs(engine.config) if err != nil { return fmt.Errorf("failed to open blockDB: %w", err) @@ -122,7 +135,23 @@ func (engine *Engine) OpenDBs() error { engine.stateDB = stateDB engine.stateStore = stateStore + evidenceDB, err := DefaultDBProvider(&DBContext{ID: "evidence", Config: engine.config}) + if err != nil { + return fmt.Errorf("failed to open evidenceDB: %w", err) + } + + engine.evidenceDB = evidenceDB + engine.areDBsOpen = true + engineLogger.Debug( + "opened dbs", + "blockDB", + fmt.Sprintf("%s/%s/blockstore.db", engine.homePath, engine.config.DBPath), + "stateDB", + fmt.Sprintf("%s/%s/state.db", engine.homePath, engine.config.DBPath), + "evidenceDB", + fmt.Sprintf("%s/%s/evidence.db", engine.homePath, engine.config.DBPath), + ) return nil } @@ -139,12 +168,25 @@ func (engine *Engine) CloseDBs() error { return fmt.Errorf("failed to close stateDB: %w", err) } + if err := engine.evidenceDB.Close(); err != nil { + return fmt.Errorf("failed to close evidenceDB: %w", err) + } + engine.areDBsOpen = false + engineLogger.Debug( + "closed dbs", + "blockDB", + fmt.Sprintf("%s/%s/blockstore.db", engine.homePath, engine.config.DBPath), + "stateDB", + fmt.Sprintf("%s/%s/state.db", engine.homePath, engine.config.DBPath), + "evidenceDB", + fmt.Sprintf("%s/%s/evidence.db", engine.homePath, engine.config.DBPath), + ) return nil } -func (engine *Engine) GetHomePath() string { - return engine.HomePath +func (engine *Engine) GetRpcListenAddress() string { + return engine.config.RPC.ListenAddress } func (engine *Engine) GetProxyAppAddress() string { @@ -156,12 +198,12 @@ func (engine *Engine) StartProxyApp() error { return fmt.Errorf("proxy app already started") } - proxyApp, err := CreateAndStartProxyAppConns(engine.config) - if err != nil { - return err + engine.proxyApp = proxy.NewAppConns(proxy.NewRemoteClientCreator(engine.config.ProxyApp, engine.config.ABCI, false), proxy.NopMetrics()) + if err := engine.proxyApp.Start(); err != nil { + return fmt.Errorf("failed to start proxy app: %w", err) } - engine.proxyApp = proxyApp + engineLogger.Debug("started proxy app connections", "address", engine.GetProxyAppAddress()) return nil } @@ -175,39 +217,10 @@ func (engine *Engine) StopProxyApp() error { } engine.proxyApp = nil + engineLogger.Debug("stopped proxy app connections", "address", engine.GetProxyAppAddress()) return nil } -func (engine *Engine) GetChainId() (string, error) { - if err := engine.LoadConfig(); err != nil { - return "", fmt.Errorf("failed to load config: %w", err) - } - - genDoc, err := nm.DefaultGenesisDocProviderFunc(engine.config)() - if err != nil { - return "", fmt.Errorf("failed to load genDoc: %w", err) - } - - return genDoc.ChainID, nil -} - -func (engine *Engine) GetContinuationHeight() (int64, error) { - height := engine.GetHeight() - - initialHeight, err := utils.GetInitialHeightFromGenesisFile(engine.GetGenesisPath()) - if err != nil { - return 0, fmt.Errorf("failed to load initial height from genesis file: %w", err) - } - - continuationHeight := height + 1 - - if continuationHeight < initialHeight { - continuationHeight = initialHeight - } - - return continuationHeight, nil -} - func (engine *Engine) DoHandshake() error { state, err := tmState.NewStore(engine.stateDB, tmState.StoreOptions{ DiscardABCIResponses: false, @@ -216,13 +229,17 @@ func (engine *Engine) DoHandshake() error { return fmt.Errorf("failed to load state from genDoc: %w", err) } - eventBus, err := CreateAndStartEventBus() - if err != nil { + eventBus := cometTypes.NewEventBus() + eventBus.SetLogger(engineLogger.With("module", "events")) + if err := eventBus.Start(); err != nil { return fmt.Errorf("failed to start event bus: %w", err) } - if err := DoHandshake(engine.stateStore, state, engine.blockStore, engine.genDoc, eventBus, engine.proxyApp); err != nil { - return fmt.Errorf("failed to do handshake: %w", err) + handshaker := cs.NewHandshaker(engine.stateStore, state, engine.blockStore, engine.genDoc) + handshaker.SetLogger(engineLogger.With("module", "consensus")) + handshaker.SetEventBus(eventBus) + if err := handshaker.Handshake(engine.proxyApp); err != nil { + return fmt.Errorf("error during handshake: %v", err) } state, err = engine.stateStore.Load() @@ -232,20 +249,20 @@ func (engine *Engine) DoHandshake() error { engine.state = state - mempool := CreateMempool(engine.config, engine.proxyApp, state) + mp := CreateMempool(engine.config, engine.proxyApp, state) - _, evidencePool, err := CreateEvidenceReactor(engine.config, engine.stateStore, engine.blockStore) + evidencePool, err := evidence.NewPool(engine.evidenceDB, engine.stateStore, engine.blockStore) if err != nil { - return fmt.Errorf("failed to create evidence reactor: %w", err) + return fmt.Errorf("failed to create evidence pool: %w", err) } - engine.mempool = &mempool + engine.mempool = &mp engine.evidencePool = evidencePool engine.blockExecutor = tmState.NewBlockExecutor( engine.stateStore, - cometLogger.With("module", "state"), + engineLogger.With("module", "state"), engine.proxyApp.Consensus(), - mempool, + mp, evidencePool, engine.blockStore, ) @@ -253,99 +270,58 @@ func (engine *Engine) DoHandshake() error { return nil } -func (engine *Engine) ApplyBlock(runtime *string, value []byte) error { - var block *Block - - if runtime == nil { - // if runtime is nil we sync from another cometbft node - var blockResponse BlockResponse - err := json.Unmarshal(value, &blockResponse) - if err != nil { - return fmt.Errorf("failed to unmarshal block response: %w", err) - } - block = &blockResponse.Result.Block - } else if *runtime == utils.KSyncRuntimeTendermint { - var parsed TendermintValue - - if err := json.Unmarshal(value, &parsed); err != nil { - return fmt.Errorf("failed to unmarshal value: %w", err) - } +func (engine *Engine) ApplyBlock(rawBlock, nextRawBlock []byte) error { + var block, nextBlock *Block - block = parsed.Block.Block - } else if *runtime == utils.KSyncRuntimeTendermintBsync { - if err := json.Unmarshal(value, &block); err != nil { - return fmt.Errorf("failed to unmarshal value: %w", err) - } - } else { - return fmt.Errorf("runtime %s unknown", runtime) + if err := json.Unmarshal(rawBlock, &block); err != nil { + return fmt.Errorf("failed to unmarshal block: %w", err) } - // if the previous block is not defined we continue - if engine.prevBlock == nil { - engine.prevBlock = block - return nil + if err := json.Unmarshal(nextRawBlock, &nextBlock); err != nil { + return fmt.Errorf("failed to unmarshal next block: %w", err) } // get block data - blockParts, err := engine.prevBlock.MakePartSet(tmTypes.BlockPartSizeBytes) + blockParts, err := block.MakePartSet(tmTypes.BlockPartSizeBytes) if err != nil { return fmt.Errorf("failed make part set of block: %w", err) } - blockId := tmTypes.BlockID{Hash: engine.prevBlock.Hash(), PartSetHeader: blockParts.Header()} + blockId := tmTypes.BlockID{Hash: block.Hash(), PartSetHeader: blockParts.Header()} // verify block - if err := engine.blockExecutor.ValidateBlock(engine.state, engine.prevBlock); err != nil { - return fmt.Errorf("block validation failed at height %d: %w", engine.prevBlock.Height, err) + if err := engine.blockExecutor.ValidateBlock(engine.state, block); err != nil { + return fmt.Errorf("block validation failed at height %d: %w", block.Height, err) } // verify commits - if err := engine.state.Validators.VerifyCommitLight(engine.state.ChainID, blockId, engine.prevBlock.Height, block.LastCommit); err != nil { - return fmt.Errorf("light commit verification failed at height %d: %w", engine.prevBlock.Height, err) + if err := engine.state.Validators.VerifyCommitLight(engine.state.ChainID, blockId, block.Height, nextBlock.LastCommit); err != nil { + return fmt.Errorf("light commit verification failed at height %d: %w", block.Height, err) } // store block - engine.blockStore.SaveBlock(engine.prevBlock, blockParts, block.LastCommit) + engine.blockStore.SaveBlock(block, blockParts, nextBlock.LastCommit) // execute block against app - state, err := engine.blockExecutor.ApplyBlock(engine.state, blockId, engine.prevBlock) + state, err := engine.blockExecutor.ApplyBlock(engine.state, blockId, block) if err != nil { - return fmt.Errorf("failed to apply block at height %d: %w", engine.prevBlock.Height, err) + return fmt.Errorf("failed to apply block at height %d: %w", block.Height, err) } - // update values for next round + // update state for next round engine.state = state - engine.prevBlock = block - return nil } -func (engine *Engine) ApplyFirstBlockOverP2P(runtime string, value, nextValue []byte) error { +func (engine *Engine) ApplyFirstBlockOverP2P(rawBlock, nextRawBlock []byte) error { var block, nextBlock *Block - if runtime == utils.KSyncRuntimeTendermint { - var parsed, nextParsed TendermintValue - - if err := json.Unmarshal(value, &parsed); err != nil { - return fmt.Errorf("failed to unmarshal value: %w", err) - } - - if err := json.Unmarshal(nextValue, &nextParsed); err != nil { - return fmt.Errorf("failed to unmarshal next value: %w", err) - } - - block = parsed.Block.Block - nextBlock = nextParsed.Block.Block - } else if runtime == utils.KSyncRuntimeTendermintBsync { - if err := json.Unmarshal(value, &block); err != nil { - return fmt.Errorf("failed to unmarshal value: %w", err) - } + if err := json.Unmarshal(rawBlock, &block); err != nil { + return fmt.Errorf("failed to unmarshal block: %w", err) + } - if err := json.Unmarshal(nextValue, &nextBlock); err != nil { - return fmt.Errorf("failed to unmarshal next value: %w", err) - } - } else { - return fmt.Errorf("runtime %s unknown", runtime) + if err := json.Unmarshal(nextRawBlock, &nextBlock); err != nil { + return fmt.Errorf("failed to unmarshal next block: %w", err) } genDoc, err := nm.DefaultGenesisDocProviderFunc(engine.config)() @@ -380,7 +356,7 @@ func (engine *Engine) ApplyFirstBlockOverP2P(runtime string, value, nextValue [] nodeInfo, err := MakeNodeInfo(engine.config, ksyncNodeKey, genDoc) transport := cometP2P.NewMultiplexTransport(nodeInfo, *ksyncNodeKey, cometP2P.MConnConfig(engine.config.P2P)) bcR := NewBlockchainReactor(block, nextBlock) - sw := CreateSwitch(engine.config, transport, bcR, nodeInfo, ksyncNodeKey, cometLogger) + sw := CreateSwitch(engine.config, transport, bcR, nodeInfo, ksyncNodeKey, engineLogger) // start the transport addr, err := cometP2P.NewNetAddressString(cometP2P.IDAddressString(ksyncNodeKey.ID(), engine.config.P2P.ListenAddress)) @@ -417,20 +393,6 @@ func (engine *Engine) ApplyFirstBlockOverP2P(runtime string, value, nextValue [] return nil } -func (engine *Engine) GetGenesisPath() string { - return engine.config.GenesisFile() -} - -func (engine *Engine) GetGenesisHeight() (int64, error) { - defaultDocProvider := nm.DefaultGenesisDocProviderFunc(engine.config) - genDoc, err := defaultDocProvider() - if err != nil { - return 0, err - } - - return genDoc.InitialHeight, nil -} - func (engine *Engine) GetHeight() int64 { height := engine.blockStore.Height() if height == 0 { @@ -445,40 +407,20 @@ func (engine *Engine) GetBaseHeight() int64 { } func (engine *Engine) GetAppHeight() (int64, error) { - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) - - if err := socketClient.Start(); err != nil { - return 0, fmt.Errorf("failed to start socket client: %w", err) - } - - info, err := socketClient.Info(context.Background(), &abciTypes.RequestInfo{}) + info, err := engine.proxyApp.Query().Info(context.Background(), &abciTypes.RequestInfo{}) if err != nil { return 0, fmt.Errorf("failed to query info: %w", err) } - if err := socketClient.Stop(); err != nil { - return 0, fmt.Errorf("failed to stop socket client: %w", err) - } - return info.LastBlockHeight, nil } func (engine *Engine) GetSnapshots() ([]byte, error) { - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) - - if err := socketClient.Start(); err != nil { - return nil, fmt.Errorf("failed to start socket client: %w", err) - } - - res, err := socketClient.ListSnapshots(context.Background(), &abciTypes.RequestListSnapshots{}) + res, err := engine.proxyApp.Snapshot().ListSnapshots(context.Background(), &abciTypes.RequestListSnapshots{}) if err != nil { return nil, fmt.Errorf("failed to list snapshots: %w", err) } - if err := socketClient.Stop(); err != nil { - return nil, fmt.Errorf("failed to stop socket client: %w", err) - } - if len(res.Snapshots) == 0 { return json.Marshal([]Snapshot{}) } @@ -487,21 +429,11 @@ func (engine *Engine) GetSnapshots() ([]byte, error) { } func (engine *Engine) IsSnapshotAvailable(height int64) (bool, error) { - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) - - if err := socketClient.Start(); err != nil { - return false, fmt.Errorf("failed to start socket client: %w", err) - } - - res, err := socketClient.ListSnapshots(context.Background(), &abciTypes.RequestListSnapshots{}) + res, err := engine.proxyApp.Snapshot().ListSnapshots(context.Background(), &abciTypes.RequestListSnapshots{}) if err != nil { return false, fmt.Errorf("failed to list snapshots: %w", err) } - if err := socketClient.Stop(); err != nil { - return false, fmt.Errorf("failed to stop socket client: %w", err) - } - for _, snapshot := range res.Snapshots { if snapshot.Height == uint64(height) { return true, nil @@ -512,13 +444,7 @@ func (engine *Engine) IsSnapshotAvailable(height int64) (bool, error) { } func (engine *Engine) GetSnapshotChunk(height, format, chunk int64) ([]byte, error) { - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) - - if err := socketClient.Start(); err != nil { - return nil, fmt.Errorf("failed to start socket client: %w", err) - } - - res, err := socketClient.LoadSnapshotChunk(context.Background(), &abciTypes.RequestLoadSnapshotChunk{ + res, err := engine.proxyApp.Snapshot().LoadSnapshotChunk(context.Background(), &abciTypes.RequestLoadSnapshotChunk{ Height: uint64(height), Format: uint32(format), Chunk: uint32(chunk), @@ -527,10 +453,6 @@ func (engine *Engine) GetSnapshotChunk(height, format, chunk int64) ([]byte, err return nil, fmt.Errorf("failed to load snapshot chunk: %w", err) } - if err := socketClient.Stop(); err != nil { - return nil, fmt.Errorf("failed to stop socket client: %w", err) - } - return json.Marshal(res.Chunk) } @@ -539,13 +461,13 @@ func (engine *Engine) GetBlock(height int64) ([]byte, error) { return json.Marshal(block) } -func (engine *Engine) StartRPCServer() { +func (engine *Engine) StartRPCServer(port int64) { // wait until all reactors have been booted for engine.blockExecutor == nil { time.Sleep(1000) } - rpcLogger := cometLogger.With("module", "rpc-server") + rpcLogger := engineLogger.With("module", "rpc-server") consensusReactor := cs.NewReactor(cs.NewState( engine.config.Consensus, @@ -558,12 +480,12 @@ func (engine *Engine) StartRPCServer() { nodeKey, err := cometP2P.LoadNodeKey(engine.config.NodeKeyFile()) if err != nil { - cometLogger.Error(fmt.Sprintf("failed to get nodeKey: %s", err)) + engineLogger.Error(fmt.Sprintf("failed to get nodeKey: %s", err)) return } nodeInfo, err := MakeNodeInfo(engine.config, nodeKey, engine.genDoc) if err != nil { - cometLogger.Error(fmt.Sprintf("failed to get nodeInfo: %s", err)) + engineLogger.Error(fmt.Sprintf("failed to get nodeInfo: %s", err)) return } @@ -597,14 +519,14 @@ func (engine *Engine) StartRPCServer() { config := rpcserver.DefaultConfig() rpcserver.RegisterRPCFuncs(mux, routes, rpcLogger) - listener, err := rpcserver.Listen(fmt.Sprintf("tcp://127.0.0.1:%d", engine.RpcServerPort), 10) + listener, err := rpcserver.Listen(fmt.Sprintf("tcp://127.0.0.1:%d", port), 10) if err != nil { - cometLogger.Error(fmt.Sprintf("failed to get rpc listener: %s", err)) + engineLogger.Error(fmt.Sprintf("failed to get rpc listener: %s", err)) return } if err := rpcserver.Serve(listener, mux, rpcLogger, config); err != nil { - cometLogger.Error(fmt.Sprintf("failed to start rpc server: %s", err)) + engineLogger.Error(fmt.Sprintf("failed to start rpc server: %s", err)) return } } @@ -666,86 +588,73 @@ func (engine *Engine) GetSeenCommit(height int64) ([]byte, error) { return json.Marshal(block.LastCommit) } -func (engine *Engine) OfferSnapshot(value []byte) (string, uint32, error) { - var bundle TendermintSsyncBundle +func (engine *Engine) OfferSnapshot(rawSnapshot, rawState []byte) error { + var snapshot *abciTypes.Snapshot - if err := json.Unmarshal(value, &bundle); err != nil { - return abciTypes.ResponseOfferSnapshot_UNKNOWN.String(), 0, fmt.Errorf("failed to unmarshal tendermint-ssync bundle: %w", err) + if err := json.Unmarshal(rawSnapshot, &snapshot); err != nil { + return fmt.Errorf("failed to unmarshal snapshot: %w", err) } - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) + var state *tmState.State - if err := socketClient.Start(); err != nil { - return abciTypes.ResponseOfferSnapshot_UNKNOWN.String(), 0, fmt.Errorf("failed to start socket client: %w", err) + if err := json.Unmarshal(rawState, &state); err != nil { + return fmt.Errorf("failed to unmarshal state: %w", err) } - res, err := socketClient.OfferSnapshot(context.Background(), &abciTypes.RequestOfferSnapshot{ - Snapshot: bundle[0].Value.Snapshot, - AppHash: bundle[0].Value.State.AppHash, + res, err := engine.proxyApp.Snapshot().OfferSnapshot(context.Background(), &abciTypes.RequestOfferSnapshot{ + Snapshot: snapshot, + AppHash: state.AppHash, }) - if err != nil { - return abciTypes.ResponseOfferSnapshot_UNKNOWN.String(), 0, err + return err } - if err := socketClient.Stop(); err != nil { - return abciTypes.ResponseOfferSnapshot_UNKNOWN.String(), 0, fmt.Errorf("failed to stop socket client: %w", err) + if res.Result.String() != abciTypes.ResponseOfferSnapshot_ACCEPT.String() { + return fmt.Errorf(res.Result.String()) } - return res.Result.String(), bundle[0].Value.Snapshot.Chunks, nil + return nil } -func (engine *Engine) ApplySnapshotChunk(chunkIndex uint32, value []byte) (string, error) { - var bundle TendermintSsyncBundle - - if err := json.Unmarshal(value, &bundle); err != nil { - return abciTypes.ResponseApplySnapshotChunk_UNKNOWN.String(), fmt.Errorf("failed to unmarshal tendermint-ssync bundle: %w", err) - } - - nodeKey, err := p2p.LoadNodeKey(engine.config.NodeKeyFile()) +func (engine *Engine) ApplySnapshotChunk(chunkIndex int64, chunk []byte) error { + res, err := engine.proxyApp.Snapshot().ApplySnapshotChunk(context.Background(), &abciTypes.RequestApplySnapshotChunk{ + Index: uint32(chunkIndex), + Chunk: chunk, + Sender: string(engine.nodeKey.ID()), + }) if err != nil { - return abciTypes.ResponseApplySnapshotChunk_UNKNOWN.String(), fmt.Errorf("loading node key file failed: %w", err) + return err } - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) - - if err := socketClient.Start(); err != nil { - return abciTypes.ResponseApplySnapshotChunk_UNKNOWN.String(), fmt.Errorf("failed to start socket client: %w", err) + if res.Result.String() != abciTypes.ResponseApplySnapshotChunk_ACCEPT.String() { + return fmt.Errorf(res.Result.String()) } - res, err := socketClient.ApplySnapshotChunk(context.Background(), &abciTypes.RequestApplySnapshotChunk{ - Index: chunkIndex, - Chunk: bundle[0].Value.Chunk, - Sender: string(nodeKey.ID()), - }) + return nil +} - if err != nil { - return abciTypes.ResponseApplySnapshotChunk_UNKNOWN.String(), err - } +func (engine *Engine) BootstrapState(rawState, rawSeenCommit, _ []byte) error { + var state *tmState.State - if err := socketClient.Stop(); err != nil { - return abciTypes.ResponseApplySnapshotChunk_UNKNOWN.String(), fmt.Errorf("failed to stop socket client: %w", err) + if err := json.Unmarshal(rawState, &state); err != nil { + return fmt.Errorf("failed to unmarshal state: %w", err) } - return res.Result.String(), nil -} - -func (engine *Engine) BootstrapState(value []byte) error { - var bundle TendermintSsyncBundle + var seenCommit *tmTypes.Commit - if err := json.Unmarshal(value, &bundle); err != nil { - return fmt.Errorf("failed to unmarshal tendermint-ssync bundle: %w", err) + if err := json.Unmarshal(rawSeenCommit, &seenCommit); err != nil { + return fmt.Errorf("failed to unmarshal seen commit: %w", err) } - if err := engine.stateStore.Bootstrap(*bundle[0].Value.State); err != nil { + if err := engine.stateStore.Bootstrap(*state); err != nil { return fmt.Errorf("failed to bootstrap state: %w", err) } - if err := engine.blockStore.SaveSeenCommit(bundle[0].Value.State.LastBlockHeight, bundle[0].Value.SeenCommit); err != nil { + if err := engine.blockStore.SaveSeenCommit(state.LastBlockHeight, seenCommit); err != nil { return fmt.Errorf("failed to save seen commit: %w", err) } - if err := engine.stateStore.SetOfflineStateSyncHeight(bundle[0].Value.State.LastBlockHeight); err != nil { + if err := engine.stateStore.SetOfflineStateSyncHeight(state.LastBlockHeight); err != nil { return fmt.Errorf("failed to set offline state sync height: %w", err) } @@ -770,28 +679,23 @@ func (engine *Engine) PruneBlocks(toHeight int64) error { } func (engine *Engine) ResetAll(keepAddrBook bool) error { - config, err := LoadConfig(engine.HomePath) - if err != nil { - return fmt.Errorf("failed to load config.toml: %w", err) - } - - dbDir := config.DBDir() - addrBookFile := config.P2P.AddrBookFile() - privValKeyFile := config.PrivValidatorKeyFile() - privValStateFile := config.PrivValidatorStateFile() + dbDir := engine.config.DBDir() + addrBookFile := engine.config.P2P.AddrBookFile() + privValKeyFile := engine.config.PrivValidatorKeyFile() + privValStateFile := engine.config.PrivValidatorStateFile() if keepAddrBook { - cometLogger.Info("the address book remains intact") + engineLogger.Info("the address book remains intact") } else { if err := os.Remove(addrBookFile); err == nil { - cometLogger.Info("removed existing address book", "file", addrBookFile) + engineLogger.Info("removed existing address book", "file", addrBookFile) } else if !os.IsNotExist(err) { return fmt.Errorf("error removing address book, file: %s, err: %w", addrBookFile, err) } } if err := os.RemoveAll(dbDir); err == nil { - cometLogger.Info("removed all blockchain history", "dir", dbDir) + engineLogger.Info("removed all blockchain history", "dir", dbDir) } else { return fmt.Errorf("error removing all blockchain history, dir: %s, err: %w", dbDir, err) } @@ -804,7 +708,7 @@ func (engine *Engine) ResetAll(keepAddrBook bool) error { if _, err := os.Stat(privValKeyFile); err == nil { pv := privval.LoadFilePVEmptyState(privValKeyFile, privValStateFile) pv.Reset() - cometLogger.Info( + engineLogger.Info( "Reset private validator file to genesis state", "keyFile", privValKeyFile, "stateFile", privValStateFile, @@ -812,12 +716,20 @@ func (engine *Engine) ResetAll(keepAddrBook bool) error { } else { pv := privval.GenFilePV(privValKeyFile, privValStateFile) pv.Save() - cometLogger.Info( + engineLogger.Info( "Generated private validator file", "keyFile", privValKeyFile, "stateFile", privValStateFile, ) } + if err := engine.CloseDBs(); err != nil { + return fmt.Errorf("failed to close dbs: %w", err) + } + + if err := engine.OpenDBs(); err != nil { + return fmt.Errorf("failed to open dbs: %w", err) + } + return nil } diff --git a/engines/cometbft-v38/helpers.go b/engines/cometbft-v38/helpers.go index 5be40bb..8f12ddb 100644 --- a/engines/cometbft-v38/helpers.go +++ b/engines/cometbft-v38/helpers.go @@ -1,16 +1,12 @@ package cometbft_v38 import ( - "fmt" cfg "github.com/KYVENetwork/cometbft/v38/config" - cs "github.com/KYVENetwork/cometbft/v38/consensus" - "github.com/KYVENetwork/cometbft/v38/evidence" mempl "github.com/KYVENetwork/cometbft/v38/mempool" "github.com/KYVENetwork/cometbft/v38/proxy" "github.com/KYVENetwork/cometbft/v38/state" sm "github.com/KYVENetwork/cometbft/v38/state" "github.com/KYVENetwork/cometbft/v38/store" - cometTypes "github.com/KYVENetwork/cometbft/v38/types" dbm "github.com/cometbft/cometbft-db" "github.com/spf13/viper" "path/filepath" @@ -71,43 +67,8 @@ func GetBlockstoreDBs(config *Config) (dbm.DB, *store.BlockStore, error) { return blockStoreDB, blockStore, nil } -func CreateAndStartProxyAppConns(config *Config) (proxy.AppConns, error) { - proxyApp := proxy.NewAppConns(proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()), proxy.NopMetrics()) - proxyApp.SetLogger(cometLogger.With("module", "proxy")) - if err := proxyApp.Start(); err != nil { - return nil, fmt.Errorf("error starting proxy app connections: %v", err) - } - return proxyApp, nil -} - -func CreateAndStartEventBus() (*cometTypes.EventBus, error) { - eventBus := cometTypes.NewEventBus() - eventBus.SetLogger(cometLogger.With("module", "events")) - if err := eventBus.Start(); err != nil { - return nil, err - } - return eventBus, nil -} - -func DoHandshake( - stateStore sm.Store, - state sm.State, - blockStore sm.BlockStore, - genDoc *GenesisDoc, - eventBus cometTypes.BlockEventPublisher, - proxyApp proxy.AppConns, -) error { - handshaker := cs.NewHandshaker(stateStore, state, blockStore, genDoc) - handshaker.SetLogger(cometLogger.With("module", "consensus")) - handshaker.SetEventBus(eventBus) - if err := handshaker.Handshake(proxyApp); err != nil { - return fmt.Errorf("error during handshake: %v", err) - } - return nil -} - func CreateMempool(config *Config, proxyApp proxy.AppConns, state sm.State) mempl.Mempool { - logger := cometLogger.With("module", "mempool") + logger := engineLogger.With("module", "mempool") mp := mempl.NewCListMempool( config.Mempool, proxyApp.Mempool(), @@ -124,18 +85,3 @@ func CreateMempool(config *Config, proxyApp proxy.AppConns, state sm.State) memp return mp } - -func CreateEvidenceReactor(config *Config, stateStore sm.Store, blockStore *store.BlockStore) (*evidence.Reactor, *evidence.Pool, error) { - evidenceDB, err := DefaultDBProvider(&DBContext{ID: "evidence", Config: config}) - if err != nil { - return nil, nil, err - } - evidenceLogger := cometLogger.With("module", "evidence") - evidencePool, err := evidence.NewPool(evidenceDB, stateStore, blockStore) - if err != nil { - return nil, nil, err - } - evidenceReactor := evidence.NewReactor(evidencePool) - evidenceReactor.SetLogger(evidenceLogger) - return evidenceReactor, evidencePool, nil -} diff --git a/engines/cometbft-v38/logger.go b/engines/cometbft-v38/logger.go index be322ca..56e0070 100644 --- a/engines/cometbft-v38/logger.go +++ b/engines/cometbft-v38/logger.go @@ -3,46 +3,53 @@ package cometbft_v38 import ( "fmt" "github.com/KYVENetwork/cometbft/v38/libs/log" - klogger "github.com/KYVENetwork/ksync/utils" + "github.com/KYVENetwork/ksync/logger" + "github.com/KYVENetwork/ksync/utils" "github.com/rs/zerolog" ) -func CometLogger() (logger log.Logger) { - logger = KsyncCometLogger{logger: klogger.LogFormatter("")} - return -} +var ( + engineLogger = EngineLogger{logger: logger.NewLogger(utils.EngineCometBFTV38)} +) -type KsyncCometLogger struct { +type EngineLogger struct { logger zerolog.Logger } -func (l KsyncCometLogger) Debug(msg string, keyvals ...interface{}) {} +func (l EngineLogger) Debug(msg string, keyvals ...interface{}) { + logger := l.logger.Debug() + + for i := 0; i < len(keyvals); i = i + 2 { + logger = logger.Any(fmt.Sprintf("%s", keyvals[i]), keyvals[i+1]) + } + + logger.Msg(msg) +} -func (l KsyncCometLogger) Info(msg string, keyvals ...interface{}) { +func (l EngineLogger) Info(msg string, keyvals ...interface{}) { logger := l.logger.Info() for i := 0; i < len(keyvals); i = i + 2 { if keyvals[i] == "hash" || keyvals[i] == "appHash" { - logger = logger.Str(fmt.Sprintf("%v", keyvals[i]), fmt.Sprintf("%x", keyvals[i+1])) + logger = logger.Str(fmt.Sprintf("%v", keyvals[i]), fmt.Sprintf("%s", keyvals[i+1])) } else { - logger = logger.Str(fmt.Sprintf("%v", keyvals[i]), fmt.Sprintf("%v", keyvals[i+1])) + logger = logger.Any(fmt.Sprintf("%s", keyvals[i]), keyvals[i+1]) } } logger.Msg(msg) } -func (l KsyncCometLogger) Error(msg string, keyvals ...interface{}) { +func (l EngineLogger) Error(msg string, keyvals ...interface{}) { logger := l.logger.Error() for i := 0; i < len(keyvals); i = i + 2 { - logger = logger.Str(fmt.Sprintf("%v", keyvals[i]), fmt.Sprintf("%v", keyvals[i+1])) + logger = logger.Any(fmt.Sprintf("%s", keyvals[i]), keyvals[i+1]) } logger.Msg(msg) } -func (l KsyncCometLogger) With(keyvals ...interface{}) (logger log.Logger) { - logger = KsyncCometLogger{logger: klogger.LogFormatter(keyvals)} - return +func (l EngineLogger) With(keyvals ...interface{}) log.Logger { + return EngineLogger{logger: logger.NewLogger(utils.EngineCometBFTV38, keyvals)} } diff --git a/engines/cometbft-v38/p2p.go b/engines/cometbft-v38/p2p.go index f56a4f3..91cb743 100644 --- a/engines/cometbft-v38/p2p.go +++ b/engines/cometbft-v38/p2p.go @@ -9,7 +9,6 @@ import ( bcproto "github.com/KYVENetwork/cometbft/v38/proto/cometbft/v38/blocksync" sm "github.com/KYVENetwork/cometbft/v38/state" "github.com/KYVENetwork/cometbft/v38/version" - log "github.com/KYVENetwork/ksync/utils" "reflect" ) @@ -17,10 +16,6 @@ const ( BlocksyncChannel = byte(0x40) ) -var ( - logger = log.KsyncLogger("p2p") -) - type BlockchainReactor struct { p2p.BaseReactor @@ -51,7 +46,7 @@ func (bcR *BlockchainReactor) GetChannels() []*p2p.ChannelDescriptor { } func (bcR *BlockchainReactor) sendStatusToPeer(src p2p.Peer) (queued bool) { - logger.Info().Int64("base", bcR.block.Height).Int64("height", bcR.block.Height+1).Msg("Sent status to peer") + bcR.Logger.Info("Sent status to peer", "base", bcR.block.Height, "height", bcR.block.Height+1) return src.Send(p2p.Envelope{ ChannelID: BlocksyncChannel, @@ -66,11 +61,11 @@ func (bcR *BlockchainReactor) sendBlockToPeer(msg *bcproto.BlockRequest, src p2p if msg.Height == bcR.block.Height { bl, err := bcR.block.ToProto() if err != nil { - logger.Error().Str("could not convert msg to protobuf", err.Error()) + bcR.Logger.Error("could not convert msg to protobuf", err.Error()) return false } - logger.Info().Msg(fmt.Sprintf("sent block with height %d to peer", bcR.block.Height)) + bcR.Logger.Info(fmt.Sprintf("sent block with height %d to peer", bcR.block.Height)) return src.TrySend(p2p.Envelope{ ChannelID: BlocksyncChannel, @@ -81,11 +76,11 @@ func (bcR *BlockchainReactor) sendBlockToPeer(msg *bcproto.BlockRequest, src p2p if msg.Height == bcR.nextBlock.Height { bl, err := bcR.nextBlock.ToProto() if err != nil { - logger.Error().Str("could not convert msg to protobuf", err.Error()) + bcR.Logger.Error("could not convert msg to protobuf", err.Error()) return false } - logger.Info().Msg(fmt.Sprintf("sent block with height %d to peer", bcR.nextBlock.Height)) + bcR.Logger.Info(fmt.Sprintf("sent block with height %d to peer", bcR.nextBlock.Height)) return src.TrySend(p2p.Envelope{ ChannelID: BlocksyncChannel, @@ -93,7 +88,7 @@ func (bcR *BlockchainReactor) sendBlockToPeer(msg *bcproto.BlockRequest, src p2p }) } - logger.Error().Msg(fmt.Sprintf("peer asked for different block, expected = %d,%d, requested %d", bcR.block.Height, bcR.nextBlock.Height, msg.Height)) + bcR.Logger.Error(fmt.Sprintf("peer asked for different block, expected = %d,%d, requested %d", bcR.block.Height, bcR.nextBlock.Height, msg.Height)) return false } @@ -106,15 +101,15 @@ func (bcR *BlockchainReactor) ReceiveEnvelope(e p2p.Envelope) { switch msg := e.Message.(type) { case *bcproto.StatusRequest: - logger.Info().Msg("Incoming status request") + bcR.Logger.Info("Incoming status request") bcR.sendStatusToPeer(e.Src) case *bcproto.BlockRequest: - logger.Info().Int64("height", msg.Height).Msg("Incoming block request") + bcR.Logger.Info("Incoming block request", "height", msg.Height) bcR.sendBlockToPeer(msg, e.Src) case *bcproto.StatusResponse: - logger.Info().Int64("base", msg.Base).Int64("height", msg.Height).Msgf("Incoming status response") + bcR.Logger.Info("Incoming status response", "base", msg.Base, "height", msg.Height) default: - logger.Error().Msg(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg))) + bcR.Logger.Error(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg))) } } diff --git a/engines/cometbft-v38/types.go b/engines/cometbft-v38/types.go index da75a75..1fa9132 100644 --- a/engines/cometbft-v38/types.go +++ b/engines/cometbft-v38/types.go @@ -4,56 +4,14 @@ import ( abciTypes "github.com/KYVENetwork/cometbft/v38/abci/types" cometCfg "github.com/KYVENetwork/cometbft/v38/config" cometP2P "github.com/KYVENetwork/cometbft/v38/p2p" - cometState "github.com/KYVENetwork/cometbft/v38/state" cometTypes "github.com/KYVENetwork/cometbft/v38/types" ) type Block = cometTypes.Block -type LightBlock = cometTypes.LightBlock type Snapshot = abciTypes.Snapshot type Config = cometCfg.Config type GenesisDoc = cometTypes.GenesisDoc -type TendermintValue struct { - Block struct { - Block *Block `json:"block"` - } `json:"block"` -} - -type TendermintDataItem struct { - Key string `json:"key"` - Value TendermintValue `json:"value"` -} - -type TendermintBsyncDataItem struct { - Key string `json:"key"` - Value *Block `json:"value"` -} - -type TendermintBundle = []TendermintDataItem - -type TendermintBsyncBundle = []TendermintBsyncDataItem - -type TendermintSsyncBundle = []TendermintSsyncDataItem - -type TendermintSsyncDataItem struct { - Key string `json:"key"` - Value struct { - Snapshot *abciTypes.Snapshot `json:"snapshot"` - Block *Block `json:"block"` - SeenCommit *cometTypes.Commit `json:"seenCommit"` - State *cometState.State `json:"state"` - ChunkIndex uint32 `json:"chunkIndex"` - Chunk []byte `json:"chunk"` - } `json:"value"` -} - -type BlockResponse struct { - Result struct { - Block cometTypes.Block `json:"block"` - } `json:"result"` -} - type Transport struct { nodeInfo cometP2P.NodeInfo } diff --git a/engines/engines.go b/engines/engines.go deleted file mode 100644 index 8811001..0000000 --- a/engines/engines.go +++ /dev/null @@ -1,90 +0,0 @@ -package engines - -import ( - "fmt" - "github.com/KYVENetwork/ksync/engines/celestia-core-v34" - "github.com/KYVENetwork/ksync/engines/cometbft-v37" - "github.com/KYVENetwork/ksync/engines/cometbft-v38" - "github.com/KYVENetwork/ksync/engines/tendermint-v34" - "github.com/KYVENetwork/ksync/sources/helpers" - "github.com/KYVENetwork/ksync/types" - "github.com/KYVENetwork/ksync/utils" - "os" - "strconv" -) - -var ( - logger = utils.KsyncLogger("engines") -) - -func EngineSourceFactory(engine, homePath, registryUrl, source string, rpcServerPort, continuationHeight int64) (types.Engine, error) { - // if the engine was specified by the user or the source is empty we determine the engine by the engine input - if engine != "" || source == "" { - return EngineFactory(engine, homePath, rpcServerPort), nil - } - - entry, err := helpers.GetSourceRegistryEntry(registryUrl, source) - if err != nil { - return nil, fmt.Errorf("failed to get source registry entry: %w", err) - } - - for _, upgrade := range entry.Codebase.Settings.Upgrades { - height, err := strconv.ParseInt(upgrade.Height, 10, 64) - if err != nil { - return nil, fmt.Errorf("failed to parse upgrade height %s: %w", upgrade.Height, err) - } - - if continuationHeight < height { - break - } - - engine = upgrade.Engine - } - - logger.Info().Msg(fmt.Sprintf("using \"%s\" as consensus engine", engine)) - return EngineFactory(engine, homePath, rpcServerPort), nil -} - -func EngineFactory(engine, homePath string, rpcServerPort int64) types.Engine { - switch engine { - case "": - return &cometbft_v38.Engine{HomePath: homePath, RpcServerPort: rpcServerPort} - case utils.EngineTendermintV34: - return &tendermint_v34.Engine{HomePath: homePath, RpcServerPort: rpcServerPort} - case utils.EngineCometBFTV37: - return &cometbft_v37.Engine{HomePath: homePath, RpcServerPort: rpcServerPort} - case utils.EngineCometBFTV38: - return &cometbft_v38.Engine{HomePath: homePath, RpcServerPort: rpcServerPort} - case utils.EngineCelestiaCoreV34: - return &celestia_core_v34.Engine{HomePath: homePath, RpcServerPort: rpcServerPort} - - // These engines are deprecated and will be removed soon - case utils.EngineTendermintV34Legacy: - logger.Warn().Msg(fmt.Sprintf("engine %s is deprecated and will soon be removed, use %s instead", utils.EngineTendermintV34Legacy, utils.EngineTendermintV34)) - return &tendermint_v34.Engine{HomePath: homePath, RpcServerPort: rpcServerPort} - case utils.EngineCometBFTV37Legacy: - logger.Warn().Msg(fmt.Sprintf("engine %s is deprecated and will soon be removed, use %s instead", utils.EngineCometBFTV37Legacy, utils.EngineCometBFTV37)) - return &cometbft_v37.Engine{HomePath: homePath, RpcServerPort: rpcServerPort} - case utils.EngineCometBFTV38Legacy: - logger.Warn().Msg(fmt.Sprintf("engine %s is deprecated and will soon be removed, use %s instead", utils.EngineCometBFTV38Legacy, utils.EngineCometBFTV38)) - return &cometbft_v38.Engine{HomePath: homePath, RpcServerPort: rpcServerPort} - case utils.EngineCelestiaCoreV34Legacy: - logger.Warn().Msg(fmt.Sprintf("engine %s is deprecated and will soon be removed, use %s instead", utils.EngineCelestiaCoreV34Legacy, utils.EngineCelestiaCoreV34)) - return &celestia_core_v34.Engine{HomePath: homePath, RpcServerPort: rpcServerPort} - - // These engines are deprecated and will be removed soon - case utils.EngineTendermintLegacy: - logger.Warn().Msg(fmt.Sprintf("engine %s is deprecated and will soon be removed, use %s instead", utils.EngineTendermintLegacy, utils.EngineTendermintV34)) - return &tendermint_v34.Engine{HomePath: homePath, RpcServerPort: rpcServerPort} - case utils.EngineCometBFTLegacy: - logger.Warn().Msg(fmt.Sprintf("engine %s is deprecated and will soon be removed, use %s or %s instead", utils.EngineCometBFTLegacy, utils.EngineCometBFTV37, utils.EngineCometBFTV38)) - return &cometbft_v37.Engine{HomePath: homePath, RpcServerPort: rpcServerPort} - case utils.EngineCelestiaCoreLegacy: - logger.Warn().Msg(fmt.Sprintf("engine %s is deprecated and will soon be removed, use %s instead", utils.EngineCelestiaCoreLegacy, utils.EngineCelestiaCoreV34)) - return &celestia_core_v34.Engine{HomePath: homePath, RpcServerPort: rpcServerPort} - default: - logger.Error().Msg(fmt.Sprintf("engine %s not found, run \"ksync engines\" to list all available engines", engine)) - os.Exit(1) - return nil - } -} diff --git a/engines/tendermint-v34/helpers.go b/engines/tendermint-v34/helpers.go index b46f746..775dd4f 100644 --- a/engines/tendermint-v34/helpers.go +++ b/engines/tendermint-v34/helpers.go @@ -1,18 +1,15 @@ package tendermint_v34 import ( - "fmt" + dbm "github.com/cometbft/cometbft-db" "github.com/spf13/viper" cfg "github.com/tendermint/tendermint/config" - cs "github.com/tendermint/tendermint/consensus" - "github.com/tendermint/tendermint/evidence" mempl "github.com/tendermint/tendermint/mempool" + memplv0 "github.com/tendermint/tendermint/mempool/v0" "github.com/tendermint/tendermint/proxy" "github.com/tendermint/tendermint/state" sm "github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/store" - tmTypes "github.com/tendermint/tendermint/types" - dbm "github.com/tendermint/tm-db" "path/filepath" ) @@ -53,7 +50,9 @@ func GetStateDBs(config *Config) (dbm.DB, state.Store, error) { return nil, nil, err } - stateStore := state.NewStore(stateDB) + stateStore := state.NewStore(stateDB, sm.StoreOptions{ + DiscardABCIResponses: config.Storage.DiscardABCIResponses, + }) return stateDB, stateStore, nil } @@ -69,72 +68,21 @@ func GetBlockstoreDBs(config *Config) (dbm.DB, *store.BlockStore, error) { return blockStoreDB, blockStore, nil } -func CreateAndStartProxyAppConns(config *Config) (proxy.AppConns, error) { - proxyApp := proxy.NewAppConns(proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir())) - proxyApp.SetLogger(tmLogger.With("module", "proxy")) - if err := proxyApp.Start(); err != nil { - return nil, fmt.Errorf("error starting proxy app connections: %v", err) - } - return proxyApp, nil -} - -func CreateAndStartEventBus() (*tmTypes.EventBus, error) { - eventBus := tmTypes.NewEventBus() - eventBus.SetLogger(tmLogger.With("module", "events")) - if err := eventBus.Start(); err != nil { - return nil, err - } - return eventBus, nil -} - -func DoHandshake( - stateStore sm.Store, - state sm.State, - blockStore sm.BlockStore, - genDoc *GenesisDoc, - eventBus tmTypes.BlockEventPublisher, - proxyApp proxy.AppConns, -) error { - handshaker := cs.NewHandshaker(stateStore, state, blockStore, genDoc) - handshaker.SetLogger(tmLogger.With("module", "consensus")) - handshaker.SetEventBus(eventBus) - if err := handshaker.Handshake(proxyApp); err != nil { - return fmt.Errorf("error during handshake: %v", err) - } - return nil -} - -func CreateMempoolAndMempoolReactor(config *Config, proxyApp proxy.AppConns, - state sm.State) (*mempl.Reactor, *mempl.CListMempool) { - - mempool := mempl.NewCListMempool( +func CreateMempoolAndMempoolReactor(config *Config, proxyApp proxy.AppConns, state sm.State) mempl.Mempool { + logger := engineLogger.With("module", "mempool") + mp := memplv0.NewCListMempool( config.Mempool, proxyApp.Mempool(), state.LastBlockHeight, - mempl.WithPreCheck(sm.TxPreCheck(state)), - mempl.WithPostCheck(sm.TxPostCheck(state)), + memplv0.WithMetrics(mempl.NopMetrics()), + memplv0.WithPreCheck(sm.TxPreCheck(state)), + memplv0.WithPostCheck(sm.TxPostCheck(state)), ) - mempoolLogger := tmLogger.With("module", "mempool") - mempoolReactor := mempl.NewReactor(config.Mempool, mempool) - mempoolReactor.SetLogger(mempoolLogger) + mp.SetLogger(logger) if config.Consensus.WaitForTxs() { - mempool.EnableTxsAvailable() + mp.EnableTxsAvailable() } - return mempoolReactor, mempool -} -func CreateEvidenceReactor(config *Config, stateStore sm.Store, blockStore *store.BlockStore) (*evidence.Reactor, *evidence.Pool, error) { - evidenceDB, err := DefaultDBProvider(&DBContext{ID: "evidence", Config: config}) - if err != nil { - return nil, nil, err - } - evidenceLogger := tmLogger.With("module", "evidence") - evidencePool, err := evidence.NewPool(evidenceDB, stateStore, blockStore) - if err != nil { - return nil, nil, err - } - evidenceReactor := evidence.NewReactor(evidencePool) - evidenceReactor.SetLogger(evidenceLogger) - return evidenceReactor, evidencePool, nil + return mp } diff --git a/engines/tendermint-v34/logger.go b/engines/tendermint-v34/logger.go index 4e473f9..0450a08 100644 --- a/engines/tendermint-v34/logger.go +++ b/engines/tendermint-v34/logger.go @@ -2,47 +2,54 @@ package tendermint_v34 import ( "fmt" - klogger "github.com/KYVENetwork/ksync/utils" + "github.com/KYVENetwork/ksync/logger" + "github.com/KYVENetwork/ksync/utils" "github.com/rs/zerolog" "github.com/tendermint/tendermint/libs/log" ) -func TmLogger() (logger log.Logger) { - logger = KsyncTmLogger{logger: klogger.LogFormatter("")} - return -} +var ( + engineLogger = EngineLogger{logger: logger.NewLogger(utils.EngineTendermintV34)} +) -type KsyncTmLogger struct { +type EngineLogger struct { logger zerolog.Logger } -func (l KsyncTmLogger) Debug(msg string, keyvals ...interface{}) {} +func (l EngineLogger) Debug(msg string, keyvals ...interface{}) { + logger := l.logger.Debug() + + for i := 0; i < len(keyvals); i = i + 2 { + logger = logger.Any(fmt.Sprintf("%s", keyvals[i]), keyvals[i+1]) + } + + logger.Msg(msg) +} -func (l KsyncTmLogger) Info(msg string, keyvals ...interface{}) { +func (l EngineLogger) Info(msg string, keyvals ...interface{}) { logger := l.logger.Info() for i := 0; i < len(keyvals); i = i + 2 { if keyvals[i] == "hash" || keyvals[i] == "appHash" { - logger = logger.Str(fmt.Sprintf("%v", keyvals[i]), fmt.Sprintf("%x", keyvals[i+1])) + logger = logger.Str(fmt.Sprintf("%s", keyvals[i]), fmt.Sprintf("%X", keyvals[i+1])) } else { - logger = logger.Str(fmt.Sprintf("%v", keyvals[i]), fmt.Sprintf("%v", keyvals[i+1])) + logger = logger.Any(fmt.Sprintf("%s", keyvals[i]), keyvals[i+1]) } } logger.Msg(msg) } -func (l KsyncTmLogger) Error(msg string, keyvals ...interface{}) { +func (l EngineLogger) Error(msg string, keyvals ...interface{}) { logger := l.logger.Error() for i := 0; i < len(keyvals); i = i + 2 { - logger = logger.Str(fmt.Sprintf("%v", keyvals[i]), fmt.Sprintf("%v", keyvals[i+1])) + logger = logger.Any(fmt.Sprintf("%s", keyvals[i]), keyvals[i+1]) } logger.Msg(msg) } -func (l KsyncTmLogger) With(keyvals ...interface{}) (logger log.Logger) { - logger = KsyncTmLogger{logger: klogger.LogFormatter(keyvals)} - return +func (l EngineLogger) With(keyvals ...interface{}) log.Logger { + return EngineLogger{logger: logger.NewLogger(utils.EngineTendermintV34, keyvals)} } diff --git a/engines/tendermint-v34/p2p.go b/engines/tendermint-v34/p2p.go index 676f133..1fe030b 100644 --- a/engines/tendermint-v34/p2p.go +++ b/engines/tendermint-v34/p2p.go @@ -2,7 +2,6 @@ package tendermint_v34 import ( "fmt" - log "github.com/KYVENetwork/ksync/utils" bc "github.com/tendermint/tendermint/blockchain" bcv0 "github.com/tendermint/tendermint/blockchain/v0" tmLog "github.com/tendermint/tendermint/libs/log" @@ -17,10 +16,6 @@ const ( BlockchainChannel = byte(0x40) ) -var ( - logger = log.KsyncLogger("p2p") -) - type BlockchainReactor struct { p2p.BaseReactor @@ -45,6 +40,7 @@ func (bcR *BlockchainReactor) GetChannels() []*p2p.ChannelDescriptor { SendQueueCapacity: 1000, RecvBufferCapacity: 50 * 4096, RecvMessageCapacity: bc.MaxMsgSize, + MessageType: &bcproto.Message{}, }, } } @@ -54,11 +50,11 @@ func (bcR *BlockchainReactor) sendStatusToPeer(src p2p.Peer) (queued bool) { Base: bcR.block.Height, Height: bcR.block.Height + 1}) if err != nil { - logger.Error().Str("could not convert msg to protobuf", err.Error()) + bcR.Logger.Error("could not convert msg to protobuf", err.Error()) return } - logger.Info().Int64("base", bcR.block.Height).Int64("height", bcR.block.Height+1).Msg("Sent status to peer") + bcR.Logger.Info("Sent status to peer", "base", bcR.block.Height, "height", bcR.block.Height+1) return src.Send(BlockchainChannel, msgBytes) } @@ -67,17 +63,17 @@ func (bcR *BlockchainReactor) sendBlockToPeer(msg *bcproto.BlockRequest, src p2p if msg.Height == bcR.block.Height { bl, err := bcR.block.ToProto() if err != nil { - logger.Error().Str("could not convert msg to protobuf", err.Error()) + bcR.Logger.Error("could not convert msg to protobuf", err.Error()) return false } msgBytes, err := bc.EncodeMsg(&bcproto.BlockResponse{Block: bl}) if err != nil { - logger.Error().Str("could not marshal msg", err.Error()) + bcR.Logger.Error("could not marshal msg", err.Error()) return false } - logger.Info().Msg(fmt.Sprintf("sent block with height %d to peer", bcR.block.Height)) + bcR.Logger.Info(fmt.Sprintf("sent block with height %d to peer", bcR.block.Height)) return src.TrySend(BlockchainChannel, msgBytes) } @@ -85,44 +81,66 @@ func (bcR *BlockchainReactor) sendBlockToPeer(msg *bcproto.BlockRequest, src p2p if msg.Height == bcR.nextBlock.Height { bl, err := bcR.nextBlock.ToProto() if err != nil { - logger.Error().Str("could not convert msg to protobuf", err.Error()) + bcR.Logger.Error("could not convert msg to protobuf", err.Error()) + return false } msgBytes, err := bc.EncodeMsg(&bcproto.BlockResponse{Block: bl}) if err != nil { - logger.Error().Str("could not marshal msg", err.Error()) + bcR.Logger.Error("could not marshal msg", err.Error()) return false } - logger.Info().Msg(fmt.Sprintf("sent block with height %d to peer", bcR.nextBlock.Height)) + bcR.Logger.Info(fmt.Sprintf("sent block with height %d to peer", bcR.nextBlock.Height)) return src.TrySend(BlockchainChannel, msgBytes) } - logger.Error().Msg(fmt.Sprintf("peer asked for different block, expected = %d,%d, requested %d", bcR.block.Height, bcR.nextBlock.Height, msg.Height)) + bcR.Logger.Error(fmt.Sprintf("peer asked for different block, expected = %d,%d, requested %d", bcR.block.Height, bcR.nextBlock.Height, msg.Height)) return false } func (bcR *BlockchainReactor) Receive(chID byte, src p2p.Peer, msgBytes []byte) { msg, err := bc.DecodeMsg(msgBytes) if err != nil { - logger.Error().Msgf("Error decoding message", fmt.Sprintf("src: %s", src), fmt.Sprintf("chId: %b", chID), err) + bcR.Logger.Error("Error decoding message", fmt.Sprintf("src: %s", src), fmt.Sprintf("chId: %b", chID), err) bcR.Switch.StopPeerForError(src, err) return } switch msg := msg.(type) { case *bcproto.StatusRequest: - logger.Info().Msg("Incoming status request") + bcR.Logger.Info("Incoming status request") bcR.sendStatusToPeer(src) case *bcproto.BlockRequest: - logger.Info().Int64("height", msg.Height).Msg("Incoming block request") + bcR.Logger.Info("Incoming block request", "height", msg.Height) bcR.sendBlockToPeer(msg, src) case *bcproto.StatusResponse: - logger.Info().Int64("base", msg.Base).Int64("height", msg.Height).Msgf("Incoming status response") + bcR.Logger.Info("Incoming status response", "base", msg.Base, "height", msg.Height) + default: + bcR.Logger.Error(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg))) + } +} + +func (bcR *BlockchainReactor) ReceiveEnvelope(e p2p.Envelope) { + if err := bc.ValidateMsg(e.Message); err != nil { + bcR.Logger.Error("Peer sent us invalid msg", "peer", e.Src, "msg", e.Message, "err", err) + bcR.Switch.StopPeerForError(e.Src, err) + return + } + + switch msg := e.Message.(type) { + case *bcproto.StatusRequest: + bcR.Logger.Info("Incoming status request") + bcR.sendStatusToPeer(e.Src) + case *bcproto.BlockRequest: + bcR.Logger.Info("Incoming block request", "height", msg.Height) + bcR.sendBlockToPeer(msg, e.Src) + case *bcproto.StatusResponse: + bcR.Logger.Info("Incoming status response", "base", msg.Base, "height", msg.Height) default: - logger.Error().Msg(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg))) + bcR.Logger.Error(fmt.Sprintf("Unknown message type %v", reflect.TypeOf(msg))) } } diff --git a/engines/tendermint-v34/tendermint.go b/engines/tendermint-v34/tendermint.go index a01e0cc..517c284 100644 --- a/engines/tendermint-v34/tendermint.go +++ b/engines/tendermint-v34/tendermint.go @@ -3,7 +3,6 @@ package tendermint_v34 import ( "fmt" "github.com/KYVENetwork/ksync/utils" - abciClient "github.com/tendermint/tendermint/abci/client" abciTypes "github.com/tendermint/tendermint/abci/types" cfg "github.com/tendermint/tendermint/config" cs "github.com/tendermint/tendermint/consensus" @@ -26,21 +25,16 @@ import ( "net/http" "time" - db "github.com/tendermint/tm-db" + db "github.com/cometbft/cometbft-db" "net/url" "os" "strconv" ) -var ( - tmLogger = TmLogger() -) - type Engine struct { - HomePath string - RpcServerPort int64 - areDBsOpen bool - config *cfg.Config + homePath string + areDBsOpen bool + config *cfg.Config blockDB db.DB blockStore *tmStore.BlockStore @@ -48,17 +42,35 @@ type Engine struct { stateDB db.DB stateStore tmState.Store + evidenceDB db.DB + genDoc *GenesisDoc privValidatorKey crypto.PubKey + nodeKey *tmP2P.NodeKey state tmState.State - prevBlock *Block proxyApp proxy.AppConns - mempool *mempool.CListMempool + mempool *mempool.Mempool evidencePool *evidence.Pool blockExecutor *tmState.BlockExecutor } +func NewEngine(homePath string) (*Engine, error) { + engine := &Engine{ + homePath: homePath, + } + + if err := engine.LoadConfig(); err != nil { + return nil, err + } + + if err := engine.OpenDBs(); err != nil { + return nil, err + } + + return engine, nil +} + func (engine *Engine) GetName() string { return utils.EngineTendermintV34 } @@ -68,32 +80,18 @@ func (engine *Engine) LoadConfig() error { return nil } - config, err := LoadConfig(engine.HomePath) + config, err := LoadConfig(engine.homePath) if err != nil { return fmt.Errorf("failed to load config.toml: %w", err) } engine.config = config - return nil -} - -func (engine *Engine) OpenDBs() error { - if engine.areDBsOpen { - return nil - } - - if err := engine.LoadConfig(); err != nil { - return err - } - - if err := utils.FormatGenesisFile(engine.config.GenesisFile()); err != nil { - return fmt.Errorf("failed to format genesis file: %w", err) - } genDoc, err := nm.DefaultGenesisDocProviderFunc(engine.config)() if err != nil { return fmt.Errorf("failed to load state and genDoc: %w", err) } + engine.genDoc = genDoc privValidatorKey, err := privval.LoadFilePVEmptyState( @@ -105,6 +103,21 @@ func (engine *Engine) OpenDBs() error { } engine.privValidatorKey = privValidatorKey + nodeKey, err := tmP2P.LoadNodeKey(engine.config.NodeKeyFile()) + if err != nil { + return fmt.Errorf("loading node key file failed: %w", err) + } + engine.nodeKey = nodeKey + + engineLogger.Debug("loaded config", "configPath", fmt.Sprintf("%s/config.toml", engine.homePath)) + return nil +} + +func (engine *Engine) OpenDBs() error { + if engine.areDBsOpen { + return nil + } + blockDB, blockStore, err := GetBlockstoreDBs(engine.config) if err != nil { return fmt.Errorf("failed to open blockDB: %w", err) @@ -121,7 +134,23 @@ func (engine *Engine) OpenDBs() error { engine.stateDB = stateDB engine.stateStore = stateStore + evidenceDB, err := DefaultDBProvider(&DBContext{ID: "evidence", Config: engine.config}) + if err != nil { + return fmt.Errorf("failed to open evidenceDB: %w", err) + } + + engine.evidenceDB = evidenceDB + engine.areDBsOpen = true + engineLogger.Debug( + "opened dbs", + "blockDB", + fmt.Sprintf("%s/%s/blockstore.db", engine.homePath, engine.config.DBPath), + "stateDB", + fmt.Sprintf("%s/%s/state.db", engine.homePath, engine.config.DBPath), + "evidenceDB", + fmt.Sprintf("%s/%s/evidence.db", engine.homePath, engine.config.DBPath), + ) return nil } @@ -138,12 +167,25 @@ func (engine *Engine) CloseDBs() error { return fmt.Errorf("failed to close stateDB: %w", err) } + if err := engine.evidenceDB.Close(); err != nil { + return fmt.Errorf("failed to close evidenceDB: %w", err) + } + engine.areDBsOpen = false + engineLogger.Debug( + "closed dbs", + "blockDB", + fmt.Sprintf("%s/%s/blockstore.db", engine.homePath, engine.config.DBPath), + "stateDB", + fmt.Sprintf("%s/%s/state.db", engine.homePath, engine.config.DBPath), + "evidenceDB", + fmt.Sprintf("%s/%s/evidence.db", engine.homePath, engine.config.DBPath), + ) return nil } -func (engine *Engine) GetHomePath() string { - return engine.HomePath +func (engine *Engine) GetRpcListenAddress() string { + return engine.config.RPC.ListenAddress } func (engine *Engine) GetProxyAppAddress() string { @@ -155,12 +197,12 @@ func (engine *Engine) StartProxyApp() error { return fmt.Errorf("proxy app already started") } - proxyApp, err := CreateAndStartProxyAppConns(engine.config) - if err != nil { - return err + engine.proxyApp = proxy.NewAppConns(proxy.NewRemoteClientCreator(engine.config.ProxyApp, engine.config.ABCI, false)) + if err := engine.proxyApp.Start(); err != nil { + return fmt.Errorf("failed to start proxy app: %w", err) } - engine.proxyApp = proxyApp + engineLogger.Debug("started proxy app connections", "address", engine.GetProxyAppAddress()) return nil } @@ -174,52 +216,29 @@ func (engine *Engine) StopProxyApp() error { } engine.proxyApp = nil + engineLogger.Debug("stopped proxy app connections", "address", engine.GetProxyAppAddress()) return nil } -func (engine *Engine) GetChainId() (string, error) { - if err := engine.LoadConfig(); err != nil { - return "", fmt.Errorf("failed to load config: %w", err) - } - - genDoc, err := nm.DefaultGenesisDocProviderFunc(engine.config)() - if err != nil { - return "", fmt.Errorf("failed to load genDoc: %w", err) - } - - return genDoc.ChainID, nil -} - -func (engine *Engine) GetContinuationHeight() (int64, error) { - height := engine.blockStore.Height() - - initialHeight, err := utils.GetInitialHeightFromGenesisFile(engine.GetGenesisPath()) - if err != nil { - return 0, fmt.Errorf("failed to load initial height from genesis file: %w", err) - } - - continuationHeight := height + 1 - - if continuationHeight < initialHeight { - continuationHeight = initialHeight - } - - return continuationHeight, nil -} - func (engine *Engine) DoHandshake() error { - state, err := tmState.NewStore(engine.stateDB).LoadFromDBOrGenesisDoc(engine.genDoc) + state, err := tmState.NewStore(engine.stateDB, tmState.StoreOptions{ + DiscardABCIResponses: false, + }).LoadFromDBOrGenesisDoc(engine.genDoc) if err != nil { return fmt.Errorf("failed to load state from genDoc: %w", err) } - eventBus, err := CreateAndStartEventBus() - if err != nil { + eventBus := tmTypes.NewEventBus() + eventBus.SetLogger(engineLogger.With("module", "events")) + if err := eventBus.Start(); err != nil { return fmt.Errorf("failed to start event bus: %w", err) } - if err := DoHandshake(engine.stateStore, state, engine.blockStore, engine.genDoc, eventBus, engine.proxyApp); err != nil { - return fmt.Errorf("failed to do handshake: %w", err) + handshaker := cs.NewHandshaker(engine.stateStore, state, engine.blockStore, engine.genDoc) + handshaker.SetLogger(engineLogger.With("module", "consensus")) + handshaker.SetEventBus(eventBus) + if err := handshaker.Handshake(engine.proxyApp); err != nil { + return fmt.Errorf("error during handshake: %w", err) } state, err = engine.stateStore.Load() @@ -229,115 +248,74 @@ func (engine *Engine) DoHandshake() error { engine.state = state - _, mempool := CreateMempoolAndMempoolReactor(engine.config, engine.proxyApp, state) + mp := CreateMempoolAndMempoolReactor(engine.config, engine.proxyApp, state) - _, evidencePool, err := CreateEvidenceReactor(engine.config, engine.stateStore, engine.blockStore) + evidencePool, err := evidence.NewPool(engine.evidenceDB, engine.stateStore, engine.blockStore) if err != nil { - return fmt.Errorf("failed to create evidence reactor: %w", err) + return fmt.Errorf("failed to create evidence pool: %w", err) } - engine.mempool = mempool + engine.mempool = &mp engine.evidencePool = evidencePool engine.blockExecutor = tmState.NewBlockExecutor( engine.stateStore, - tmLogger.With("module", "state"), + engineLogger.With("module", "state"), engine.proxyApp.Consensus(), - mempool, + mp, evidencePool, ) return nil } -func (engine *Engine) ApplyBlock(runtime *string, value []byte) error { - var block *Block - - if runtime == nil { - // if runtime is nil we sync from another tendermint node - var blockResponse BlockResponse - err := json.Unmarshal(value, &blockResponse) - if err != nil { - return fmt.Errorf("failed to unmarshal block response: %w", err) - } - block = &blockResponse.Result.Block - } else if *runtime == utils.KSyncRuntimeTendermint { - var parsed TendermintValue - - if err := json.Unmarshal(value, &parsed); err != nil { - return fmt.Errorf("failed to unmarshal value: %w", err) - } +func (engine *Engine) ApplyBlock(rawBlock, nextRawBlock []byte) error { + var block, nextBlock *Block - block = parsed.Block.Block - } else if *runtime == utils.KSyncRuntimeTendermintBsync { - if err := json.Unmarshal(value, &block); err != nil { - return fmt.Errorf("failed to unmarshal value: %w", err) - } - } else { - return fmt.Errorf("runtime %s unknown", runtime) + if err := json.Unmarshal(rawBlock, &block); err != nil { + return fmt.Errorf("failed to unmarshal block: %w", err) } - // if the previous block is not defined we continue - if engine.prevBlock == nil { - engine.prevBlock = block - return nil + if err := json.Unmarshal(nextRawBlock, &nextBlock); err != nil { + return fmt.Errorf("failed to unmarshal next block: %w", err) } // get block data - blockParts := engine.prevBlock.MakePartSet(tmTypes.BlockPartSizeBytes) - blockId := tmTypes.BlockID{Hash: engine.prevBlock.Hash(), PartSetHeader: blockParts.Header()} + blockParts := block.MakePartSet(tmTypes.BlockPartSizeBytes) + blockId := tmTypes.BlockID{Hash: block.Hash(), PartSetHeader: blockParts.Header()} // verify block - if err := engine.blockExecutor.ValidateBlock(engine.state, engine.prevBlock); err != nil { - return fmt.Errorf("block validation failed at height %d: %w", engine.prevBlock.Height, err) + if err := engine.blockExecutor.ValidateBlock(engine.state, block); err != nil { + return fmt.Errorf("block validation failed at height %d: %w", block.Height, err) } // verify commits - if err := engine.state.Validators.VerifyCommitLight(engine.state.ChainID, blockId, engine.prevBlock.Height, block.LastCommit); err != nil { - return fmt.Errorf("light commit verification failed at height %d: %w", engine.prevBlock.Height, err) + if err := engine.state.Validators.VerifyCommitLight(engine.state.ChainID, blockId, block.Height, nextBlock.LastCommit); err != nil { + return fmt.Errorf("light commit verification failed at height %d: %w", block.Height, err) } // store block - engine.blockStore.SaveBlock(engine.prevBlock, blockParts, block.LastCommit) + engine.blockStore.SaveBlock(block, blockParts, nextBlock.LastCommit) // execute block against app - state, _, err := engine.blockExecutor.ApplyBlock(engine.state, blockId, engine.prevBlock) + state, _, err := engine.blockExecutor.ApplyBlock(engine.state, blockId, block) if err != nil { - return fmt.Errorf("failed to apply block at height %d: %w", engine.prevBlock.Height, err) + return fmt.Errorf("failed to apply block at height %d: %w", block.Height, err) } - // update values for next round + // update state for next round engine.state = state - engine.prevBlock = block - return nil } -func (engine *Engine) ApplyFirstBlockOverP2P(runtime string, value, nextValue []byte) error { +func (engine *Engine) ApplyFirstBlockOverP2P(rawBlock, nextRawBlock []byte) error { var block, nextBlock *Block - if runtime == utils.KSyncRuntimeTendermint { - var parsed, nextParsed TendermintValue - - if err := json.Unmarshal(value, &parsed); err != nil { - return fmt.Errorf("failed to unmarshal value: %w", err) - } - - if err := json.Unmarshal(nextValue, &nextParsed); err != nil { - return fmt.Errorf("failed to unmarshal next value: %w", err) - } - - block = parsed.Block.Block - nextBlock = nextParsed.Block.Block - } else if runtime == utils.KSyncRuntimeTendermintBsync { - if err := json.Unmarshal(value, &block); err != nil { - return fmt.Errorf("failed to unmarshal value: %w", err) - } + if err := json.Unmarshal(rawBlock, &block); err != nil { + return fmt.Errorf("failed to unmarshal block: %w", err) + } - if err := json.Unmarshal(nextValue, &nextBlock); err != nil { - return fmt.Errorf("failed to unmarshal next value: %w", err) - } - } else { - return fmt.Errorf("runtime %s unknown", runtime) + if err := json.Unmarshal(nextRawBlock, &nextBlock); err != nil { + return fmt.Errorf("failed to unmarshal next block: %w", err) } peerAddress := engine.config.P2P.ListenAddress @@ -367,7 +345,7 @@ func (engine *Engine) ApplyFirstBlockOverP2P(runtime string, value, nextValue [] nodeInfo, err := MakeNodeInfo(engine.config, ksyncNodeKey, engine.genDoc) transport := tmP2P.NewMultiplexTransport(nodeInfo, *ksyncNodeKey, tmP2P.MConnConfig(engine.config.P2P)) bcR := NewBlockchainReactor(block, nextBlock) - sw := CreateSwitch(engine.config, transport, bcR, nodeInfo, ksyncNodeKey, tmLogger) + sw := CreateSwitch(engine.config, transport, bcR, nodeInfo, ksyncNodeKey, engineLogger) // start the transport addr, err := tmP2P.NewNetAddressString(tmP2P.IDAddressString(nodeKey.ID(), engine.config.P2P.ListenAddress)) @@ -404,20 +382,6 @@ func (engine *Engine) ApplyFirstBlockOverP2P(runtime string, value, nextValue [] return nil } -func (engine *Engine) GetGenesisPath() string { - return engine.config.GenesisFile() -} - -func (engine *Engine) GetGenesisHeight() (int64, error) { - defaultDocProvider := nm.DefaultGenesisDocProviderFunc(engine.config) - genDoc, err := defaultDocProvider() - if err != nil { - return 0, err - } - - return genDoc.InitialHeight, nil -} - func (engine *Engine) GetHeight() int64 { return engine.blockStore.Height() } @@ -427,40 +391,20 @@ func (engine *Engine) GetBaseHeight() int64 { } func (engine *Engine) GetAppHeight() (int64, error) { - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) - - if err := socketClient.Start(); err != nil { - return 0, fmt.Errorf("failed to start socket client: %w", err) - } - - info, err := socketClient.InfoSync(abciTypes.RequestInfo{}) + info, err := engine.proxyApp.Query().InfoSync(abciTypes.RequestInfo{}) if err != nil { return 0, fmt.Errorf("failed to query info: %w", err) } - if err := socketClient.Stop(); err != nil { - return 0, fmt.Errorf("failed to stop socket client: %w", err) - } - return info.LastBlockHeight, nil } func (engine *Engine) GetSnapshots() ([]byte, error) { - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) - - if err := socketClient.Start(); err != nil { - return nil, fmt.Errorf("failed to start socket client: %w", err) - } - - res, err := socketClient.ListSnapshotsSync(abciTypes.RequestListSnapshots{}) + res, err := engine.proxyApp.Snapshot().ListSnapshotsSync(abciTypes.RequestListSnapshots{}) if err != nil { return nil, fmt.Errorf("failed to list snapshots: %w", err) } - if err := socketClient.Stop(); err != nil { - return nil, fmt.Errorf("failed to stop socket client: %w", err) - } - if len(res.Snapshots) == 0 { return json.Marshal([]Snapshot{}) } @@ -469,21 +413,11 @@ func (engine *Engine) GetSnapshots() ([]byte, error) { } func (engine *Engine) IsSnapshotAvailable(height int64) (bool, error) { - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) - - if err := socketClient.Start(); err != nil { - return false, fmt.Errorf("failed to start socket client: %w", err) - } - - res, err := socketClient.ListSnapshotsSync(abciTypes.RequestListSnapshots{}) + res, err := engine.proxyApp.Snapshot().ListSnapshotsSync(abciTypes.RequestListSnapshots{}) if err != nil { return false, fmt.Errorf("failed to list snapshots: %w", err) } - if err := socketClient.Stop(); err != nil { - return false, fmt.Errorf("failed to stop socket client: %w", err) - } - for _, snapshot := range res.Snapshots { if snapshot.Height == uint64(height) { return true, nil @@ -494,13 +428,7 @@ func (engine *Engine) IsSnapshotAvailable(height int64) (bool, error) { } func (engine *Engine) GetSnapshotChunk(height, format, chunk int64) ([]byte, error) { - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) - - if err := socketClient.Start(); err != nil { - return nil, fmt.Errorf("failed to start socket client: %w", err) - } - - res, err := socketClient.LoadSnapshotChunkSync(abciTypes.RequestLoadSnapshotChunk{ + res, err := engine.proxyApp.Snapshot().LoadSnapshotChunkSync(abciTypes.RequestLoadSnapshotChunk{ Height: uint64(height), Format: uint32(format), Chunk: uint32(chunk), @@ -509,10 +437,6 @@ func (engine *Engine) GetSnapshotChunk(height, format, chunk int64) ([]byte, err return nil, fmt.Errorf("failed to load snapshot chunk: %w", err) } - if err := socketClient.Stop(); err != nil { - return nil, fmt.Errorf("failed to stop socket client: %w", err) - } - return json.Marshal(res.Chunk) } @@ -521,31 +445,31 @@ func (engine *Engine) GetBlock(height int64) ([]byte, error) { return json.Marshal(block) } -func (engine *Engine) StartRPCServer() { +func (engine *Engine) StartRPCServer(port int64) { // wait until all reactors have been booted for engine.blockExecutor == nil { time.Sleep(1000) } - rpcLogger := tmLogger.With("module", "rpc-server") + rpcLogger := engineLogger.With("module", "rpc-server") consensusReactor := cs.NewReactor(cs.NewState( engine.config.Consensus, engine.state.Copy(), engine.blockExecutor, engine.blockStore, - engine.mempool, + *engine.mempool, engine.evidencePool, ), false, cs.ReactorMetrics(cs.NopMetrics())) nodeKey, err := tmP2P.LoadNodeKey(engine.config.NodeKeyFile()) if err != nil { - tmLogger.Error(fmt.Sprintf("failed to get nodeKey: %s", err)) + engineLogger.Error(fmt.Sprintf("failed to get nodeKey: %s", err)) return } nodeInfo, err := MakeNodeInfo(engine.config, nodeKey, engine.genDoc) if err != nil { - tmLogger.Error(fmt.Sprintf("failed to get nodeInfo: %s", err)) + engineLogger.Error(fmt.Sprintf("failed to get nodeInfo: %s", err)) return } @@ -579,14 +503,14 @@ func (engine *Engine) StartRPCServer() { config := rpcserver.DefaultConfig() rpcserver.RegisterRPCFuncs(mux, routes, rpcLogger) - listener, err := rpcserver.Listen(fmt.Sprintf("tcp://127.0.0.1:%d", engine.RpcServerPort), config) + listener, err := rpcserver.Listen(fmt.Sprintf("tcp://127.0.0.1:%d", port), config) if err != nil { - tmLogger.Error(fmt.Sprintf("failed to get rpc listener: %s", err)) + engineLogger.Error(fmt.Sprintf("failed to get rpc listener: %s", err)) return } if err := rpcserver.Serve(listener, mux, rpcLogger, config); err != nil { - tmLogger.Error(fmt.Sprintf("failed to start rpc server: %s", err)) + engineLogger.Error(fmt.Sprintf("failed to start rpc server: %s", err)) return } } @@ -648,97 +572,90 @@ func (engine *Engine) GetSeenCommit(height int64) ([]byte, error) { return json.Marshal(block.LastCommit) } -func (engine *Engine) OfferSnapshot(value []byte) (string, uint32, error) { - var bundle TendermintSsyncBundle +func (engine *Engine) OfferSnapshot(rawSnapshot, rawState []byte) error { + var snapshot *abciTypes.Snapshot - if err := json.Unmarshal(value, &bundle); err != nil { - return abciTypes.ResponseOfferSnapshot_UNKNOWN.String(), 0, fmt.Errorf("failed to unmarshal tendermint-ssync bundle: %w", err) + if err := json.Unmarshal(rawSnapshot, &snapshot); err != nil { + return fmt.Errorf("failed to unmarshal snapshot: %w", err) } - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) + var state *tmState.State - if err := socketClient.Start(); err != nil { - return abciTypes.ResponseOfferSnapshot_UNKNOWN.String(), 0, fmt.Errorf("failed to start socket client: %w", err) + if err := json.Unmarshal(rawState, &state); err != nil { + return fmt.Errorf("failed to unmarshal state: %w", err) } - res, err := socketClient.OfferSnapshotSync(abciTypes.RequestOfferSnapshot{ - Snapshot: bundle[0].Value.Snapshot, - AppHash: bundle[0].Value.State.AppHash, + res, err := engine.proxyApp.Snapshot().OfferSnapshotSync(abciTypes.RequestOfferSnapshot{ + Snapshot: snapshot, + AppHash: state.AppHash, }) - if err != nil { - return abciTypes.ResponseOfferSnapshot_UNKNOWN.String(), 0, err + return err } - if err := socketClient.Stop(); err != nil { - return abciTypes.ResponseOfferSnapshot_UNKNOWN.String(), 0, fmt.Errorf("failed to stop socket client: %w", err) + if res.Result.String() != abciTypes.ResponseOfferSnapshot_ACCEPT.String() { + return fmt.Errorf(res.Result.String()) } - return res.Result.String(), bundle[0].Value.Snapshot.Chunks, nil + return nil } -func (engine *Engine) ApplySnapshotChunk(chunkIndex uint32, value []byte) (string, error) { - var bundle TendermintSsyncBundle - - if err := json.Unmarshal(value, &bundle); err != nil { - return abciTypes.ResponseApplySnapshotChunk_UNKNOWN.String(), fmt.Errorf("failed to unmarshal tendermint-ssync bundle: %w", err) - } - - nodeKey, err := tmP2P.LoadNodeKey(engine.config.NodeKeyFile()) +func (engine *Engine) ApplySnapshotChunk(chunkIndex int64, chunk []byte) error { + res, err := engine.proxyApp.Snapshot().ApplySnapshotChunkSync(abciTypes.RequestApplySnapshotChunk{ + Index: uint32(chunkIndex), + Chunk: chunk, + Sender: string(engine.nodeKey.ID()), + }) if err != nil { - return abciTypes.ResponseApplySnapshotChunk_UNKNOWN.String(), fmt.Errorf("loading node key file failed: %w", err) + return err } - socketClient := abciClient.NewSocketClient(engine.config.ProxyApp, false) - - if err := socketClient.Start(); err != nil { - return abciTypes.ResponseApplySnapshotChunk_UNKNOWN.String(), fmt.Errorf("failed to start socket client: %w", err) + if res.Result.String() != abciTypes.ResponseApplySnapshotChunk_ACCEPT.String() { + return fmt.Errorf(res.Result.String()) } - res, err := socketClient.ApplySnapshotChunkSync(abciTypes.RequestApplySnapshotChunk{ - Index: chunkIndex, - Chunk: bundle[0].Value.Chunk, - Sender: string(nodeKey.ID()), - }) + return nil +} - if err != nil { - return abciTypes.ResponseApplySnapshotChunk_UNKNOWN.String(), err - } +func (engine *Engine) BootstrapState(rawState, rawSeenCommit, rawBlock []byte) error { + var state *tmState.State - if err := socketClient.Stop(); err != nil { - return abciTypes.ResponseApplySnapshotChunk_UNKNOWN.String(), fmt.Errorf("failed to stop socket client: %w", err) + if err := json.Unmarshal(rawState, &state); err != nil { + return fmt.Errorf("failed to unmarshal state: %w", err) } - return res.Result.String(), nil -} + var seenCommit *tmTypes.Commit + + if err := json.Unmarshal(rawSeenCommit, &seenCommit); err != nil { + return fmt.Errorf("failed to unmarshal seen commit: %w", err) + } -func (engine *Engine) BootstrapState(value []byte) error { - var bundle TendermintSsyncBundle + var block *tmTypes.Block - if err := json.Unmarshal(value, &bundle); err != nil { - return fmt.Errorf("failed to unmarshal tendermint-ssync bundle: %w", err) + if err := json.Unmarshal(rawBlock, &block); err != nil { + return fmt.Errorf("failed to unmarshal block: %w", err) } // if TimeIotaMs is zero we set it to 1 else the app would panic. // in rare circumstances this can be zero if the snapshot got // created with the engine cometbft-v0.37 or cometbft-v0.38 but the // height is still for tendermint-v0.34 - if bundle[0].Value.State.ConsensusParams.Block.TimeIotaMs == 0 { - bundle[0].Value.State.ConsensusParams.Block.TimeIotaMs = 1 + if state.ConsensusParams.Block.TimeIotaMs == 0 { + state.ConsensusParams.Block.TimeIotaMs = 1 } - err := engine.stateStore.Bootstrap(*bundle[0].Value.State) + err := engine.stateStore.Bootstrap(*state) if err != nil { - return fmt.Errorf("failed to bootstrap state: %s\"", err) + return fmt.Errorf("failed to bootstrap state: %w", err) } - err = engine.blockStore.SaveSeenCommit(bundle[0].Value.State.LastBlockHeight, bundle[0].Value.SeenCommit) + err = engine.blockStore.SaveSeenCommit(state.LastBlockHeight, seenCommit) if err != nil { return fmt.Errorf("failed to save seen commit: %s\"", err) } - blockParts := bundle[0].Value.Block.MakePartSet(tmTypes.BlockPartSizeBytes) - engine.blockStore.SaveBlock(bundle[0].Value.Block, blockParts, bundle[0].Value.SeenCommit) + blockParts := block.MakePartSet(tmTypes.BlockPartSizeBytes) + engine.blockStore.SaveBlock(block, blockParts, seenCommit) return nil } @@ -761,7 +678,7 @@ func (engine *Engine) PruneBlocks(toHeight int64) error { } func (engine *Engine) ResetAll(keepAddrBook bool) error { - config, err := LoadConfig(engine.HomePath) + config, err := LoadConfig(engine.homePath) if err != nil { return fmt.Errorf("failed to load config.toml: %w", err) } @@ -772,17 +689,17 @@ func (engine *Engine) ResetAll(keepAddrBook bool) error { privValStateFile := config.PrivValidatorStateFile() if keepAddrBook { - tmLogger.Info("the address book remains intact") + engineLogger.Info("the address book remains intact") } else { if err := os.Remove(addrBookFile); err == nil { - tmLogger.Info("removed existing address book", "file", addrBookFile) + engineLogger.Info("removed existing address book", "file", addrBookFile) } else if !os.IsNotExist(err) { return fmt.Errorf("error removing address book, file: %s, err: %w", addrBookFile, err) } } if err := os.RemoveAll(dbDir); err == nil { - tmLogger.Info("removed all blockchain history", "dir", dbDir) + engineLogger.Info("removed all blockchain history", "dir", dbDir) } else { return fmt.Errorf("error removing all blockchain history, dir: %s, err: %w", dbDir, err) } @@ -795,7 +712,7 @@ func (engine *Engine) ResetAll(keepAddrBook bool) error { if _, err := os.Stat(privValKeyFile); err == nil { pv := privval.LoadFilePVEmptyState(privValKeyFile, privValStateFile) pv.Reset() - tmLogger.Info( + engineLogger.Info( "Reset private validator file to genesis state", "keyFile", privValKeyFile, "stateFile", privValStateFile, @@ -803,12 +720,20 @@ func (engine *Engine) ResetAll(keepAddrBook bool) error { } else { pv := privval.GenFilePV(privValKeyFile, privValStateFile) pv.Save() - tmLogger.Info( + engineLogger.Info( "Generated private validator file", "keyFile", privValKeyFile, "stateFile", privValStateFile, ) } + if err := engine.CloseDBs(); err != nil { + return fmt.Errorf("failed to close dbs: %w", err) + } + + if err := engine.OpenDBs(); err != nil { + return fmt.Errorf("failed to open dbs: %w", err) + } + return nil } diff --git a/engines/tendermint-v34/types.go b/engines/tendermint-v34/types.go index ccaee5b..ad11b6c 100644 --- a/engines/tendermint-v34/types.go +++ b/engines/tendermint-v34/types.go @@ -4,56 +4,14 @@ import ( abciTypes "github.com/tendermint/tendermint/abci/types" tmCfg "github.com/tendermint/tendermint/config" tmP2P "github.com/tendermint/tendermint/p2p" - tmState "github.com/tendermint/tendermint/state" tmTypes "github.com/tendermint/tendermint/types" ) type Block = tmTypes.Block -type LightBlock = tmTypes.LightBlock type Snapshot = abciTypes.Snapshot type Config = tmCfg.Config type GenesisDoc = tmTypes.GenesisDoc -type TendermintValue struct { - Block struct { - Block *Block `json:"block"` - } `json:"block"` -} - -type TendermintDataItem struct { - Key string `json:"key"` - Value TendermintValue `json:"value"` -} - -type TendermintBsyncDataItem struct { - Key string `json:"key"` - Value *Block `json:"value"` -} - -type TendermintBundle = []TendermintDataItem - -type TendermintBsyncBundle = []TendermintBsyncDataItem - -type TendermintSsyncBundle = []TendermintSsyncDataItem - -type TendermintSsyncDataItem struct { - Key string `json:"key"` - Value struct { - Snapshot *abciTypes.Snapshot `json:"snapshot"` - Block *Block `json:"block"` - SeenCommit *tmTypes.Commit `json:"seenCommit"` - State *tmState.State `json:"state"` - ChunkIndex uint32 `json:"chunkIndex"` - Chunk []byte `json:"chunk"` - } `json:"value"` -} - -type BlockResponse struct { - Result struct { - Block tmTypes.Block `json:"block"` - } `json:"result"` -} - type Transport struct { nodeInfo tmP2P.NodeInfo } diff --git a/flags/flags.go b/flags/flags.go new file mode 100644 index 0000000..26323c6 --- /dev/null +++ b/flags/flags.go @@ -0,0 +1,31 @@ +package flags + +// note that new flags have to be also registered +// for tracking in metrics/metrics.go +var ( + BinaryPath string + HomePath string + ChainId string + ChainRest string + StorageRest string + BlockRpc string + SnapshotPoolId string + BlockPoolId string + StartHeight int64 + TargetHeight int64 + RpcServer bool + RpcServerPort int64 + SnapshotPort int64 + BlockRpcReqTimeout int64 + Pruning bool + KeepSnapshots bool + SkipWaiting bool + AppFlags string + AppLogs bool + AutoSelectBinaryVersion bool + Reset bool + KeepAddrBook bool + OptOut bool + Debug bool + Y bool +) diff --git a/go.mod b/go.mod index 7ac1b49..b6f12c2 100644 --- a/go.mod +++ b/go.mod @@ -3,40 +3,34 @@ module github.com/KYVENetwork/ksync go 1.22.4 require ( - github.com/KYVENetwork/celestia-core v1.44.0-tm-v0.34.29 - github.com/KYVENetwork/cometbft/v37 v37.0.2 - github.com/KYVENetwork/cometbft/v38 v38.0.3 - github.com/cometbft/cometbft-db v0.9.1 + github.com/KYVENetwork/celestia-core v1.47.0-tm-v0.34.29 + github.com/KYVENetwork/cometbft/v37 v37.0.3 + github.com/KYVENetwork/cometbft/v38 v38.0.4 + github.com/cometbft/cometbft-db v0.9.5 github.com/gin-gonic/gin v1.9.1 - github.com/google/uuid v1.4.0 + github.com/google/uuid v1.6.0 github.com/jedib0t/go-pretty/v6 v6.4.7 - github.com/onsi/ginkgo/v2 v2.21.0 - github.com/onsi/gomega v1.34.2 github.com/rs/zerolog v1.30.0 github.com/segmentio/analytics-go v3.1.0+incompatible - github.com/spf13/cobra v1.8.0 - github.com/spf13/viper v1.18.1 - github.com/tendermint/tendermint v0.34.14 - github.com/tendermint/tm-db v0.6.7 + github.com/spf13/cobra v1.8.1 + github.com/spf13/viper v1.19.0 + github.com/tendermint/tendermint v0.34.27 gopkg.in/yaml.v2 v2.4.0 - gotest.tools v2.2.0+incompatible ) require ( - github.com/Workiva/go-datastructures v1.0.53 // indirect + github.com/Workiva/go-datastructures v1.1.5 // indirect github.com/aws/aws-sdk-go v1.40.45 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect - github.com/btcsuite/btcd v0.22.1 // indirect - github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/celestiaorg/nmt v0.21.0 // indirect github.com/cespare/xxhash v1.1.0 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/cosmos/gogoproto v1.4.11 // indirect - github.com/cosmos/gorocksdb v1.2.0 // indirect - github.com/creachadair/taskgroup v0.3.2 // indirect + github.com/creachadair/taskgroup v0.13.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/dgraph-io/badger/v2 v2.2007.4 // indirect @@ -46,7 +40,7 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect - github.com/go-kit/kit v0.12.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 github.com/go-logr/logr v1.4.2 // indirect @@ -54,17 +48,15 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.0 // indirect - github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/glog v1.1.2 // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/glog v1.2.2 // 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/btree v1.1.3 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/orderedcode v0.0.1 // indirect - github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect - github.com/gorilla/websocket v1.5.0 // indirect + github.com/gorilla/websocket v1.5.3 // indirect github.com/grafana/otel-profiling-go v0.5.1 // indirect github.com/grafana/pyroscope-go v1.1.1 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.6 // indirect @@ -74,41 +66,42 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.3 // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect - github.com/lib/pq v1.10.7 // indirect + github.com/lib/pq v1.10.9 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/linxGnu/grocksdb v1.8.6 // indirect + github.com/linxGnu/grocksdb v1.9.3 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect - github.com/minio/highwayhash v1.0.2 // indirect + github.com/mimoo/StrobeGo v0.0.0-20220103164710-9a04d6ca976b // indirect + github.com/minio/highwayhash v1.0.3 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/oasisprotocol/curve25519-voi v0.0.0-20220708102147-0a8a51822cae // indirect - github.com/pelletier/go-toml/v2 v2.1.0 // indirect - github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect + github.com/onsi/gomega v1.34.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.42.0 // indirect - github.com/prometheus/procfs v0.12.0 // indirect + github.com/prometheus/client_golang v1.20.5 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.59.1 // indirect + github.com/prometheus/procfs v0.15.1 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rivo/uniseg v0.2.0 // indirect - github.com/rs/cors v1.8.3 // indirect - github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/rs/cors v1.11.1 // indirect + github.com/sagikazarmark/locafero v0.6.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect - github.com/sasha-s/go-deadlock v0.3.1 // indirect + github.com/sasha-s/go-deadlock v0.3.5 // indirect github.com/segmentio/backo-go v1.0.1 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect - github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/cast v1.7.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/testify v1.9.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect @@ -116,24 +109,28 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect - go.etcd.io/bbolt v1.3.8 // indirect - go.opentelemetry.io/otel v1.21.0 // indirect + go.etcd.io/bbolt v1.3.11 // indirect + go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.18.0 // indirect - go.opentelemetry.io/otel/metric v1.21.0 // indirect + go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/otel/sdk v1.21.0 // indirect - go.opentelemetry.io/otel/trace v1.21.0 // indirect - go.uber.org/multierr v1.10.0 // indirect + go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.28.0 // indirect - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect golang.org/x/net v0.30.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.26.0 // indirect golang.org/x/text v0.19.0 // indirect - golang.org/x/tools v0.26.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect - google.golang.org/grpc v1.60.0 // indirect - google.golang.org/protobuf v1.34.1 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect + google.golang.org/grpc v1.67.1 // indirect + google.golang.org/protobuf v1.35.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) + +replace ( + github.com/btcsuite/btcd/btcec/v2 v2.3.4 => github.com/btcsuite/btcd/btcec/v2 v2.2.2 + github.com/tendermint/tendermint => github.com/KYVENetwork/cometbft v0.34.35 +) diff --git a/go.sum b/go.sum index a16ad47..d5efb09 100644 --- a/go.sum +++ b/go.sum @@ -1,158 +1,72 @@ -cloud.google.com/go v0.26.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.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= github.com/ChainSafe/go-schnorrkel v1.0.0 h1:3aDA67lAykLaG1y3AOjs88dMxC88PgUuHRrLeDnvGIM= github.com/ChainSafe/go-schnorrkel v1.0.0/go.mod h1:dpzHYVxLZcp8pjlV+O+UR8K0Hp/z7vcchBSbMBEhCw4= -github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/KYVENetwork/celestia-core v1.44.0-tm-v0.34.29 h1:Y3MfR91mx7C7Xipyp4tO7gAPO6scx4UINs71fGGbjcw= -github.com/KYVENetwork/celestia-core v1.44.0-tm-v0.34.29/go.mod h1:F24hB7hFzH/7oXDPwC0csYnzoyprrGiHkMh/PHtIRY4= -github.com/KYVENetwork/cometbft/v37 v37.0.2 h1:nVRHfZYmeO8MLHazNbVdNtH72OrjrOwffvlYEIfVraQ= -github.com/KYVENetwork/cometbft/v37 v37.0.2/go.mod h1:eAUIGNAQfYvLNuTZS48MsjqFtIYA8mU9ZcJmGbVMk90= -github.com/KYVENetwork/cometbft/v38 v38.0.3 h1:BJc+CmZwweQsu0BcHi4Bo/KpMjSOUAVydr0i28SjECI= -github.com/KYVENetwork/cometbft/v38 v38.0.3/go.mod h1:8g8iw3Pp/ZkXPBgmPon9K/kHcj53vE86l5228rhmcuk= -github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= -github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/KYVENetwork/celestia-core v1.47.0-tm-v0.34.29 h1:MaXU8B5EcAdf9FcryMaUsZtcizabH/N1uRcp/LR/Jgo= +github.com/KYVENetwork/celestia-core v1.47.0-tm-v0.34.29/go.mod h1:F24hB7hFzH/7oXDPwC0csYnzoyprrGiHkMh/PHtIRY4= +github.com/KYVENetwork/cometbft v0.34.35 h1:kSwb+Is995tvI5xaYX6RQ9GRVrfMMXzpUHS+Yei+MxQ= +github.com/KYVENetwork/cometbft v0.34.35/go.mod h1:SA1at6NTspQqvJ3Ud9TV9ixb0xgzoWNHGZVOU4HO+mM= +github.com/KYVENetwork/cometbft/v37 v37.0.3 h1:kimHuadNTh3qDHfuB5eYyixoEGLpmnmYDc4dVsPG/jA= +github.com/KYVENetwork/cometbft/v37 v37.0.3/go.mod h1:Q2yJ37nDdqtqjt58rhyaooQej7amyWIoEu+0tvKPRUI= +github.com/KYVENetwork/cometbft/v38 v38.0.4 h1:uynbwfnXDfgEPT3lZDhuC5aUBEaDgiCTVvmmmJ99sZo= +github.com/KYVENetwork/cometbft/v38 v38.0.4/go.mod h1:DZ0aJmo9hA1WA2Qm+USv4L8lLBZ0rDS/yoyuEy+B5s4= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/Workiva/go-datastructures v1.0.52/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA= -github.com/Workiva/go-datastructures v1.0.53 h1:J6Y/52yX10Xc5JjXmGtWoSSxs3mZnGSaq37xZZh7Yig= -github.com/Workiva/go-datastructures v1.0.53/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A= -github.com/adlio/schema v1.1.13/go.mod h1:L5Z7tw+7lRK1Fnpi/LT/ooCP1elkXn0krMWBQHUhEDE= -github.com/adlio/schema v1.3.3 h1:oBJn8I02PyTB466pZO1UZEn1TV5XLlifBSyMrmHl/1I= -github.com/adlio/schema v1.3.3/go.mod h1:1EsRssiv9/Ce2CMzq5DoL7RiMshhuigQxrR4DMV9fHg= -github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= -github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -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/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/Workiva/go-datastructures v1.1.5 h1:5YfhQ4ry7bZc2Mc7R0YZyYwpf5c6t1cEFvdAhd6Mkf4= +github.com/Workiva/go-datastructures v1.1.5/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A= +github.com/adlio/schema v1.3.6 h1:k1/zc2jNfeiZBA5aFTRy37jlBIuCkXCm0XmvpzCKI9I= +github.com/adlio/schema v1.3.6/go.mod h1:qkxwLgPBd1FgLRHYVCmQT/rrBr3JH38J9LjmVzWNudg= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= -github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= -github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.40.45 h1:QN1nsY27ssD/JmW4s83qmSb+uL6DG4GmCDzjmJB4xUI= github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= -github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= -github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= -github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c= -github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= -github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= -github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= -github.com/btcsuite/btcd/btcutil v1.1.3 h1:xfbtw8lwpp0G6NwSHb+UE67ryTFHJAiNuipusjXSohQ= -github.com/btcsuite/btcd/btcutil v1.1.3/go.mod h1:UR7dsSJzJUfMmFiiLlIrMq1lS9jh9EdCV7FStZSnpi0= +github.com/btcsuite/btcd/btcec/v2 v2.2.2 h1:5uxe5YjoCq+JeOpg0gZSNHuFgeogrocBYxvg6w9sAgc= +github.com/btcsuite/btcd/btcec/v2 v2.2.2/go.mod h1:9/CSmJxmuvqzX9Wh2fXMWToLOHhPd11lSPuIupwTkI8= +github.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/AYFd6c= +github.com/btcsuite/btcd/btcutil v1.1.6/go.mod h1:9dFymx8HpuLqBnsPELrImQeTQfKBQqzqGbbV3jK55aE= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= -github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= -github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= -github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= -github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ= -github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= -github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= -github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= -github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= -github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= -github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= -github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= -github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= -github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/celestiaorg/nmt v0.21.0 h1:81MBqxNn3orByoiCtdNVjwi5WsLgMkzHwP02ZMhTBHM= github.com/celestiaorg/nmt v0.21.0/go.mod h1:ia/EpCk0enD5yO5frcxoNoFToz2Ghtk2i+blmCRjIY8= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= -github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -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/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= -github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/cometbft/cometbft-db v0.9.5 h1:ZlIm/peuB9BlRuK01/b/hIIWH2U2m2Q0DNfZ7JmCvhY= +github.com/cometbft/cometbft-db v0.9.5/go.mod h1:Sr3SrYWcAyGvL0HzZMaSJOGMWDEIyiXV1QjCMxM/HNk= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= 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/gorocksdb v1.2.0 h1:d0l3jJG8M4hBouIZq0mDUHZ+zjOx044J3nGRskwTb4Y= -github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creachadair/taskgroup v0.3.2 h1:zlfutDS+5XG40AOxcHDSThxKzns8Tnr9jnr6VqkYlkM= -github.com/creachadair/taskgroup v0.3.2/go.mod h1:wieWwecHVzsidg2CsUnFinW1faVN4+kq+TDlRJQ0Wbk= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= -github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creachadair/taskgroup v0.13.0 h1:VKaW1fi1/Erkkrvx4NvaddzHCGA+hh5QPc5Veiq+joI= +github.com/creachadair/taskgroup v0.13.0/go.mod h1:9oDDPt/5QPS4iylvPMC81GRlj+1je8AFDbjUh4zaQWo= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -161,51 +75,23 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= -github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= -github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE= github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= -github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= -github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= -github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= -github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= -github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= -github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk= -github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= -github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= -github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= -github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -214,22 +100,14 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= -github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= -github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= +github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU= +github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -246,397 +124,192 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= -github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= -github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= -github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY= +github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -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.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +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.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us= github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8= github.com/grafana/otel-profiling-go v0.5.1/go.mod h1:ftN/t5A/4gQI19/8MoWurBEtC6gFw8Dns1sJZ9W4Tls= github.com/grafana/pyroscope-go v1.1.1 h1:PQoUU9oWtO3ve/fgIiklYuGilvsm8qaGhlY4Vw6MAcQ= github.com/grafana/pyroscope-go v1.1.1/go.mod h1:Mw26jU7jsL/KStNSGGuuVYdUq7Qghem5P8aXYXSXG88= github.com/grafana/pyroscope-go/godeltaprof v0.1.6 h1:nEdZ8louGAplSvIJi1HVp7kWvFvdiiYg3COLlTwJiFo= github.com/grafana/pyroscope-go/godeltaprof v0.1.6/go.mod h1:Tk376Nbldo4Cha9RgiU7ik8WKFkNpfds98aUzS8omLE= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= github.com/gtank/merlin v0.1.1 h1:eQ90iG7K9pOhtereWsmyRJ6RAwcP4tHTDBHXNg+u5is= github.com/gtank/merlin v0.1.1/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc= github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/jedib0t/go-pretty/v6 v6.4.7 h1:lwiTJr1DEkAgzljsUsORmWsVn5MQjt1BPJdPCtJ6KXE= github.com/jedib0t/go-pretty/v6 v6.4.7/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs= -github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.17.3 h1:qkRjuerhUU1EmXLYGkSH6EZL+vPSxIrYjLNAK4slzwA= github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= -github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -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.6 h1:O7I6SIGPrypf3f/gmrrLUBQDKfO8uOoYdWf4gLS06tc= -github.com/linxGnu/grocksdb v1.8.6/go.mod h1:xZCIb5Muw+nhbDK4Y5UJuOrin5MceOuiXkVUR7vp4WY= -github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/linxGnu/grocksdb v1.9.3 h1:s1cbPcOd0cU2SKXRG1nEqCOWYAELQjdqg3RVI2MH9ik= +github.com/linxGnu/grocksdb v1.9.3/go.mod h1:QYiYypR2d4v63Wj1adOOfzglnoII0gLj3PNh4fZkcFA= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= -github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0EmT/QLXibWjSUDjKWvXIT19NBVp94= -github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= -github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= -github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= -github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mimoo/StrobeGo v0.0.0-20220103164710-9a04d6ca976b h1:QrHweqAtyJ9EwCaGHBu1fghwxIPiopAHV06JlXrMHjk= +github.com/mimoo/StrobeGo v0.0.0-20220103164710-9a04d6ca976b/go.mod h1:xxLb2ip6sSUts3g1irPVHyk/DGslwQsNOo9I7smJfNU= +github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= +github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg= +github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= -github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= -github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= -github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= -github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oasisprotocol/curve25519-voi v0.0.0-20220708102147-0a8a51822cae h1:FatpGJD2jmJfhZiFDElaC0QhZUDQnxUeAwTGkfAHN3I= github.com/oasisprotocol/curve25519-voi v0.0.0-20220708102147-0a8a51822cae/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s= -github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= -github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= -github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= -github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= -github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= -github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= -github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= -github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= -github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= -github.com/opencontainers/runc v1.1.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b+d8w= -github.com/opencontainers/runc v1.1.3/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= -github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= -github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= -github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/opencontainers/runc v1.2.0-rc.2 h1:5P32s2x9w1gAk20jbkwbQCZCfqVFashCwjD1UL2Ykc4= +github.com/opencontainers/runc v1.2.0-rc.2/go.mod h1:H8njh/SD+WY9bYMmVsEEWDJgJdviOSDjNeXMjeNbYCE= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= -github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= -github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= -github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= -github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= -github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw= +github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= -github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.8.0/go.mod h1:O9VU6huf47PktckDQfMTX0Y8tY0/7TSWwj+ITvv0TnM= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -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.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= -github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= -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= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.59.1 h1:LXb1quJHWm1P6wq/U824uxYi4Sg0oGvNeUm1z5dJoX0= +github.com/prometheus/common v0.59.1/go.mod h1:GpWM7dewqmVYcd7SmRaiWVe9SSqjf0UrwnYnpEZNuT0= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo= -github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= +github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c= github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w= 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= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= -github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk= +github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= -github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= -github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= -github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= -github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU= +github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U= github.com/segmentio/analytics-go v3.1.0+incompatible h1:IyiOfUgQFVHvsykKKbdI7ZsH374uv3/DfZUo9+G0Z80= github.com/segmentio/analytics-go v3.1.0+incompatible/go.mod h1:C7CYBtQWk4vRk2RyLu0qOcbHJ18E3F1HV2C/8JvKN48= github.com/segmentio/backo-go v1.0.1 h1:68RQccglxZeyURy93ASB/2kc9QudzgIDexJ927N++y4= github.com/segmentio/backo-go v1.0.1/go.mod h1:9/Rh6yILuLysoQnZ2oNooD2g7aBnvM7r/fNVxRNWfBc= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -646,28 +319,19 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= -github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= +github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= -github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= -github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/spf13/viper v1.18.1 h1:rmuU42rScKWlhhJDyXZRKJQHXFX02chSVW1IvkPGiVM= -github.com/spf13/viper v1.18.1/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= -github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= 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/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= @@ -675,7 +339,6 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/ 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= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -685,19 +348,10 @@ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o 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.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= -github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= -github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= -github.com/tendermint/tendermint v0.34.14 h1:GCXmlS8Bqd2Ix3TQCpwYLUNHe+Y+QyJsm5YE+S/FkPo= -github.com/tendermint/tendermint v0.34.14/go.mod h1:FrwVm3TvsVicI9Z7FlucHV6Znfd5KBc/Lpp69cCwtk0= -github.com/tendermint/tm-db v0.6.4/go.mod h1:dptYhIpJ2M5kUuenLr+Yyf3zQOv1SgBZcl8/BmWlMBw= -github.com/tendermint/tm-db v0.6.7 h1:fE00Cbl0jayAoqlExN6oyQJ7fR/ZtoVOmvPJ//+shu8= -github.com/tendermint/tm-db v0.6.7/go.mod h1:byQDzFkZV1syXr/ReXS808NxA2xvyuuVgXOJ/088L6I= github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U= github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= @@ -705,187 +359,78 @@ github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JT github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk10Udg= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= -github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c h1:3lbZUMbMiGUW/LMkfsEABsc5zNT9+b1CvsJx47JzJ8g= github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= -go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= -go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= -go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= +go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0= +go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.18.0 h1:hSWWvDjXHVLq9DkmB+77fl8v7+t+yYiS+eNkiplDK54= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.18.0/go.mod h1:zG7KQql1WjZCaUJd+L/ReSYx4bjbYJxg5ws9ws+mYes= -go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= -go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= -go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= -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-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= -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-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= 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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= -golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -893,128 +438,48 @@ golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 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= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= -golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= 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= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:ultW7fxlIvee4HYrtnaRPon9HpEgFk5zYpmfMgtKB5I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.60.0 h1:6FQAR0kM31P6MRdeluor2w2gPaS4SVNrD/DNTxrQ15k= -google.golang.org/grpc v1.60.0/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= 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= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 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= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -1022,15 +487,4 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/heightsync/heightsync.go b/heightsync/heightsync.go deleted file mode 100644 index 834b69e..0000000 --- a/heightsync/heightsync.go +++ /dev/null @@ -1,180 +0,0 @@ -package heightsync - -import ( - "fmt" - "github.com/KYVENetwork/ksync/blocksync" - "github.com/KYVENetwork/ksync/bootstrap" - "github.com/KYVENetwork/ksync/statesync" - "github.com/KYVENetwork/ksync/types" - "github.com/KYVENetwork/ksync/utils" - "strings" - "time" -) - -var ( - logger = utils.KsyncLogger("height-sync") -) - -// PerformHeightSyncValidationChecks checks if the targetHeight lies in the range of available blocks and checks -// if a state-sync snapshot is available right before the targetHeight -func PerformHeightSyncValidationChecks(engine types.Engine, chainRest string, snapshotPoolId int64, blockPoolId *int64, targetHeight int64, userInput bool) (snapshotBundleId, snapshotHeight int64, err error) { - height := engine.GetHeight() - - // only if the app has not indexed any blocks yet we state-sync to the specified startHeight - if height == 0 { - snapshotBundleId, snapshotHeight, _ = statesync.PerformStateSyncValidationChecks(chainRest, snapshotPoolId, targetHeight, false) - } - - continuationHeight := snapshotHeight - if continuationHeight == 0 { - c, err := engine.GetContinuationHeight() - if err != nil { - return 0, 0, fmt.Errorf("failed to get continuation height: %w", err) - } - continuationHeight = c - } - - if err := blocksync.PerformBlockSyncValidationChecks(chainRest, nil, blockPoolId, continuationHeight, targetHeight, true, false); err != nil { - return 0, 0, fmt.Errorf("block-sync validation checks failed: %w", err) - } - - // we ignore if the state-sync validation checks fail because if there are no available snapshots we simply block-sync - // to the targetHeight - snapshotBundleId, snapshotHeight, _ = statesync.PerformStateSyncValidationChecks(chainRest, snapshotPoolId, targetHeight, false) - - if userInput { - answer := "" - if snapshotHeight > 0 { - fmt.Printf("\u001B[36m[KSYNC]\u001B[0m should target height %d be reached by applying snapshot at height %d and syncing the remaining %d blocks [y/N]: ", targetHeight, snapshotHeight, targetHeight-snapshotHeight) - } else { - fmt.Printf("\u001B[36m[KSYNC]\u001B[0m should target height %d be reached by syncing from initial height [y/N]: ", targetHeight) - } - - if _, err := fmt.Scan(&answer); err != nil { - return 0, 0, fmt.Errorf("failed to read in user input: %w", err) - } - - if strings.ToLower(answer) != "y" { - return 0, 0, fmt.Errorf("aborted state-sync") - } - } - - return -} - -func StartHeightSyncWithBinary(engine types.Engine, binaryPath, homePath, chainId, chainRest, storageRest string, snapshotPoolId int64, blockPoolId *int64, targetHeight, snapshotBundleId, snapshotHeight int64, appFlags string, optOut, debug bool) error { - logger.Info().Msg("starting height-sync") - - start := time.Now() - processId := 0 - args := strings.Split(appFlags, ",") - var err error - - // if there are snapshots available before the requested height we apply the nearest - if snapshotHeight > 0 { - // start binary process thread - processId, err = utils.StartBinaryProcessForDB(engine, binaryPath, debug, args) - if err != nil { - return fmt.Errorf("failed to start binary process: %w", err) - } - - if err := engine.OpenDBs(); err != nil { - return fmt.Errorf("failed to open dbs in engine: %w", err) - } - - utils.TrackSyncStartEvent(engine, utils.HEIGHT_SYNC, chainId, chainRest, storageRest, targetHeight, optOut) - - // apply state sync snapshot - if err := statesync.StartStateSyncExecutor(engine, chainRest, storageRest, snapshotPoolId, snapshotBundleId); err != nil { - logger.Error().Msg(fmt.Sprintf("failed to apply state-sync: %s", err)) - - // stop binary process thread - if err := utils.StopProcessByProcessId(processId); err != nil { - return fmt.Errorf("failed to stop process by process id: %w", err) - } - - return fmt.Errorf("failed to start state-sync executor: %w", err) - } - } else { - // if we have to sync from genesis we first bootstrap the node - if err := bootstrap.StartBootstrapWithBinary(engine, binaryPath, homePath, chainRest, storageRest, nil, blockPoolId, appFlags, debug); err != nil { - return fmt.Errorf("failed to bootstrap node: %w", err) - } - - // after the node is bootstrapped we start the binary process thread - processId, err = utils.StartBinaryProcessForDB(engine, binaryPath, debug, args) - if err != nil { - return fmt.Errorf("failed to start binary process: %w", err) - } - - if err := engine.OpenDBs(); err != nil { - return fmt.Errorf("failed to open dbs in engine: %w", err) - } - - utils.TrackSyncStartEvent(engine, utils.HEIGHT_SYNC, chainId, chainRest, storageRest, targetHeight, optOut) - } - - // TODO: does app has to be restarted after a state-sync? - if engine.GetName() == utils.EngineCometBFTV37 || engine.GetName() == utils.EngineCometBFTV38 { - // ignore error, since process gets terminated anyway afterward - e := engine.CloseDBs() - _ = e - - if err := utils.StopProcessByProcessId(processId); err != nil { - return fmt.Errorf("failed to stop binary process: %w", err) - } - - // wait until process has properly shut down - time.Sleep(10 * time.Second) - - processId, err = utils.StartBinaryProcessForDB(engine, binaryPath, debug, args) - if err != nil { - return fmt.Errorf("failed to start binary process: %w", err) - } - - // wait until process has properly started - time.Sleep(10 * time.Second) - - if err := engine.OpenDBs(); err != nil { - logger.Error().Msg(fmt.Sprintf("failed to open dbs in engine: %s", err)) - - // stop binary process thread - if err := utils.StopProcessByProcessId(processId); err != nil { - return fmt.Errorf("failed to stop binary process: %w", err) - } - - return fmt.Errorf("failed to close dbs in engine: %w", err) - } - } - - // if we have not reached our target height yet we block-sync the remaining ones - if remaining := targetHeight - snapshotHeight; remaining > 0 { - logger.Info().Msg(fmt.Sprintf("block-syncing remaining %d blocks", remaining)) - if err := blocksync.StartBlockSyncExecutor(engine, chainRest, storageRest, nil, blockPoolId, targetHeight, 0, 0, false, false, nil); err != nil { - logger.Error().Msg(fmt.Sprintf("failed to apply block-sync: %s", err)) - - // stop binary process thread - if err := utils.StopProcessByProcessId(processId); err != nil { - return fmt.Errorf("failed to stop process by process id: %w", err) - } - - return fmt.Errorf("failed to start block-sync executor: %w", err) - } - } - - elapsed := time.Since(start).Seconds() - utils.TrackSyncCompletedEvent(snapshotHeight, targetHeight-snapshotHeight, targetHeight, elapsed, optOut) - - // stop binary process thread - if err := utils.StopProcessByProcessId(processId); err != nil { - return fmt.Errorf("failed to stop process by process id: %w", err) - } - - if err := engine.CloseDBs(); err != nil { - return fmt.Errorf("failed to close dbs in engine: %w", err) - } - - logger.Info().Msg(fmt.Sprintf("reached target height %d with applying state-sync snapshot at %d and block-syncing the remaining %d blocks in %.2f seconds", targetHeight, snapshotHeight, targetHeight-snapshotHeight, elapsed)) - logger.Info().Msg(fmt.Sprintf("successfully reached target height with height-sync")) - return nil -} diff --git a/images/Dockerfile.kyve b/images/Dockerfile.kyve new file mode 100644 index 0000000..f06be47 --- /dev/null +++ b/images/Dockerfile.kyve @@ -0,0 +1,42 @@ +FROM golang:1.22 + +WORKDIR /app + +RUN apt update && apt upgrade -y + +RUN go install cosmossdk.io/tools/cosmovisor/cmd/cosmovisor@v1.6.0 + +ENV DAEMON_HOME=/root/.kyve +ENV DAEMON_NAME=kyved + +RUN wget -qO- https://github.com/KYVENetwork/chain/releases/download/v1.0.0/kyved_linux_amd64.tar.gz | tar -xzv \ + && ./kyved init ksync --chain-id kyve-1 \ + && wget https://raw.githubusercontent.com/KYVENetwork/networks/main/kyve-1/genesis.json -O ~/.kyve/config/genesis.json \ + && cosmovisor init kyved + +RUN wget -qO- https://github.com/KYVENetwork/chain/releases/download/v1.1.3/kyved_mainnet_linux_amd64.tar.gz | tar -xzv \ + && cosmovisor add-upgrade v1.1.0 kyved + +RUN wget -qO- https://github.com/KYVENetwork/chain/releases/download/v1.2.2/kyved_mainnet_linux_amd64.tar.gz | tar -xzv \ + && cosmovisor add-upgrade v1.2.0 kyved + +RUN wget -qO- https://github.com/KYVENetwork/chain/releases/download/v1.3.2/kyved_mainnet_linux_amd64.tar.gz | tar -xzv \ + && cosmovisor add-upgrade v1.3.0 kyved + +RUN wget -qO- https://github.com/KYVENetwork/chain/releases/download/v1.4.0/kyved_mainnet_linux_amd64.tar.gz | tar -xzv \ + && cosmovisor add-upgrade v1.4.0 kyved + +RUN wget https://github.com/KYVENetwork/chain/releases/download/v1.5.0/kyved_mainnet_linux_amd64 -O kyved \ + && chmod +x kyved \ + && cosmovisor add-upgrade v1.5.0 kyved + +RUN rm kyved + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . + +RUN make build + +CMD ["/bin/sh", "-c", "if [ ! -f /app/.first_run ]; then echo 'First run detected. Initializing...'; touch /app/.first_run; /app/build/ksync height-sync -b cosmovisor -c kaon-1 --opt-out -a -y -r -d -t ${TARGET_HEIGHT}; else echo 'Subsequent run detected. Skipping initialization...'; fi && exec cosmovisor run start --rpc.laddr='tcp://0.0.0.0:26657' --api.enable=true"] diff --git a/logger/logger.go b/logger/logger.go new file mode 100644 index 0000000..93b67c2 --- /dev/null +++ b/logger/logger.go @@ -0,0 +1,34 @@ +package logger + +import ( + "fmt" + "github.com/rs/zerolog" + "io" + "os" +) + +var ( + Logger = NewLogger("KSYNC") +) + +func init() { + zerolog.SetGlobalLevel(zerolog.InfoLevel) +} + +func NewLogger(name string, keyvals ...interface{}) zerolog.Logger { + writer := io.MultiWriter(os.Stdout) + customConsoleWriter := zerolog.ConsoleWriter{Out: writer} + customConsoleWriter.FormatCaller = func(i interface{}) string { + return fmt.Sprintf("\x1b[36m[%s]\x1b[0m", name) + } + + loggerWith := zerolog.New(customConsoleWriter).With() + + if len(keyvals) > 1 { + for i := 0; i < len(keyvals); i = i + 2 { + loggerWith = loggerWith.Str(fmt.Sprintf("%v", keyvals[i]), fmt.Sprintf("%v", keyvals[i+1])) + } + } + + return loggerWith.Timestamp().Logger() +} diff --git a/metrics/metrics.go b/metrics/metrics.go new file mode 100644 index 0000000..790c95c --- /dev/null +++ b/metrics/metrics.go @@ -0,0 +1,314 @@ +package metrics + +import ( + "fmt" + "github.com/KYVENetwork/ksync/flags" + "github.com/KYVENetwork/ksync/logger" + "github.com/google/uuid" + "github.com/segmentio/analytics-go" + "os" + "os/signal" + "path/filepath" + "runtime" + runtimeDebug "runtime/debug" + "strings" + "syscall" + "time" +) + +const ( + SegmentWriteKey = "aTXiSVqhrmavVNbF2M61pyBDF4stWHgf" +) + +var ( + command = "ksync" + interrupt = false + startTime = time.Now() + sourceId string + userConfirmationInput string + userConfirmationDuration time.Duration + continuationHeight int64 + snapshotHeight int64 + latestHeight int64 + successfulRequests int64 + failedRequests int64 +) + +func SetCommand(_command string) { + command = _command +} + +func SetSourceId(_sourceId string) { + sourceId = _sourceId +} + +func SetUserConfirmationInput(_userConfirmationInput string) { + userConfirmationInput = _userConfirmationInput +} + +func SetUserConfirmationDuration(_userConfirmationDuration time.Duration) { + userConfirmationDuration = _userConfirmationDuration +} + +func SetContinuationHeight(_continuationHeight int64) { + continuationHeight = _continuationHeight +} + +func SetSnapshotHeight(_snapshotHeight int64) { + snapshotHeight = _snapshotHeight +} + +func SetLatestHeight(_latestHeight int64) { + latestHeight = _latestHeight +} + +func IncreaseSuccessfulRequests() { + successfulRequests++ +} + +func IncreaseFailedRequests() { + failedRequests++ +} + +// GetSyncDuration gets the sync time duration. +// We subtract the user confirmation duration +// since this time was not spent on actually syncing the node +func GetSyncDuration() time.Duration { + return time.Since(startTime.Add(userConfirmationDuration)) +} + +func GetInterrupt() bool { + return interrupt +} + +func getVersion() string { + version, ok := runtimeDebug.ReadBuildInfo() + if !ok { + panic("failed to get ksync version") + } + + if version.Main.Version == "" { + return "dev" + } + + return strings.TrimSpace(version.Main.Version) +} + +func getGoVersion() string { + version, ok := runtimeDebug.ReadBuildInfo() + if !ok { + panic("failed to get go version") + } + + return version.GoVersion +} + +func getUserId() (string, error) { + // we identify a KSYNC user by their local id file which is stored + // under "$HOME/.ksync/id". If the id file was not created yet + // or got deleted we create a new one + home, err := os.UserHomeDir() + if err != nil { + return "", err + } + + ksyncDir := filepath.Join(home, ".ksync") + + // if ksync home directory does not exist we create it + if _, err = os.Stat(ksyncDir); os.IsNotExist(err) { + if err := os.Mkdir(ksyncDir, 0o755); err != nil { + return "", err + } + } + + idFile := filepath.Join(ksyncDir, "id") + + // if id file does not exist we create a new user id and store it + if _, err = os.Stat(idFile); os.IsNotExist(err) { + newUserId := uuid.New().String() + + if err := os.WriteFile(idFile, []byte(newUserId), 0o755); err != nil { + return "", err + } + + return newUserId, nil + } + + // if id file exists read the contents + data, err := os.ReadFile(idFile) + if err != nil { + return "", err + } + + return string(data), nil +} + +func getContext() *analytics.Context { + timezone, _ := time.Now().Zone() + locale := os.Getenv("LANG") + + return &analytics.Context{ + App: analytics.AppInfo{ + Name: "ksync", + Version: getVersion(), + }, + Location: analytics.LocationInfo{}, + OS: analytics.OSInfo{ + Name: fmt.Sprintf("%s-%s", runtime.GOOS, runtime.GOARCH), + }, + Locale: locale, + Timezone: timezone, + } +} + +func getProperties(errorRuntime error) analytics.Properties { + properties := analytics.NewProperties() + + // set flag properties (all must start with "flag_") + properties.Set("flag_binary_path", flags.BinaryPath) + properties.Set("flag_home_path", flags.HomePath) + properties.Set("flag_chain_id", flags.ChainId) + properties.Set("flag_chain_rest", flags.ChainRest) + properties.Set("flag_storage_rest", flags.StorageRest) + properties.Set("flag_block_rpc", flags.BlockRpc) + properties.Set("flag_snapshot_pool_id", flags.SnapshotPoolId) + properties.Set("flag_block_pool_id", flags.BlockPoolId) + properties.Set("flag_start_height", flags.StartHeight) + properties.Set("flag_target_height", flags.TargetHeight) + properties.Set("flag_rpc_server", flags.RpcServer) + properties.Set("flag_rpc_server_port", flags.RpcServerPort) + properties.Set("flag_snapshot_port", flags.SnapshotPort) + properties.Set("flag_block_rpc_req_timeout", flags.BlockRpcReqTimeout) + properties.Set("flag_pruning", flags.Pruning) + properties.Set("flag_keep_snapshots", flags.KeepSnapshots) + properties.Set("flag_skip_waiting", flags.SkipWaiting) + properties.Set("flag_app_logs", flags.AppLogs) + properties.Set("flag_auto_select_binary_version", flags.AutoSelectBinaryVersion) + properties.Set("flag_keep_addr_book", flags.KeepAddrBook) + properties.Set("flag_opt_out", flags.OptOut) + properties.Set("flag_debug", flags.Debug) + properties.Set("flag_y", flags.Y) + + // set metric properties (all must start with "metric_") + properties.Set("metrics_total_duration", time.Since(startTime).Milliseconds()) + properties.Set("metrics_source_id", sourceId) + properties.Set("metrics_user_confirmation_input", userConfirmationInput) + properties.Set("metrics_user_confirmation_duration", userConfirmationDuration.Milliseconds()) + properties.Set("metrics_continuation_height", continuationHeight) + properties.Set("metrics_snapshot_height", snapshotHeight) + properties.Set("metrics_latest_height", latestHeight) + properties.Set("metrics_sync_duration", GetSyncDuration().Milliseconds()) + properties.Set("metrics_successful_requests", successfulRequests) + properties.Set("metrics_failed_requests", failedRequests) + + if latestHeight > continuationHeight-1 { + properties.Set("metrics_blocks_synced", latestHeight-(continuationHeight-1)) + } else { + properties.Set("metrics_blocks_synced", 0) + } + + // set error properties (all must start with "error_") + if errorRuntime == nil { + properties.Set("error_runtime", "") + } else { + properties.Set("error_runtime", errorRuntime.Error()) + } + + properties.Set("error_interrupt", interrupt) + + // set status properties (all must start with "status_") + if command == "block-sync" || command == "height-sync" || command == "serve-blocks" || command == "serve-snapshots" { + reachedTargetHeight := flags.TargetHeight > 0 && latestHeight == flags.TargetHeight && errorRuntime == nil + properties.Set("status_reached_target_height", reachedTargetHeight) + } else if command == "state-sync" { + reachedTargetHeight := latestHeight > 0 && errorRuntime == nil + properties.Set("status_reached_target_height", reachedTargetHeight) + } else { + properties.Set("status_reached_target_height", false) + } + + snapshotApplied := snapshotHeight > 0 && errorRuntime == nil + properties.Set("status_snapshot_applied", snapshotApplied) + + userConfirmationAborted := userConfirmationDuration.Milliseconds() > 0 && strings.ToLower(userConfirmationInput) != "y" + properties.Set("status_user_confirmation_aborted", userConfirmationAborted) + + // set build properties (all must start with "build_") + properties.Set("build_go_version", getGoVersion()) + properties.Set("build_os_name", runtime.GOOS) + properties.Set("build_os_arch", runtime.GOARCH) + + return properties +} + +// CatchInterrupt catches interrupt signals from Ctrl+C ensures +// that metrics are sent before KSYNC exits +func CatchInterrupt() { + c := make(chan os.Signal) + signal.Notify(c, os.Interrupt, syscall.SIGTERM) + + go func() { + <-c + logger.Logger.Info().Msg("received interrupt signal, shutting down KSYNC") + SendTrack(fmt.Errorf("INTERRUPT")) + + os.Exit(1) + }() +} + +// WaitForInterrupt waits indefinitely until KSYNC gets exited in +// CatchInterrupt after the metrics have been sent. We wait or else +// KSYNC may exit before the metrics have been properly send +func WaitForInterrupt() { + if interrupt { + <-(chan int)(nil) + } +} + +func SendTrack(errorRuntime error) { + // if the user opts out we return immediately + if flags.OptOut { + logger.Logger.Debug().Msg("opting-out of metric collection") + return + } + + // if KSYNC received an interrupt before we do not send another + // track message + if interrupt { + return + } + + // if the runtime error indicates an interrupt we set the interrupt + // value for later + if errorRuntime != nil && errorRuntime.Error() == "INTERRUPT" { + errorRuntime = nil + interrupt = true + } + + userId, err := getUserId() + if err != nil { + logger.Logger.Debug().Err(err).Msg("failed to get user id") + return + } + + message := analytics.Track{ + UserId: userId, + Event: command, + Context: getContext(), + Properties: getProperties(errorRuntime), + } + + client := analytics.New(SegmentWriteKey) + + if err := client.Enqueue(message); err != nil { + logger.Logger.Debug().Err(err).Msg("failed to enqueue track message") + return + } + + if err := client.Close(); err != nil { + logger.Logger.Debug().Err(err).Msg("failed to close client") + return + } + + logger.Logger.Debug().Str("event", message.Event).Str("userId", message.UserId).Any("context", message.Context).Any("properties", message.Properties).Msg("sent track message") +} diff --git a/servesnapshots/servesnapshots.go b/servesnapshots/servesnapshots.go deleted file mode 100644 index 5d3d78f..0000000 --- a/servesnapshots/servesnapshots.go +++ /dev/null @@ -1,204 +0,0 @@ -package servesnapshots - -import ( - "encoding/json" - "fmt" - "github.com/KYVENetwork/ksync/blocksync" - "github.com/KYVENetwork/ksync/bootstrap" - "github.com/KYVENetwork/ksync/collectors/pool" - "github.com/KYVENetwork/ksync/server" - "github.com/KYVENetwork/ksync/statesync" - "github.com/KYVENetwork/ksync/types" - "github.com/KYVENetwork/ksync/utils" - "strconv" - "strings" - "time" -) - -var ( - logger = utils.KsyncLogger("serve-snapshots") -) - -// PerformServeSnapshotsValidationChecks checks if the targetHeight lies in the range of available blocks and checks -// if a state-sync snapshot is available right before the startHeight -func PerformServeSnapshotsValidationChecks(engine types.Engine, chainRest string, snapshotPoolId, blockPoolId, startHeight, targetHeight int64) (snapshotBundleId, snapshotHeight int64, err error) { - height := engine.GetHeight() - - // only if the app has not indexed any blocks yet we state-sync to the specified startHeight - if height == 0 { - snapshotBundleId, snapshotHeight, _ = statesync.PerformStateSyncValidationChecks(chainRest, snapshotPoolId, startHeight, false) - } - - continuationHeight := snapshotHeight - if continuationHeight == 0 { - c, err := engine.GetContinuationHeight() - if err != nil { - return 0, 0, fmt.Errorf("failed to get continuation height: %w", err) - } - continuationHeight = c - } - - if err := blocksync.PerformBlockSyncValidationChecks(chainRest, nil, &blockPoolId, continuationHeight, targetHeight, false, false); err != nil { - return 0, 0, fmt.Errorf("block-sync validation checks failed: %w", err) - } - - return -} - -func StartServeSnapshotsWithBinary(engine types.Engine, binaryPath, homePath, chainRest, storageRest string, blockPoolId *int64, snapshotPoolId, targetHeight, height, snapshotBundleId, snapshotHeight, snapshotPort int64, appFlags string, rpcServer, pruning, keepSnapshots, skipWaiting, debug bool) error { - logger.Info().Msg("starting serve-snapshots") - - if pruning && skipWaiting { - return fmt.Errorf("pruning has to be disabled with --pruning=false if --skip-waiting is true") - } - - // get snapshot interval from pool - var config types.TendermintSSyncConfig - snapshotPool, err := pool.GetPoolInfo(chainRest, snapshotPoolId) - - if err := json.Unmarshal([]byte(snapshotPool.Pool.Data.Config), &config); err != nil { - return fmt.Errorf("failed to read pool config: %w", err) - } - - logger.Info().Msg(fmt.Sprintf("found snapshot interval of %d on snapshot pool", config.Interval)) - - snapshotArgs := append(strings.Split(appFlags, ","), "--state-sync.snapshot-interval", strconv.FormatInt(config.Interval, 10)) - - if pruning { - snapshotArgs = append( - snapshotArgs, - "--pruning", - "custom", - "--pruning-keep-recent", - strconv.FormatInt(utils.SnapshotPruningWindowFactor*config.Interval, 10), - "--pruning-interval", - "10", - ) - - if keepSnapshots { - snapshotArgs = append( - snapshotArgs, - "--state-sync.snapshot-keep-recent", - "0", - ) - } else { - snapshotArgs = append( - snapshotArgs, - "--state-sync.snapshot-keep-recent", - strconv.FormatInt(utils.SnapshotPruningWindowFactor, 10), - ) - } - } else { - snapshotArgs = append( - snapshotArgs, - "--state-sync.snapshot-keep-recent", - "0", - "--pruning", - "nothing", - ) - } - - processId := 0 - - if height == 0 && snapshotHeight > 0 { - // start binary process thread - processId, err = utils.StartBinaryProcessForDB(engine, binaryPath, debug, snapshotArgs) - if err != nil { - return fmt.Errorf("failed to start binary process: %w", err) - } - - if err := engine.OpenDBs(); err != nil { - return fmt.Errorf("failed to open dbs in engine: %w", err) - } - - // found snapshot, applying it and continuing block-sync from here - if err := statesync.StartStateSyncExecutor(engine, chainRest, storageRest, snapshotPoolId, snapshotBundleId); err != nil { - logger.Error().Msg(fmt.Sprintf("state-sync failed with: %s", err)) - - // stop binary process thread - if err := utils.StopProcessByProcessId(processId); err != nil { - return fmt.Errorf("failed to stop process by process id: %w", err) - } - - return fmt.Errorf("failed to start state-sync executor: %w", err) - } - - // TODO: does app has to be restarted after a state-sync? - if engine.GetName() == utils.EngineCometBFTV37 || engine.GetName() == utils.EngineCometBFTV38 { - // ignore error, since process gets terminated anyway afterward - e := engine.CloseDBs() - _ = e - - if err := utils.StopProcessByProcessId(processId); err != nil { - return fmt.Errorf("failed to stop process by process id: %w", err) - } - - // wait until process has properly shut down - time.Sleep(10 * time.Second) - - processId, err = utils.StartBinaryProcessForDB(engine, binaryPath, debug, snapshotArgs) - if err != nil { - return fmt.Errorf("failed to start process: %w", err) - } - - // wait until process has properly started - time.Sleep(10 * time.Second) - - if err := engine.OpenDBs(); err != nil { - logger.Error().Msg(fmt.Sprintf("failed to open dbs in engine: %s", err)) - - // stop binary process thread - if err := utils.StopProcessByProcessId(processId); err != nil { - return fmt.Errorf("failed to stop process by process id: %w", err) - } - - return fmt.Errorf("failed to open dbs in engine: %w", err) - } - } - } else { - // if we have to sync from genesis we first bootstrap the node - if err := bootstrap.StartBootstrapWithBinary(engine, binaryPath, homePath, chainRest, storageRest, nil, blockPoolId, appFlags, debug); err != nil { - return fmt.Errorf("failed to bootstrap node: %w", err) - } - - // after the node is bootstrapped we start the binary process thread - processId, err = utils.StartBinaryProcessForDB(engine, binaryPath, debug, snapshotArgs) - if err != nil { - return fmt.Errorf("failed to start binary process: %w", err) - } - - if err := engine.OpenDBs(); err != nil { - return fmt.Errorf("failed to open dbs in engine: %w", err) - } - } - - if rpcServer { - go engine.StartRPCServer() - } - - go server.StartSnapshotApiServer(engine, snapshotPort) - - // db executes blocks against app until target height - if err := blocksync.StartBlockSyncExecutor(engine, chainRest, storageRest, nil, blockPoolId, targetHeight, snapshotPoolId, config.Interval, pruning, skipWaiting, nil); err != nil { - logger.Error().Msg(fmt.Sprintf("failed to start db executor: %s", err)) - - // stop binary process thread - if err := utils.StopProcessByProcessId(processId); err != nil { - return fmt.Errorf("failed to stop process by process id: %w", err) - } - - return fmt.Errorf("failed to start block-sync executor: %w", err) - } - - // stop binary process thread - if err := utils.StopProcessByProcessId(processId); err != nil { - return fmt.Errorf("failed to stop process by process id: %w", err) - } - - if err := engine.CloseDBs(); err != nil { - return fmt.Errorf("failed to close dbs in engine: %w", err) - } - - logger.Info().Msg(fmt.Sprintf("finished serve-snapshots")) - return nil -} diff --git a/sources/sources.go b/sources/sources.go deleted file mode 100644 index 1e82401..0000000 --- a/sources/sources.go +++ /dev/null @@ -1,82 +0,0 @@ -package sources - -import ( - _ "embed" - "fmt" - "github.com/KYVENetwork/ksync/sources/helpers" - "github.com/KYVENetwork/ksync/types" - "github.com/KYVENetwork/ksync/utils" - "strconv" -) - -func FormatOutput(entry *types.Entry, chainId string) (string, string, string) { - var blockKey, stateKey, heightKey string - if chainId == utils.ChainIdMainnet && entry.Networks.Kyve != nil { - blockKey, stateKey, heightKey = helpers.FormatKeys(entry.Networks.Kyve.BlockStartKey, entry.Networks.Kyve.LatestBlockKey, entry.Networks.Kyve.StateStartKey, entry.Networks.Kyve.LatestStateKey) - } else if chainId == utils.ChainIdKaon && entry.Networks.Kaon != nil { - blockKey, stateKey, heightKey = helpers.FormatKeys(entry.Networks.Kaon.BlockStartKey, entry.Networks.Kaon.LatestBlockKey, entry.Networks.Kaon.StateStartKey, entry.Networks.Kaon.LatestStateKey) - } - return blockKey, stateKey, heightKey -} - -func GetPoolIds(chainId, source, blockPoolId, snapshotPoolId, registryUrl string, blockPoolRequired, snapshotPoolRequired bool) (int64, int64, error) { - if source == "" && blockPoolId == "" && blockPoolRequired { - return 0, 0, fmt.Errorf("either --source or --block-pool-id are required") - } - if source == "" && snapshotPoolId == "" && snapshotPoolRequired { - return 0, 0, fmt.Errorf("either --source or --snapshot-pool-id are required") - } - - var bId, sId int64 - - if source != "" { - bIdRaw, sIdRaw, err := getPoolsBySource(chainId, source, registryUrl) - if err != nil { - return 0, 0, fmt.Errorf("failed to load pool Ids for source %s from %s: %w", source, registryUrl, err) - } - - if bIdRaw == nil { - return 0, 0, fmt.Errorf("source %s does not contain a block-pool", source) - } - if sIdRaw == nil && snapshotPoolRequired { - return 0, 0, fmt.Errorf("source %s does not contain a snapshot-pool", source) - } - bId = int64(*bIdRaw) - - if sIdRaw != nil { - sId = int64(*sIdRaw) - } - } - - if blockPoolId != "" { - var err error - bId, err = strconv.ParseInt(blockPoolId, 10, 64) - if err != nil { - return 0, 0, err - } - } - if snapshotPoolId != "" { - var err error - sId, err = strconv.ParseInt(snapshotPoolId, 10, 64) - if err != nil { - return 0, 0, err - } - } - return bId, sId, nil -} - -func getPoolsBySource(chainId, source, registryUrl string) (*int, *int, error) { - if chainId != utils.ChainIdMainnet && chainId != utils.ChainIdKaon { - return nil, nil, fmt.Errorf("chain ID %s is not supported", chainId) - } - - entry, err := helpers.GetSourceRegistryEntry(registryUrl, source) - if err != nil { - return nil, nil, fmt.Errorf("failed to get source registry entry: %v", err) - } - - if chainId == utils.ChainIdMainnet { - return entry.Networks.Kyve.Integrations.KSYNC.BlockSyncPool, entry.Networks.Kyve.Integrations.KSYNC.StateSyncPool, nil - } - return entry.Networks.Kaon.Integrations.KSYNC.BlockSyncPool, entry.Networks.Kaon.Integrations.KSYNC.StateSyncPool, nil -} diff --git a/sources/version.go b/sources/version.go deleted file mode 100644 index 7d16d1c..0000000 --- a/sources/version.go +++ /dev/null @@ -1,138 +0,0 @@ -package sources - -import ( - "fmt" - "github.com/KYVENetwork/ksync/sources/helpers" - log "github.com/KYVENetwork/ksync/utils" - "os" - "os/exec" - "strconv" - "strings" -) - -var ( - logger = log.KsyncLogger("sources") -) - -func SelectCosmovisorVersion(binaryPath, homePath, registryUrl, source string, continuationHeight int64) error { - if !strings.HasSuffix(binaryPath, "cosmovisor") || source == "" { - return nil - } - - var upgradeName string - - entry, err := helpers.GetSourceRegistryEntry(registryUrl, source) - if err != nil { - return fmt.Errorf("failed to get source registry entry: %w", err) - } - - for _, upgrade := range entry.Codebase.Settings.Upgrades { - height, err := strconv.ParseInt(upgrade.Height, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse upgrade height %s: %w", upgrade.Height, err) - } - - if continuationHeight < height { - break - } - - upgradeName = upgrade.Name - } - - if upgradeName == "genesis" { - if _, err := os.Stat(fmt.Sprintf("%s/cosmovisor/%s", homePath, upgradeName)); err != nil { - return fmt.Errorf("\"%s\" not installed in cosmovisor", upgradeName) - } - } else { - if _, err := os.Stat(fmt.Sprintf("%s/cosmovisor/upgrades/%s", homePath, upgradeName)); err != nil { - return fmt.Errorf("upgrade \"%s\" not installed in cosmovisor", upgradeName) - } - } - - symlinkPath := fmt.Sprintf("%s/cosmovisor/current", homePath) - - if _, err := os.Lstat(symlinkPath); err == nil { - if err := os.Remove(symlinkPath); err != nil { - return fmt.Errorf("failed to remove symlink from path %s: %w", symlinkPath, err) - } - } - - if upgradeName == "genesis" { - if err := os.Symlink(fmt.Sprintf("%s/cosmovisor/%s", homePath, upgradeName), symlinkPath); err != nil { - return fmt.Errorf("failed to create symlink: %w", err) - } - } else { - if err := os.Symlink(fmt.Sprintf("%s/cosmovisor/upgrades/%s", homePath, upgradeName), symlinkPath); err != nil { - return fmt.Errorf("failed to create symlink: %w", err) - } - } - - logger.Info().Msgf("selected binary version \"%s\" from height %d for cosmovisor", upgradeName, continuationHeight) - return nil -} - -func IsBinaryRecommendedVersion(binaryPath, registryUrl, source string, continuationHeight int64, userInput bool) error { - if binaryPath == "" || source == "" || !userInput { - return nil - } - - cmdPath, err := exec.LookPath(binaryPath) - if err != nil { - return fmt.Errorf("failed to lookup binary path: %w", err) - } - - cmd := exec.Command(cmdPath) - - // if we run with cosmovisor we start with the cosmovisor run command - if strings.HasSuffix(binaryPath, "cosmovisor") { - cmd.Args = append(cmd.Args, "run") - cmd.Env = append(os.Environ(), "COSMOVISOR_DISABLE_LOGS=true") - } - - cmd.Args = append(cmd.Args, "version") - - out, err := cmd.CombinedOutput() - if err != nil { - return fmt.Errorf("failed to get output of binary: %w", err) - } - - binaryVersion := strings.TrimSuffix(string(out), "\n") - binaryVersionFormatted := fmt.Sprintf("v%s", binaryVersion) - - var recommendedVersion string - - entry, err := helpers.GetSourceRegistryEntry(registryUrl, source) - if err != nil { - return fmt.Errorf("failed to get source registry entry: %w", err) - } - - for _, upgrade := range entry.Codebase.Settings.Upgrades { - height, err := strconv.ParseInt(upgrade.Height, 10, 64) - if err != nil { - return fmt.Errorf("failed to parse upgrade height %s: %w", upgrade.Height, err) - } - - if continuationHeight < height { - break - } - - recommendedVersion = upgrade.RecommendedVersion - } - - if binaryVersion == recommendedVersion || binaryVersionFormatted == recommendedVersion { - return nil - } - - fmt.Printf("\u001B[36m[KSYNC]\u001B[0m The recommended binary version for the current height %d is %s while the provided binary has the following version: %s. Proceed anyway? [y/N]: ", continuationHeight, recommendedVersion, binaryVersion) - - answer := "" - if _, err := fmt.Scan(&answer); err != nil { - return fmt.Errorf("failed to read user input: %w", err) - } - - if strings.ToLower(answer) != "y" { - return fmt.Errorf("abort") - } - - return nil -} diff --git a/statesync/executor.go b/statesync/executor.go deleted file mode 100644 index 155bf33..0000000 --- a/statesync/executor.go +++ /dev/null @@ -1,82 +0,0 @@ -package statesync - -import ( - "fmt" - "github.com/KYVENetwork/ksync/collectors/bundles" - "github.com/KYVENetwork/ksync/types" - "github.com/KYVENetwork/ksync/utils" -) - -// StartStateSyncExecutor takes the bundle id of the first snapshot chunk and applies the snapshot from there -func StartStateSyncExecutor(engine types.Engine, chainRest, storageRest string, snapshotPoolId, snapshotBundleId int64) error { - logger.Info().Msg(fmt.Sprintf("applying state-sync snapshot")) - - appHeight, err := engine.GetAppHeight() - if err != nil { - return fmt.Errorf("requesting height from app failed: %w", err) - } - - if appHeight > 0 { - return fmt.Errorf("app height %d is not zero, please reset with \"ksync reset-all\" or run the command with \"--reset-all\"", appHeight) - } - - finalizedBundle, err := bundles.GetFinalizedBundleById(chainRest, snapshotPoolId, snapshotBundleId) - if err != nil { - return fmt.Errorf("failed getting finalized bundle: %w", err) - } - - snapshotHeight, _, err := utils.ParseSnapshotFromKey(finalizedBundle.ToKey) - if err != nil { - return fmt.Errorf("failed getting snapshot height from to_key %s: %w", finalizedBundle.ToKey, err) - } - - deflated, err := bundles.GetDataFromFinalizedBundle(*finalizedBundle, storageRest) - if err != nil { - return fmt.Errorf("failed getting data from finalized bundle: %w", err) - } - - res, chunks, err := engine.OfferSnapshot(deflated) - if err != nil { - return fmt.Errorf("offering snapshot failed: %w", err) - } - - if res == "ACCEPT" { - logger.Info().Msg(fmt.Sprintf("offering snapshot for height %d: %s", snapshotHeight, res)) - } else { - logger.Error().Msg(fmt.Sprintf("offering snapshot for height %d failed: %s", snapshotHeight, res)) - return fmt.Errorf("offering snapshot result: %s", res) - } - - for chunkIndex := uint32(0); chunkIndex < chunks; chunkIndex++ { - chunkBundleFinalized, err := bundles.GetFinalizedBundleById(chainRest, snapshotPoolId, snapshotBundleId+int64(chunkIndex)) - if err != nil { - return fmt.Errorf("failed getting finalized bundle: %w", err) - } - - chunkBundleDeflated, err := bundles.GetDataFromFinalizedBundle(*chunkBundleFinalized, storageRest) - if err != nil { - return fmt.Errorf("failed getting data from finalized bundle: %w", err) - } - - logger.Info().Msg(fmt.Sprintf("downloaded snapshot chunk %d/%d", chunkIndex+1, chunks)) - - res, err := engine.ApplySnapshotChunk(chunkIndex, chunkBundleDeflated) - if err != nil { - logger.Error().Msg(fmt.Sprintf("applying snapshot chunk %d/%d failed: %s", chunkIndex+1, chunks, err)) - return err - } - - if res == "ACCEPT" { - logger.Info().Msg(fmt.Sprintf("applying snapshot chunk %d/%d: %s", chunkIndex+1, chunks, res)) - } else { - logger.Error().Msg(fmt.Sprintf("applying snapshot chunk %d/%d failed: %s", chunkIndex+1, chunks, res)) - return fmt.Errorf("applying snapshot chunk: %s", res) - } - } - - if err := engine.BootstrapState(deflated); err != nil { - return fmt.Errorf("failed to bootstrap state: %s\"", err) - } - - return nil -} diff --git a/statesync/helpers/helpers.go b/statesync/helpers/helpers.go deleted file mode 100644 index 56944e0..0000000 --- a/statesync/helpers/helpers.go +++ /dev/null @@ -1,99 +0,0 @@ -package helpers - -import ( - "fmt" - "github.com/KYVENetwork/ksync/collectors/bundles" - "github.com/KYVENetwork/ksync/collectors/pool" - "github.com/KYVENetwork/ksync/utils" - "strconv" - "strings" -) - -// GetSnapshotPoolHeight returns the height of the snapshot the pool is currently archiving. -// Note that this snapshot can be not complete since for the state-sync to work all chunks have -// to be available. -func GetSnapshotPoolHeight(restEndpoint string, poolId int64) int64 { - snapshotPool, err := pool.GetPoolInfo(restEndpoint, poolId) - if err != nil { - panic(fmt.Errorf("could not get snapshot pool: %w", err)) - } - - var snapshotHeight int64 - - if snapshotPool.Pool.Data.CurrentKey == "" { - snapshotHeight, _, err = utils.ParseSnapshotFromKey(snapshotPool.Pool.Data.StartKey) - if err != nil { - panic(fmt.Errorf("could not parse snapshot height from start key: %w", err)) - } - } else { - snapshotHeight, _, err = utils.ParseSnapshotFromKey(snapshotPool.Pool.Data.CurrentKey) - if err != nil { - panic(fmt.Errorf("could not parse snapshot height from current key: %w", err)) - } - } - - return snapshotHeight -} - -// GetSnapshotBoundaries returns the snapshot heights for the lowest complete snapshot and the -// highest complete snapshot. A complete snapshot contains all chunks of the snapshot, a snapshot which is currently -// still being archived can have the latest chunks missing, therefore being not usable. -func GetSnapshotBoundaries(restEndpoint string, poolId int64) (startHeight int64, endHeight int64, err error) { - // load start and latest height - poolResponse, err := pool.GetPoolInfo(restEndpoint, poolId) - if err != nil { - return startHeight, endHeight, fmt.Errorf("failed to get pool info: %w", err) - } - - if poolResponse.Pool.Data.Runtime != utils.KSyncRuntimeTendermintSsync { - return startHeight, endHeight, fmt.Errorf("found invalid runtime on state-sync pool %d: Expected = %s Found = %s", poolId, utils.KSyncRuntimeTendermintSsync, poolResponse.Pool.Data.Runtime) - } - - // if no bundles have been created yet or if the current key is empty - // is no complete snapshot on the pool yet - if poolResponse.Pool.Data.TotalBundles == 0 || poolResponse.Pool.Data.CurrentKey == "" { - return startHeight, endHeight, fmt.Errorf("pool has not produced any bundles yet and therefore has no complete snapshots available") - } - - startHeight, _, err = utils.ParseSnapshotFromKey(poolResponse.Pool.Data.StartKey) - if err != nil { - return startHeight, endHeight, fmt.Errorf("failed to parse snapshot start key %s: %w", poolResponse.Pool.Data.StartKey, err) - } - - _, chunkIndex, err := utils.ParseSnapshotFromKey(poolResponse.Pool.Data.CurrentKey) - if err != nil { - return startHeight, endHeight, fmt.Errorf("failed to parse snapshot current key %s: %w", poolResponse.Pool.Data.CurrentKey, err) - } - - // to get the current bundle id we subtract 1 from the total bundles and - // in order to get the last chunk of the previous complete snapshot we go back - // all the chunks + 1 - // since it is the goal to get the highest complete snapshot we start at the current bundle id - // (poolResponse.Pool.Data.TotalBundles - 1) and go back to the snapshot before that since we know - // that the snapshot before the current one has to be completed (- (chunkIndex +1)) - highestUsableSnapshotBundleId := poolResponse.Pool.Data.TotalBundles - 1 - (chunkIndex + 1) - - // check if the current chunk is the last chunk of the snapshot, if yes we highestUsableSnapshotBundleId - // is the current one. we check this by comparing the number of chunks from the bundle summary with the - // current chunk index from the current key. - summary := strings.Split(poolResponse.Pool.Data.CurrentSummary, "/") - // bundle summary format is "height/format/chunkIndex/chunks" - // if the summary does not have the right format we skip because this is probably a legacy bundle summary. - if len(summary) == 4 { - if chunks, _ := strconv.ParseInt(summary[3], 10, 64); chunks == chunkIndex+1 { - highestUsableSnapshotBundleId = poolResponse.Pool.Data.TotalBundles - 1 - } - } - - bundle, err := bundles.GetFinalizedBundleById(restEndpoint, poolId, highestUsableSnapshotBundleId) - if err != nil { - return startHeight, endHeight, fmt.Errorf("failed to get finalized bundle with id %d: %w", highestUsableSnapshotBundleId, err) - } - - endHeight, _, err = utils.ParseSnapshotFromKey(bundle.ToKey) - if err != nil { - return startHeight, endHeight, fmt.Errorf("failed to parse snapshot key %s: %w", bundle.ToKey, err) - } - - return -} diff --git a/statesync/statesync.go b/statesync/statesync.go deleted file mode 100644 index 4c25d44..0000000 --- a/statesync/statesync.go +++ /dev/null @@ -1,116 +0,0 @@ -package statesync - -import ( - "errors" - "fmt" - "github.com/KYVENetwork/ksync/collectors/snapshots" - "github.com/KYVENetwork/ksync/statesync/helpers" - "github.com/KYVENetwork/ksync/types" - "github.com/KYVENetwork/ksync/utils" - "strings" - "time" -) - -var ( - logger = utils.KsyncLogger("state-sync") -) - -// PerformStateSyncValidationChecks checks if a snapshot is available for the targetHeight and if not returns -// the nearest available snapshot below the targetHeight. It also returns the bundle id for the snapshot -func PerformStateSyncValidationChecks(chainRest string, snapshotPoolId, targetHeight int64, userInput bool) (snapshotBundleId, snapshotHeight int64, err error) { - // get lowest and highest complete snapshot - startHeight, endHeight, err := helpers.GetSnapshotBoundaries(chainRest, snapshotPoolId) - if err != nil { - return snapshotBundleId, snapshotHeight, fmt.Errorf("failed get snapshot boundaries: %w", err) - } - - logger.Info().Msg(fmt.Sprintf("retrieved snapshot boundaries, earliest complete snapshot height = %d, latest complete snapshot height %d", startHeight, endHeight)) - - // if no snapshot height was specified we use the latest available snapshot from the pool as targetHeight - if targetHeight == 0 { - targetHeight = endHeight - logger.Info().Msg(fmt.Sprintf("no target height specified, syncing to latest available snapshot %d", targetHeight)) - } - - if targetHeight < startHeight { - return snapshotBundleId, snapshotHeight, fmt.Errorf("requested snapshot height %d but first available snapshot on pool is %d", targetHeight, startHeight) - } - - // limit snapshot search height by latest available snapshot height - snapshotSearchHeight := targetHeight - if targetHeight > endHeight { - snapshotSearchHeight = endHeight - } - - snapshotBundleId, snapshotHeight, err = snapshots.FindNearestSnapshotBundleIdByHeight(chainRest, snapshotPoolId, snapshotSearchHeight) - if err != nil { - return - } - - if userInput { - answer := "" - - // if we found a different snapshotHeight as the requested targetHeight it means the targetHeight was not - // available, and we have to sync to the nearest height below - if targetHeight != snapshotHeight { - fmt.Printf("\u001B[36m[KSYNC]\u001B[0m could not find snapshot with requested height %d, state-sync to nearest available snapshot with height %d instead? [y/N]: ", targetHeight, snapshotHeight) - } else { - fmt.Printf("\u001B[36m[KSYNC]\u001B[0m should snapshot with height %d be applied with state-sync [y/N]: ", snapshotHeight) - } - - if _, err := fmt.Scan(&answer); err != nil { - return snapshotBundleId, snapshotHeight, fmt.Errorf("failed to read in user input: %w", err) - } - - if strings.ToLower(answer) != "y" { - return snapshotBundleId, snapshotHeight, errors.New("aborted state-sync") - } - } - - return snapshotBundleId, snapshotHeight, nil -} - -func StartStateSyncWithBinary(engine types.Engine, binaryPath, chainId, chainRest, storageRest string, snapshotPoolId, targetHeight, snapshotBundleId, snapshotHeight int64, appFlags string, optOut, debug bool) error { - logger.Info().Msg("starting state-sync") - - // start binary process thread - processId, err := utils.StartBinaryProcessForDB(engine, binaryPath, debug, strings.Split(appFlags, ",")) - if err != nil { - return fmt.Errorf("failed to start binary process: %w", err) - } - - if err := engine.OpenDBs(); err != nil { - return fmt.Errorf("failed to open dbs in engine: %w", err) - } - - utils.TrackSyncStartEvent(engine, utils.STATE_SYNC, chainId, chainRest, storageRest, targetHeight, optOut) - - start := time.Now() - - if err := StartStateSyncExecutor(engine, chainRest, storageRest, snapshotPoolId, snapshotBundleId); err != nil { - logger.Error().Msg(fmt.Sprintf("failed to start state-sync: %s", err)) - - // stop binary process thread - if err := utils.StopProcessByProcessId(processId); err != nil { - return fmt.Errorf("failed to stop process by process id: %w", err) - } - - return fmt.Errorf("failed to start state-sync executor: %w", err) - } - - // stop binary process thread - if err := utils.StopProcessByProcessId(processId); err != nil { - return fmt.Errorf("failed to stop process by process id: %w", err) - } - - elapsed := time.Since(start).Seconds() - utils.TrackSyncCompletedEvent(snapshotHeight, 0, targetHeight, elapsed, optOut) - - if err := engine.CloseDBs(); err != nil { - return fmt.Errorf("failed to close dbs in engine: %w", err) - } - - logger.Info().Msg(fmt.Sprintf("state-synced at height %d in %.2f seconds", snapshotHeight, elapsed)) - logger.Info().Msg(fmt.Sprintf("successfully applied state-sync snapshot")) - return nil -} diff --git a/sync/blocksync/blocksync.go b/sync/blocksync/blocksync.go new file mode 100644 index 0000000..15bf974 --- /dev/null +++ b/sync/blocksync/blocksync.go @@ -0,0 +1,132 @@ +package blocksync + +import ( + "fmt" + "github.com/KYVENetwork/ksync/app" + "github.com/KYVENetwork/ksync/app/collector" + "github.com/KYVENetwork/ksync/flags" + "github.com/KYVENetwork/ksync/logger" + "github.com/KYVENetwork/ksync/metrics" + "github.com/KYVENetwork/ksync/types" + "github.com/KYVENetwork/ksync/utils" +) + +// PerformBlockSyncValidationChecks makes boundary checks if app can be block-synced from the given +// continuation height to the given target height +func PerformBlockSyncValidationChecks(blockCollector types.BlockCollector, continuationHeight, targetHeight int64) error { + earliest := blockCollector.GetEarliestAvailableHeight() + latest := blockCollector.GetLatestAvailableHeight() + + logger.Logger.Info().Msg(fmt.Sprintf("retrieved block boundaries, earliest block height = %d, latest block height %d", earliest, latest)) + + if continuationHeight < earliest { + return fmt.Errorf("app is currently at height %d but first available block on pool is %d", continuationHeight, earliest) + } + + if continuationHeight > latest { + return fmt.Errorf("app is currently at height %d but last available block on pool is %d", continuationHeight, latest) + } + + if targetHeight > 0 && continuationHeight > targetHeight { + return fmt.Errorf("requested target height is %d but app is already at block height %d", targetHeight, continuationHeight) + } + + if targetHeight > 0 && targetHeight > latest { + logger.Logger.Warn().Msgf("target height %d does not exist on pool yet, syncing until height is created on pool and reached", targetHeight) + } + + if targetHeight == 0 { + logger.Logger.Info().Msg(fmt.Sprintf("no target height specified, syncing indefinitely")) + } + + return nil +} + +func getBlockCollector(app *app.CosmosApp) (types.BlockCollector, error) { + if flags.BlockRpc != "" { + blockCollector, err := collector.NewRpcBlockCollector(flags.BlockRpc, flags.BlockRpcReqTimeout) + if err != nil { + return nil, fmt.Errorf("failed to init rpc block collector: %w", err) + } + + return blockCollector, nil + } + + // if there is no entry in the source registry for the source + // and if no block pool id was provided with the flags it would fail here + blockPoolId, err := app.Source.GetSourceBlockPoolId() + if err != nil { + return nil, fmt.Errorf("failed to get block pool id: %w", err) + } + + blockCollector, err := collector.NewKyveBlockCollector(blockPoolId, app.GetChainRest()) + if err != nil { + return nil, fmt.Errorf("failed to init kyve block collector: %w", err) + } + + return blockCollector, nil +} + +func getUserConfirmation(y bool, continuationHeight, targetHeight int64) (bool, error) { + if y { + return true, nil + } + + if targetHeight > 0 { + fmt.Printf("\u001B[36m[KSYNC]\u001B[0m should %d blocks from height %d to %d be synced [y/N]: ", targetHeight-(continuationHeight-1), continuationHeight-1, targetHeight) + } else { + fmt.Printf("\u001B[36m[KSYNC]\u001B[0m should blocks from height %d be synced [y/N]: ", continuationHeight-1) + } + + return utils.GetUserConfirmationInput() +} + +func Start() error { + logger.Logger.Info().Msg("starting block-sync") + + app, err := app.NewCosmosApp() + if err != nil { + return fmt.Errorf("failed to init cosmos app: %w", err) + } + + if flags.Reset { + if err := app.ConsensusEngine.ResetAll(true); err != nil { + return fmt.Errorf("failed to reset cosmos app: %w", err) + } + } + + continuationHeight := app.GetContinuationHeight() + metrics.SetContinuationHeight(continuationHeight) + + blockCollector, err := getBlockCollector(app) + if err != nil { + return err + } + + if err := PerformBlockSyncValidationChecks(blockCollector, continuationHeight, flags.TargetHeight); err != nil { + return fmt.Errorf("block-sync validation checks failed: %w", err) + } + + if confirmation, err := getUserConfirmation(flags.Y, continuationHeight, flags.TargetHeight); !confirmation { + return err + } + + if err := app.AutoSelectBinaryVersion(continuationHeight); err != nil { + return fmt.Errorf("failed to auto select binary version: %w", err) + } + + if err := app.StartAll(0); err != nil { + return fmt.Errorf("failed to start app: %w", err) + } + + defer app.StopAll() + + // we only pass the snapshot collector to the block executor if we are creating + // state-sync snapshots with serve-snapshots + if err := StartBlockSyncExecutor(app, blockCollector, nil); err != nil { + return fmt.Errorf("failed to start block-sync executor: %w", err) + } + + logger.Logger.Info().Str("duration", metrics.GetSyncDuration().String()).Msgf("successfully finished block-sync by reaching target height %d", flags.TargetHeight) + return nil +} diff --git a/sync/blocksync/bootstrap.go b/sync/blocksync/bootstrap.go new file mode 100644 index 0000000..6117731 --- /dev/null +++ b/sync/blocksync/bootstrap.go @@ -0,0 +1,125 @@ +package blocksync + +import ( + "fmt" + "github.com/KYVENetwork/ksync/app" + "github.com/KYVENetwork/ksync/logger" + "github.com/KYVENetwork/ksync/types" + "github.com/KYVENetwork/ksync/utils" + "github.com/tendermint/tendermint/libs/json" + "strconv" + "strings" + "time" +) + +func getAppHeightFromRPC(rpcListenAddress string) (height int64, err error) { + rpc := fmt.Sprintf("%s/abci_info", strings.ReplaceAll(rpcListenAddress, "tcp", "http")) + + responseData, err := utils.GetFromUrl(rpc) + if err != nil { + return height, err + } + + var response types.AbciInfoResponse + if err := json.Unmarshal(responseData, &response); err != nil { + return height, err + } + + if response.Result.Response.LastBlockHeight == "" { + return 0, nil + } + + height, err = strconv.ParseInt(response.Result.Response.LastBlockHeight, 10, 64) + if err != nil { + return height, err + } + + return +} + +// bootstrapApp applies the first block over the p2p mode if the genesis file +// is larger than 100MB. We can not call the "InitChain" ABCI method because +// the genesis file is a param and if the message exceeds a 100MB limit the cosmos +// application panics due to defined max message size. This limit was increased +// to 2GB in this PR https://github.com/cometbft/cometbft/pull/1730, but every +// version before cometbft-v1.0.0 has this limitation +func bootstrapApp(app *app.CosmosApp, blockCollector types.BlockCollector, snapshotCollector types.SnapshotCollector) error { + // if the app already has mined at least one block we do not need to + // call "InitChain" and can therefore skip + if app.ConsensusEngine.GetHeight() > app.Genesis.GetInitialHeight() { + return nil + } + + // if the genesis file is smaller than 100MB the cosmos app will not panic + // and we can skip + if app.Genesis.GetFileSize() < (100 * 1024 * 1024) { + return nil + } + + logger.Logger.Info().Msg("genesis file is larger than 100MB, syncing first block over P2P mode") + + app.StopAll() + + block, err := blockCollector.GetBlock(app.Genesis.GetInitialHeight()) + if err != nil { + return fmt.Errorf("failed to get block %d: %w", app.Genesis.GetInitialHeight(), err) + } + + nextBlock, err := blockCollector.GetBlock(app.Genesis.GetInitialHeight() + 1) + if err != nil { + return fmt.Errorf("failed to get block %d: %w", app.Genesis.GetInitialHeight()+1, err) + } + + if err := app.StartBinaryP2P(); err != nil { + return fmt.Errorf("failed to start cosmos app in p2p mode: %w", err) + } + + logger.Logger.Info().Msg("bootstrapping node, depending on the size of the genesis file, this step can take several minutes") + + // wait until binary has properly started by testing if the /abci + // endpoint is up + for { + if _, err := getAppHeightFromRPC(app.ConsensusEngine.GetRpcListenAddress()); err == nil { + break + } + time.Sleep(5 * time.Second) + } + + logger.Logger.Info().Msg("loaded genesis file and completed ABCI handshake between app and tendermint") + + // start p2p executors and try to execute the first block on the app + if err := app.ConsensusEngine.ApplyFirstBlockOverP2P(block, nextBlock); err != nil { + app.StopBinary() + return fmt.Errorf("failed to start p2p executor: %w", err) + } + + // wait until block was properly executed by testing if the /abci + // endpoint returns the correct block height + for { + height, err := getAppHeightFromRPC(app.ConsensusEngine.GetRpcListenAddress()) + if err != nil { + app.StopBinary() + return fmt.Errorf("failed to get app height from rpc %s: %w", app.ConsensusEngine.GetRpcListenAddress(), err) + } + + if height == app.Genesis.GetInitialHeight() { + break + } + time.Sleep(5 * time.Second) + } + + app.StopBinary() + + if snapshotCollector != nil { + if err := app.StartAll(snapshotCollector.GetInterval()); err != nil { + return err + } + } else { + if err := app.StartAll(0); err != nil { + return err + } + } + + logger.Logger.Info().Msg("successfully bootstrapped node. Continuing with syncing blocks with DB mode") + return nil +} diff --git a/sync/blocksync/executor.go b/sync/blocksync/executor.go new file mode 100644 index 0000000..1cd9e45 --- /dev/null +++ b/sync/blocksync/executor.go @@ -0,0 +1,189 @@ +package blocksync + +import ( + "fmt" + "github.com/KYVENetwork/ksync/app" + "github.com/KYVENetwork/ksync/flags" + "github.com/KYVENetwork/ksync/logger" + "github.com/KYVENetwork/ksync/metrics" + "github.com/KYVENetwork/ksync/types" + "github.com/KYVENetwork/ksync/utils" + "time" +) + +var ( + blockCh = make(chan *types.BlockItem, utils.BlockBuffer) + errorCh = make(chan error) +) + +func StartBlockSyncExecutor(app *app.CosmosApp, blockCollector types.BlockCollector, snapshotCollector types.SnapshotCollector) error { + if blockCollector == nil { + return fmt.Errorf("block collector can't be nil") + } + + if err := bootstrapApp(app, blockCollector, snapshotCollector); err != nil { + return fmt.Errorf("failed to bootstrap cosmos app: %w", err) + } + + continuationHeight := app.GetContinuationHeight() + + go blockCollector.StreamBlocks(blockCh, errorCh, continuationHeight, flags.TargetHeight) + + appHeight, err := app.ConsensusEngine.GetAppHeight() + if err != nil { + return fmt.Errorf("failed to get height from cosmos app: %w", err) + } + + if err := app.ConsensusEngine.DoHandshake(); err != nil { + return fmt.Errorf("failed to do handshake: %w", err) + } + + if flags.RpcServer { + go app.ConsensusEngine.StartRPCServer(flags.RpcServerPort) + } + + snapshotPoolHeight := int64(0) + + // if KSYNC has already fetched 3 * snapshot_interval ahead of the snapshot pool we wait + // in order to not bloat the KSYNC process + if snapshotCollector != nil && !flags.SkipWaiting { + snapshotPoolHeight, err = snapshotCollector.GetCurrentHeight() + if err != nil { + return fmt.Errorf("failed to get snapshot pool height: %w", err) + } + + if continuationHeight > snapshotPoolHeight+(utils.SnapshotPruningAheadFactor*snapshotCollector.GetInterval()) { + logger.Logger.Info().Msg("synced too far ahead of snapshot pool. Waiting for snapshot pool to produce new bundles") + } + + for continuationHeight > snapshotPoolHeight+(utils.SnapshotPruningAheadFactor*snapshotCollector.GetInterval()) { + time.Sleep(10 * time.Second) + + // refresh snapshot pool height + snapshotPoolHeight, err = snapshotCollector.GetCurrentHeight() + if err != nil { + return fmt.Errorf("failed to get snapshot pool height: %w", err) + } + } + } + + block := <-blockCh + + for { + select { + case err := <-errorCh: + return fmt.Errorf("error in block collector: %w", err) + case nextBlock := <-blockCh: + logger.Logger.Debug().Int64("height", block.Height).Int64("next_height", nextBlock.Height).Msg("applying blocks to engine") + + if err := app.ConsensusEngine.ApplyBlock(block.Block, nextBlock.Block); err != nil { + // before we return we check if this is due to an upgrade, if we are running + // with cosmovisor, and it is indeed due to an upgrade we restart the binary + // and the cosmos app to apply it + if !app.IsCosmovisor() || !utils.IsUpgradeHeight(app.GetHomePath(), block.Height) { + return fmt.Errorf("failed to apply block in engine: %w", err) + } + + app.StopAll() + + if err := app.LoadConsensusEngine(); err != nil { + return fmt.Errorf("failed to reload engine: %w", err) + } + + if snapshotCollector != nil { + if err := app.StartAll(snapshotCollector.GetInterval()); err != nil { + return err + } + } else { + if err := app.StartAll(0); err != nil { + return err + } + } + + if err := app.ConsensusEngine.DoHandshake(); err != nil { + return fmt.Errorf("failed to do handshake: %w", err) + } + + block = nextBlock + continue + } + + if snapshotCollector != nil { + // prune unused blocks for serve-snapshots + if flags.Pruning && block.Height%utils.PruningInterval == 0 { + // Because we sync 3 * snapshot_interval ahead we keep the latest + // 6 * snapshot_interval blocks and prune everything before that + pruneFromHeight := app.ConsensusEngine.GetBaseHeight() + pruneToHeight := app.ConsensusEngine.GetHeight() - (utils.SnapshotPruningWindowFactor * snapshotCollector.GetInterval()) + + if pruneToHeight > pruneFromHeight { + if err := app.ConsensusEngine.PruneBlocks(pruneToHeight); err != nil { + return fmt.Errorf("failed to prune blocks from %d to %d: %w", pruneFromHeight, pruneToHeight, err) + } + + logger.Logger.Info().Msgf("successfully pruned blocks from %d to %d", pruneFromHeight, pruneToHeight) + } else { + logger.Logger.Info().Msg("found no blocks to prune. Continuing ...") + } + } + + // wait until snapshot got created if we are on the snapshot interval, + // else if KSYNC moves to fast the snapshot can not be properly written + // to disk. We check if the initial app height is smaller than the current + // applied height since in this case the app has not created the snapshot yet. + if block.Height%snapshotCollector.GetInterval() == 0 && appHeight < block.Height { + for { + logger.Logger.Info().Msg(fmt.Sprintf("waiting until snapshot at height %d is created by cosmos app", block.Height)) + + found, err := app.ConsensusEngine.IsSnapshotAvailable(block.Height) + if err != nil { + return fmt.Errorf("failed to check if snapshot is available at height %d: %w", block.Height, err) + } + + if !found { + logger.Logger.Info().Msg(fmt.Sprintf("snapshot at height %d was not created yet. Waiting ...", block.Height)) + time.Sleep(10 * time.Second) + continue + } + + logger.Logger.Info().Msg(fmt.Sprintf("snapshot at height %d was successfully created. Continuing ...", block.Height)) + break + } + + // refresh snapshot pool height here, because we don't want to fetch this on every block + snapshotPoolHeight, err = snapshotCollector.GetCurrentHeight() + if err != nil { + return fmt.Errorf("failed to get snapshot pool height: %w", err) + } + } + + // if KSYNC has already fetched 3 * snapshot_interval ahead of the snapshot pool we wait + // in order to not bloat the KSYNC process. If skipWaiting is true we sync as far as possible + if !flags.SkipWaiting { + // only log this message once + if nextBlock.Height > snapshotPoolHeight+(utils.SnapshotPruningAheadFactor*snapshotCollector.GetInterval()) { + logger.Logger.Info().Msg("synced too far ahead of snapshot pool. Waiting for snapshot pool to produce new bundles") + } + + for nextBlock.Height > snapshotPoolHeight+(utils.SnapshotPruningAheadFactor*snapshotCollector.GetInterval()) { + time.Sleep(10 * time.Second) + + snapshotPoolHeight, err = snapshotCollector.GetCurrentHeight() + if err != nil { + return fmt.Errorf("failed to get snapshot pool height: %w", err) + } + } + } + } + + metrics.SetLatestHeight(block.Height) + + // stop with block execution if we have reached our target height + if flags.TargetHeight > 0 && block.Height >= flags.TargetHeight { + return nil + } + + block = nextBlock + } + } +} diff --git a/sync/heightsync/heightsync.go b/sync/heightsync/heightsync.go new file mode 100644 index 0000000..7980eb2 --- /dev/null +++ b/sync/heightsync/heightsync.go @@ -0,0 +1,132 @@ +package heightsync + +import ( + "fmt" + "github.com/KYVENetwork/ksync/app" + "github.com/KYVENetwork/ksync/app/collector" + "github.com/KYVENetwork/ksync/flags" + "github.com/KYVENetwork/ksync/logger" + "github.com/KYVENetwork/ksync/metrics" + "github.com/KYVENetwork/ksync/sync/blocksync" + "github.com/KYVENetwork/ksync/sync/statesync" + "github.com/KYVENetwork/ksync/utils" +) + +func getUserConfirmation(y, canApplySnapshot bool, snapshotHeight, continuationHeight, targetHeight int64) (bool, error) { + if y { + return true, nil + } + + if canApplySnapshot { + if targetHeight == 0 { + fmt.Printf("\u001B[36m[KSYNC]\u001B[0m no target height specified, state-sync to height %d and sync indefinitely from there [y/N]: ", snapshotHeight) + } else if snapshotHeight == targetHeight { + fmt.Printf("\u001B[36m[KSYNC]\u001B[0m should target height %d be reached by applying a snapshot at height %d [y/N]: ", targetHeight, snapshotHeight) + } else { + fmt.Printf("\u001B[36m[KSYNC]\u001B[0m should target height %d be reached by applying a snapshot at height %d and syncing the remaining %d blocks [y/N]: ", targetHeight, snapshotHeight, targetHeight-(continuationHeight-1)) + } + } else { + fmt.Printf("\u001B[36m[KSYNC]\u001B[0m should target height %d be reached by syncing from height %d [y/N]: ", targetHeight, continuationHeight-1) + } + + return utils.GetUserConfirmationInput() +} + +func Start() error { + logger.Logger.Info().Msg("starting height-sync") + + app, err := app.NewCosmosApp() + if err != nil { + return fmt.Errorf("failed to init cosmos app: %w", err) + } + + if flags.Reset { + if err := app.ConsensusEngine.ResetAll(true); err != nil { + return fmt.Errorf("failed to reset cosmos app: %w", err) + } + } + + snapshotPoolId, err := app.Source.GetSourceSnapshotPoolId() + if err != nil { + return fmt.Errorf("failed to get snapshot pool id: %w", err) + } + + blockPoolId, err := app.Source.GetSourceBlockPoolId() + if err != nil { + return fmt.Errorf("failed to get block pool id: %w", err) + } + + snapshotCollector, err := collector.NewKyveSnapshotCollector(snapshotPoolId, app.GetChainRest()) + if err != nil { + return fmt.Errorf("failed to init kyve snapshot collector: %w", err) + } + + blockCollector, err := collector.NewKyveBlockCollector(blockPoolId, app.GetChainRest()) + if err != nil { + return fmt.Errorf("failed to init kyve block collector: %w", err) + } + + snapshotHeight := snapshotCollector.GetSnapshotHeight(flags.TargetHeight) + metrics.SetSnapshotHeight(snapshotHeight) + + canApplySnapshot := snapshotHeight > 0 && app.IsReset() + canApplyBlocks := flags.TargetHeight == 0 || flags.TargetHeight > snapshotHeight + + var continuationHeight int64 + + if canApplySnapshot { + continuationHeight = snapshotHeight + 1 + } else { + continuationHeight = app.GetContinuationHeight() + } + + metrics.SetContinuationHeight(continuationHeight) + + if canApplySnapshot { + if err := statesync.PerformStateSyncValidationChecks(snapshotCollector, snapshotHeight); err != nil { + return fmt.Errorf("state-sync validation checks failed: %w", err) + } + } + + if canApplyBlocks { + if err := blocksync.PerformBlockSyncValidationChecks(blockCollector, continuationHeight, flags.TargetHeight); err != nil { + return fmt.Errorf("block-sync validation checks failed: %w", err) + } + } + + if confirmation, err := getUserConfirmation(flags.Y, canApplySnapshot, snapshotHeight, continuationHeight, flags.TargetHeight); !confirmation { + return err + } + + if err := app.AutoSelectBinaryVersion(continuationHeight); err != nil { + return fmt.Errorf("failed to auto select binary version: %w", err) + } + + if err := app.StartAll(0); err != nil { + return fmt.Errorf("failed to start app: %w", err) + } + + defer app.StopAll() + + if canApplySnapshot { + if err := statesync.StartStateSyncExecutor(app, snapshotCollector, snapshotHeight); err != nil { + return fmt.Errorf("failed to start state-sync executor: %w", err) + } + } + + if canApplyBlocks { + // TODO: dydx needs restart here (and in serve-snapshots), other chains too? + if app.Genesis.GetChainId() == "dydx-mainnet-1" { + if err := app.RestartAll(0); err != nil { + return fmt.Errorf("failed to restart app: %w", err) + } + } + + if err := blocksync.StartBlockSyncExecutor(app, blockCollector, nil); err != nil { + return fmt.Errorf("failed to start block-sync executor: %w", err) + } + } + + logger.Logger.Info().Str("duration", metrics.GetSyncDuration().String()).Msgf("successfully finished height-sync by reaching target height %d", flags.TargetHeight) + return nil +} diff --git a/server/snapshots.go b/sync/servesnapshots/server.go similarity index 83% rename from server/snapshots.go rename to sync/servesnapshots/server.go index cb5cf24..7c442f8 100644 --- a/server/snapshots.go +++ b/sync/servesnapshots/server.go @@ -1,22 +1,21 @@ -package server +package servesnapshots import ( "fmt" - "github.com/KYVENetwork/ksync/types" + "github.com/KYVENetwork/ksync/app" + "github.com/KYVENetwork/ksync/flags" "github.com/gin-gonic/gin" "net/http" "strconv" ) type ApiServer struct { - engine types.Engine - port int64 + app *app.CosmosApp } -func StartSnapshotApiServer(engine types.Engine, port int64) *ApiServer { +func startSnapshotApiServer(app *app.CosmosApp) *ApiServer { apiServer := &ApiServer{ - engine: engine, - port: port, + app: app, } gin.SetMode(gin.ReleaseMode) @@ -28,7 +27,7 @@ func StartSnapshotApiServer(engine types.Engine, port int64) *ApiServer { r.GET("/get_state/:height", apiServer.GetStateHandler) r.GET("/get_seen_commit/:height", apiServer.GetSeenCommitHandler) - if err := r.Run(fmt.Sprintf(":%d", port)); err != nil { + if err := r.Run(fmt.Sprintf(":%d", flags.SnapshotPort)); err != nil { panic(err) } @@ -36,7 +35,7 @@ func StartSnapshotApiServer(engine types.Engine, port int64) *ApiServer { } func (apiServer *ApiServer) ListSnapshotsHandler(c *gin.Context) { - resp, err := apiServer.engine.GetSnapshots() + resp, err := apiServer.app.ConsensusEngine.GetSnapshots() if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": err.Error(), @@ -72,7 +71,7 @@ func (apiServer *ApiServer) LoadSnapshotChunkHandler(c *gin.Context) { return } - resp, err := apiServer.engine.GetSnapshotChunk(height, format, chunk) + resp, err := apiServer.app.ConsensusEngine.GetSnapshotChunk(height, format, chunk) if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": err.Error(), @@ -92,7 +91,7 @@ func (apiServer *ApiServer) GetBlockHandler(c *gin.Context) { return } - resp, err := apiServer.engine.GetBlock(height) + resp, err := apiServer.app.ConsensusEngine.GetBlock(height) if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": err.Error(), @@ -112,7 +111,7 @@ func (apiServer *ApiServer) GetStateHandler(c *gin.Context) { return } - resp, err := apiServer.engine.GetState(height) + resp, err := apiServer.app.ConsensusEngine.GetState(height) if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": err.Error(), @@ -132,7 +131,7 @@ func (apiServer *ApiServer) GetSeenCommitHandler(c *gin.Context) { return } - resp, err := apiServer.engine.GetSeenCommit(height) + resp, err := apiServer.app.ConsensusEngine.GetSeenCommit(height) if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": err.Error(), diff --git a/sync/servesnapshots/servesnapshots.go b/sync/servesnapshots/servesnapshots.go new file mode 100644 index 0000000..aa23a1c --- /dev/null +++ b/sync/servesnapshots/servesnapshots.go @@ -0,0 +1,117 @@ +package servesnapshots + +import ( + "fmt" + "github.com/KYVENetwork/ksync/app" + "github.com/KYVENetwork/ksync/app/collector" + "github.com/KYVENetwork/ksync/flags" + "github.com/KYVENetwork/ksync/logger" + "github.com/KYVENetwork/ksync/metrics" + "github.com/KYVENetwork/ksync/sync/blocksync" + "github.com/KYVENetwork/ksync/sync/statesync" +) + +func Start() error { + logger.Logger.Info().Msg("starting serve-snapshots") + + if flags.Pruning && flags.SkipWaiting { + return fmt.Errorf("pruning has to be disabled with --pruning=false if --skip-waiting is true") + } + + app, err := app.NewCosmosApp() + if err != nil { + return fmt.Errorf("failed to init cosmos app: %w", err) + } + + if flags.Reset { + if err := app.ConsensusEngine.ResetAll(true); err != nil { + return fmt.Errorf("failed to reset cosmos app: %w", err) + } + } + + if flags.StartHeight > 0 && !app.IsReset() { + return fmt.Errorf("if --start-height is provided app needs to be reset") + } + + snapshotPoolId, err := app.Source.GetSourceSnapshotPoolId() + if err != nil { + return fmt.Errorf("failed to get snapshot pool id: %w", err) + } + + blockPoolId, err := app.Source.GetSourceBlockPoolId() + if err != nil { + return fmt.Errorf("failed to get block pool id: %w", err) + } + + snapshotCollector, err := collector.NewKyveSnapshotCollector(snapshotPoolId, app.GetChainRest()) + if err != nil { + return fmt.Errorf("failed to init kyve snapshot collector: %w", err) + } + + blockCollector, err := collector.NewKyveBlockCollector(blockPoolId, app.GetChainRest()) + if err != nil { + return fmt.Errorf("failed to init kyve block collector: %w", err) + } + + snapshotHeight := snapshotCollector.GetSnapshotHeight(flags.StartHeight) + metrics.SetSnapshotHeight(snapshotHeight) + + canApplySnapshot := snapshotHeight > 0 && app.IsReset() + canApplyBlocks := flags.TargetHeight == 0 || flags.TargetHeight > snapshotHeight + + var continuationHeight int64 + + if canApplySnapshot { + continuationHeight = snapshotHeight + 1 + } else { + continuationHeight = app.GetContinuationHeight() + } + + metrics.SetContinuationHeight(continuationHeight) + + if canApplySnapshot { + if err := statesync.PerformStateSyncValidationChecks(snapshotCollector, snapshotHeight); err != nil { + return fmt.Errorf("state-sync validation checks failed: %w", err) + } + } + + if canApplyBlocks { + if err := blocksync.PerformBlockSyncValidationChecks(blockCollector, continuationHeight, flags.TargetHeight); err != nil { + return fmt.Errorf("block-sync validation checks failed: %w", err) + } + } + + if err := app.AutoSelectBinaryVersion(continuationHeight); err != nil { + return fmt.Errorf("failed to auto select binary version: %w", err) + } + + if err := app.StartAll(snapshotCollector.GetInterval()); err != nil { + return fmt.Errorf("failed to start app: %w", err) + } + + defer app.StopAll() + + if canApplySnapshot { + if err := statesync.StartStateSyncExecutor(app, snapshotCollector, snapshotHeight); err != nil { + return fmt.Errorf("failed to start state-sync executor: %w", err) + } + } + + if canApplyBlocks { + // TODO: dydx needs restart here (and in height-sync), other chains too? + if app.Genesis.GetChainId() == "dydx-mainnet-1" { + if err := app.RestartAll(snapshotCollector.GetInterval()); err != nil { + return fmt.Errorf("failed to restart app: %w", err) + } + } + + go startSnapshotApiServer(app) + + if err := blocksync.StartBlockSyncExecutor(app, blockCollector, snapshotCollector); err != nil { + return fmt.Errorf("failed to start block-sync executor: %w", err) + } + } + + logger.Logger.Info().Str("duration", metrics.GetSyncDuration().String()).Msgf("successfully finished serve-snapshots") + return nil +} diff --git a/sync/statesync/executor.go b/sync/statesync/executor.go new file mode 100644 index 0000000..70a7337 --- /dev/null +++ b/sync/statesync/executor.go @@ -0,0 +1,77 @@ +package statesync + +import ( + "fmt" + "github.com/KYVENetwork/ksync/app" + "github.com/KYVENetwork/ksync/logger" + "github.com/KYVENetwork/ksync/metrics" + "github.com/KYVENetwork/ksync/types" + "github.com/tendermint/tendermint/libs/json" +) + +// StartStateSyncExecutor takes the bundle id of the first snapshot chunk and applies the snapshot from there +func StartStateSyncExecutor(app *app.CosmosApp, snapshotCollector types.SnapshotCollector, snapshotHeight int64) error { + if snapshotCollector == nil { + return fmt.Errorf("snapshot collector can't be nil") + } + + appHeight, err := app.ConsensusEngine.GetAppHeight() + if err != nil { + return fmt.Errorf("failed to get height from cosmos app: %w", err) + } + + if appHeight > 0 { + return fmt.Errorf("app height %d is not zero, please reset with \"ksync reset-all\" or run the command with \"--reset-all\"", appHeight) + } + + bundleId, err := snapshotCollector.FindSnapshotBundleIdForHeight(snapshotHeight) + if err != nil { + return fmt.Errorf("failed to find snapshot bundle id for height %d: %w", snapshotHeight, err) + } + + snapshotDataItem, err := snapshotCollector.GetSnapshotFromBundleId(bundleId) + if err != nil { + return fmt.Errorf("failed to get snapshot from bundle id %d: %w", bundleId, err) + } + + var snapshot types.Snapshot + if err := json.Unmarshal(snapshotDataItem.Value.Snapshot, &snapshot); err != nil { + return fmt.Errorf("failed to unmarshal snapshot from bundle id %d: %w", bundleId, err) + } + + if err := app.ConsensusEngine.OfferSnapshot(snapshotDataItem.Value.Snapshot, snapshotDataItem.Value.State); err != nil { + return fmt.Errorf("failed to offer snapshot: %w", err) + } + + logger.Logger.Info().Msgf("offering snapshot for height %d: ACCEPT", snapshot.Height) + + if err := app.ConsensusEngine.ApplySnapshotChunk(0, snapshotDataItem.Value.Chunk); err != nil { + return fmt.Errorf("applying snapshot chunk %d/%d failed: %w", 1, snapshot.Chunks, err) + } + + logger.Logger.Info().Msgf("applied snapshot chunk %d/%d: ACCEPT", 1, snapshot.Chunks) + + for chunkIndex := int64(1); chunkIndex < int64(snapshot.Chunks); chunkIndex++ { + chunk, err := snapshotCollector.DownloadChunkFromBundleId(bundleId + chunkIndex) + if err != nil { + return fmt.Errorf("failed downloading snapshot chunk from bundle id %d: %w", bundleId+chunkIndex, err) + } + + logger.Logger.Info().Msgf("downloaded snapshot chunk %d/%d", chunkIndex+1, snapshot.Chunks) + + if err := app.ConsensusEngine.ApplySnapshotChunk(chunkIndex, chunk); err != nil { + return fmt.Errorf("applying snapshot chunk %d/%d failed: %w", chunkIndex+1, snapshot.Chunks, err) + } + + logger.Logger.Info().Msgf("applied snapshot chunk %d/%d: ACCEPT", chunkIndex+1, snapshot.Chunks) + } + + if err := app.ConsensusEngine.BootstrapState(snapshotDataItem.Value.State, snapshotDataItem.Value.SeenCommit, snapshotDataItem.Value.Block); err != nil { + return fmt.Errorf("failed to bootstrap state after state-sync: %w", err) + } + + metrics.SetLatestHeight(snapshotHeight) + + logger.Logger.Info().Uint64("height", snapshot.Height).Uint32("format", snapshot.Format).Str("hash", fmt.Sprintf("%X", snapshot.Hash)).Msg("snapshot restored") + return nil +} diff --git a/sync/statesync/statesync.go b/sync/statesync/statesync.go new file mode 100644 index 0000000..7f3c383 --- /dev/null +++ b/sync/statesync/statesync.go @@ -0,0 +1,109 @@ +package statesync + +import ( + "fmt" + "github.com/KYVENetwork/ksync/app" + "github.com/KYVENetwork/ksync/app/collector" + "github.com/KYVENetwork/ksync/flags" + "github.com/KYVENetwork/ksync/logger" + "github.com/KYVENetwork/ksync/metrics" + "github.com/KYVENetwork/ksync/types" + "github.com/KYVENetwork/ksync/utils" +) + +// PerformStateSyncValidationChecks makes boundary checks for the given snapshot height +func PerformStateSyncValidationChecks(snapshotCollector types.SnapshotCollector, snapshotHeight int64) error { + earliest := snapshotCollector.GetEarliestAvailableHeight() + latest := snapshotCollector.GetLatestAvailableHeight() + + logger.Logger.Info().Msgf("retrieved snapshot boundaries, earliest complete snapshot height = %d, latest complete snapshot height %d", earliest, latest) + + if snapshotHeight < earliest { + return fmt.Errorf("requested snapshot height is %d but first available snapshot on pool is %d", snapshotHeight, earliest) + } + + if snapshotHeight > latest { + return fmt.Errorf("requested snapshot height is %d but latest available snapshot on pool is %d", snapshotHeight, latest) + } + + return nil +} + +func getUserConfirmation(y bool, snapshotHeight, targetHeight int64) (bool, error) { + if y { + return true, nil + } + + // if we found a different snapshotHeight as the requested targetHeight it means there was no snapshot + // at the requested targetHeight. Ask the user here if KSYNC should sync to the nearest height instead + if targetHeight == 0 { + fmt.Printf("\u001B[36m[KSYNC]\u001B[0m no target height specified, state-sync to latest available snapshot with height %d [y/N]: ", snapshotHeight) + } else if snapshotHeight == targetHeight { + fmt.Printf("\u001B[36m[KSYNC]\u001B[0m should snapshot with height %d be applied with state-sync [y/N]: ", snapshotHeight) + } else { + fmt.Printf("\u001B[36m[KSYNC]\u001B[0m could not find snapshot with requested height %d, state-sync to nearest available snapshot with height %d instead? [y/N]: ", targetHeight, snapshotHeight) + } + + return utils.GetUserConfirmationInput() +} + +func Start() error { + logger.Logger.Info().Msg("starting state-sync") + + app, err := app.NewCosmosApp() + if err != nil { + return fmt.Errorf("failed to init cosmos app: %w", err) + } + + if flags.Reset { + if err := app.ConsensusEngine.ResetAll(true); err != nil { + return fmt.Errorf("failed to reset cosmos app: %w", err) + } + } + + if !app.IsReset() { + return fmt.Errorf("app has to be reset for state-sync") + } + + snapshotPoolId, err := app.Source.GetSourceSnapshotPoolId() + if err != nil { + return fmt.Errorf("failed to get snapshot pool id: %w", err) + } + + snapshotCollector, err := collector.NewKyveSnapshotCollector(snapshotPoolId, app.GetChainRest()) + if err != nil { + return fmt.Errorf("failed to init kyve snapshot collector: %w", err) + } + + snapshotHeight := snapshotCollector.GetSnapshotHeight(flags.TargetHeight) + metrics.SetSnapshotHeight(snapshotHeight) + + if snapshotHeight == 0 { + return fmt.Errorf("no snapshot could be found, target height %d too low", flags.TargetHeight) + } + + if err := PerformStateSyncValidationChecks(snapshotCollector, snapshotHeight); err != nil { + return fmt.Errorf("state-sync validation checks failed: %w", err) + } + + if confirmation, err := getUserConfirmation(flags.Y, snapshotHeight, flags.TargetHeight); !confirmation { + return err + } + + if err := app.AutoSelectBinaryVersion(snapshotHeight); err != nil { + return fmt.Errorf("failed to auto select binary version: %w", err) + } + + if err := app.StartAll(0); err != nil { + return fmt.Errorf("failed to start app: %w", err) + } + + defer app.StopAll() + + if err := StartStateSyncExecutor(app, snapshotCollector, snapshotHeight); err != nil { + return fmt.Errorf("failed to start state-sync executor: %w", err) + } + + logger.Logger.Info().Str("duration", metrics.GetSyncDuration().String()).Msgf("successfully finished state-sync by applying snapshot at height %d", snapshotHeight) + return nil +} diff --git a/tests/Dockerfile b/tests/Dockerfile index 68a8d82..2768247 100644 --- a/tests/Dockerfile +++ b/tests/Dockerfile @@ -20,6 +20,30 @@ RUN wget -qO- https://github.com/KYVENetwork/chain/releases/download/v1.0.0/kyve && ~/bins/kyved-v1.0.0 init ksync --chain-id kyve-1 \ && wget https://raw.githubusercontent.com/KYVENetwork/networks/main/kyve-1/genesis.json -O ~/.kyve/config/genesis.json +# install cosmovisor with all kyve versions for upgrade testing +RUN go install cosmossdk.io/tools/cosmovisor/cmd/cosmovisor@v1.6.0 + +ENV DAEMON_HOME=/root/.kyve +ENV DAEMON_NAME=kyved + +RUN cosmovisor init ~/bins/kyved-v1.0.0 + +RUN wget -qO- https://github.com/KYVENetwork/chain/releases/download/v1.1.3/kyved_mainnet_linux_amd64.tar.gz | tar -xzv \ + && cosmovisor add-upgrade v1.1.0 kyved + +RUN wget -qO- https://github.com/KYVENetwork/chain/releases/download/v1.2.2/kyved_mainnet_linux_amd64.tar.gz | tar -xzv \ + && cosmovisor add-upgrade v1.2.0 kyved + +RUN wget -qO- https://github.com/KYVENetwork/chain/releases/download/v1.3.2/kyved_mainnet_linux_amd64.tar.gz | tar -xzv \ + && cosmovisor add-upgrade v1.3.0 kyved + +RUN wget -qO- https://github.com/KYVENetwork/chain/releases/download/v1.4.0/kyved_mainnet_linux_amd64.tar.gz | tar -xzv \ + && cosmovisor add-upgrade v1.4.0 kyved + +RUN wget https://github.com/KYVENetwork/chain/releases/download/v1.5.0/kyved_mainnet_linux_amd64 -O kyved \ + && chmod +x kyved \ + && cosmovisor add-upgrade v1.5.0 kyved + # install dydxprotocold RUN wget -qO- https://github.com/dydxprotocol/v4-chain/releases/download/protocol%2Fv2.0.1/dydxprotocold-v2.0.1-linux-amd64.tar.gz | tar -xzv \ && mv build/dydxprotocold-v2.0.1-linux-amd64 ~/bins/dydxprotocold-v2.0.1 \ @@ -55,3 +79,10 @@ RUN git clone --depth 1 --branch v0.1.1-beta-patch https://github.com/andromedap && cd .. \ && rm -r andromedad \ && sed -i -r 's/minimum-gas-prices = ""/minimum-gas-prices = "0uandr"/' ~/.andromeda/config/app.toml + +# install nobled +RUN wget https://github.com/noble-assets/noble/releases/download/v8.0.3/nobled_linux-amd64 \ + && chmod +x nobled_linux-amd64 \ + && mv nobled_linux-amd64 ~/bins/nobled-v8.0.3 \ + && ~/bins/nobled-v8.0.3 init ksync --chain-id noble-1 \ + && wget https://raw.githubusercontent.com/strangelove-ventures/noble-networks/main/mainnet/noble-1/genesis.json -O ~/.noble/config/genesis.json diff --git a/tests/block_sync_test.bats b/tests/block_sync_test.bats index 00b63e9..f99bff1 100644 --- a/tests/block_sync_test.bats +++ b/tests/block_sync_test.bats @@ -1,39 +1,39 @@ @test "KYVE: block sync 50 blocks from genesis" { - run ./build/ksync block-sync -b $HOME/bins/kyved-v1.0.0 -c kaon-1 -t 50 -r -d -y + run ./build/ksync block-sync --opt-out -b $HOME/bins/kyved-v1.0.0 -c kaon-1 -t 50 -r -d -y [ "$status" -eq 0 ] } @test "KYVE: continue block sync from height 50" { - run ./build/ksync block-sync -b $HOME/bins/kyved-v1.0.0 -c kaon-1 -t 100 -d -y + run ./build/ksync block-sync --opt-out -b $HOME/bins/kyved-v1.0.0 -c kaon-1 -t 100 -d -y [ "$status" -eq 0 ] } @test "KYVE: try to block-sync with target height lower than current one" { - run ./build/ksync block-sync -b $HOME/bins/kyved-v1.0.0 -c kaon-1 -t 50 -d -y + run ./build/ksync block-sync --opt-out -b $HOME/bins/kyved-v1.0.0 -c kaon-1 -t 50 -d -y [ "$status" -eq 1 ] } @test "dYdX: block sync 50 blocks from genesis" { - run ./build/ksync block-sync -b $HOME/bins/dydxprotocold-v2.0.1 -t 50 -r -d -y + run ./build/ksync block-sync --opt-out -b $HOME/bins/dydxprotocold-v2.0.1 -t 50 -r -d -y [ "$status" -eq 0 ] } @test "dYdX: continue block sync from height 50" { - run ./build/ksync block-sync -b $HOME/bins/dydxprotocold-v2.0.1 -t 100 -d -y + run ./build/ksync block-sync --opt-out -b $HOME/bins/dydxprotocold-v2.0.1 -t 100 -d -y [ "$status" -eq 0 ] } @test "Archway: block sync 50 blocks from genesis with p2p bootstrap" { - run ./build/ksync block-sync -b $HOME/bins/archwayd-v1.0.1 -t 50 -r -d -y + run ./build/ksync block-sync --opt-out -b $HOME/bins/archwayd-v1.0.1 -t 50 -r -d -y [ "$status" -eq 0 ] } @test "Archway: continue block sync from height 50" { - run ./build/ksync block-sync -b $HOME/bins/archwayd-v1.0.1 -t 100 -d -y + run ./build/ksync block-sync --opt-out -b $HOME/bins/archwayd-v1.0.1 -t 100 -d -y [ "$status" -eq 0 ] } @test "Celestia: block sync 10 blocks from genesis" { - run ./build/ksync block-sync -b $HOME/bins/celestia-appd-v1.3.0 -t 10 -r -d -y + run ./build/ksync block-sync --opt-out -b $HOME/bins/celestia-appd-v1.3.0 -t 10 -r -d -y [ "$status" -eq 0 ] } diff --git a/tests/height_sync_test.bats b/tests/height_sync_test.bats index 628c0bc..f2eee76 100644 --- a/tests/height_sync_test.bats +++ b/tests/height_sync_test.bats @@ -1,29 +1,44 @@ @test "KYVE: height sync below first snapshot height" { - run ./build/ksync height-sync -b $HOME/bins/kyved-v1.0.0 -c kaon-1 -t 50 -r -d -y + run ./build/ksync height-sync --opt-out -b $HOME/bins/kyved-v1.0.0 -c kaon-1 -t 50 -r -d -y [ "$status" -eq 0 ] } @test "KYVE: try to height-sync if the app has not been resetted" { - run ./build/ksync height-sync -b $HOME/bins/kyved-v1.0.0 -c kaon-1 -t 12178 -d -y - [ "$status" -eq 1 ] + run ./build/ksync height-sync --opt-out -b $HOME/bins/kyved-v1.0.0 -c kaon-1 -t 100 -d -y + [ "$status" -eq 0 ] +} + +@test "KYVE Cosmovisor: try to height-sync with an upgrade between snapshot and target height" { + run ./build/ksync height-sync --opt-out -b cosmovisor -c kaon-1 -t 2061120 -r -d -a -y + [ "$status" -eq 0 ] } @test "dYdX: height sync to specific height" { - run ./build/ksync height-sync -b $HOME/bins/dydxprotocold-v2.0.1 -c kaon-1 -t 5935178 -r -d -y + run ./build/ksync height-sync --opt-out -b $HOME/bins/dydxprotocold-v2.0.1 -c kaon-1 -t 5935178 -r -d -y [ "$status" -eq 0 ] } @test "Archway: height sync below first snapshot height" { - run ./build/ksync height-sync -b $HOME/bins/archwayd-v1.0.1 -t 50 -r -d -y + run ./build/ksync height-sync --opt-out -b $HOME/bins/archwayd-v1.0.1 -t 50 -r -d -y [ "$status" -eq 0 ] } @test "Celestia: height sync to specific height" { - run ./build/ksync height-sync -b $HOME/bins/celestia-appd-v1.3.0 -t 10010 -r -d -y + run ./build/ksync height-sync --opt-out -b $HOME/bins/celestia-appd-v1.3.0 -t 10010 -r -d -y [ "$status" -eq 0 ] } @test "Andromeda: height-sync to specific height" { - run ./build/ksync height-sync -b $HOME/bins/andromedad-1-v0.1.1-beta-patch -c kaon-1 -t 2700020 -r -d -y + run ./build/ksync height-sync --opt-out -b $HOME/bins/andromedad-1-v0.1.1-beta-patch -c kaon-1 -t 2700020 -r -d -y + [ "$status" -eq 0 ] +} + +@test "Noble: height-sync to specific height" { + run ./build/ksync height-sync --opt-out -b $HOME/bins/nobled-v8.0.3 -t 16557020 -r -d -y + [ "$status" -eq 0 ] +} + +@test "Noble: height-sync to specific height on snapshot height" { + run ./build/ksync height-sync --opt-out -b $HOME/bins/nobled-v8.0.3 -t 16554000 -r -d -y [ "$status" -eq 0 ] } diff --git a/tests/info_test.bats b/tests/info_test.bats index fcf1066..7f2764a 100644 --- a/tests/info_test.bats +++ b/tests/info_test.bats @@ -1,14 +1,14 @@ @test "KYVE: info on mainnet" { - run ./build/ksync info + run ./build/ksync info --opt-out [ "$status" -eq 0 ] } @test "KYVE: info on testnet" { - run ./build/ksync info --chain-id kaon-1 + run ./build/ksync info --opt-out --chain-id kaon-1 [ "$status" -eq 0 ] } @test "KYVE: info on devnet" { - run ./build/ksync info --chain-id korellia-2 + run ./build/ksync info --opt-out --chain-id korellia-2 [ "$status" -eq 1 ] } diff --git a/tests/serve_blocks_test.bats b/tests/serve_blocks_test.bats new file mode 100644 index 0000000..dd9713c --- /dev/null +++ b/tests/serve_blocks_test.bats @@ -0,0 +1,14 @@ +@test "KYVE: serve-blocks 10 blocks from genesis" { + run ./build/ksync serve-blocks --opt-out -b $HOME/bins/kyved-v1.0.0 --block-rpc https://rpc.kyve.network -t 10 -r -d -y + [ "$status" -eq 0 ] +} + +@test "KYVE: serve-blocks from height 10" { + run ./build/ksync serve-blocks --opt-out -b $HOME/bins/kyved-v1.0.0 --block-rpc https://rpc.kyve.network -t 20 -d -y + [ "$status" -eq 0 ] +} + +@test "KYVE: try to serve-blocks with target height lower than current one" { + run ./build/ksync serve-blocks --opt-out -b $HOME/bins/kyved-v1.0.0 --block-rpc https://rpc.kyve.network -t 5 -d -y + [ "$status" -eq 1 ] +} diff --git a/tests/serve_snapshots_test.bats b/tests/serve_snapshots_test.bats new file mode 100644 index 0000000..c379ef5 --- /dev/null +++ b/tests/serve_snapshots_test.bats @@ -0,0 +1,9 @@ +@test "KYVE: serve-snapshots from start height to target height" { + run ./build/ksync serve-snapshots --opt-out -b $HOME/bins/kyved-v1.0.0 -c kaon-1 --start-height 3000 -t 3050 -r -d + [ "$status" -eq 0 ] +} + +@test "KYVE: continue serve-snapshots from current height" { + run ./build/ksync serve-snapshots --opt-out -b $HOME/bins/kyved-v1.0.0 -c kaon-1 -t 3100 -d + [ "$status" -eq 0 ] +} diff --git a/tests/state_sync_test.bats b/tests/state_sync_test.bats index 9090bec..7af12a2 100644 --- a/tests/state_sync_test.bats +++ b/tests/state_sync_test.bats @@ -1,24 +1,24 @@ @test "KYVE: state-sync exact height" { - run ./build/ksync state-sync -b $HOME/bins/kyved-v1.0.0 -c kaon-1 -t 12000 -r -d -y + run ./build/ksync state-sync --opt-out -b $HOME/bins/kyved-v1.0.0 -c kaon-1 -t 12000 -r -d -y [ "$status" -eq 0 ] } @test "KYVE: state-sync recommended nearest height" { - run ./build/ksync state-sync -b $HOME/bins/kyved-v1.0.0 -c kaon-1 -t 15302 -r -d -y + run ./build/ksync state-sync --opt-out -b $HOME/bins/kyved-v1.0.0 -c kaon-1 -t 15302 -r -d -y [ "$status" -eq 0 ] } @test "KYVE: try to state-sync if the app has not been resetted" { - run ./build/ksync state-sync -b $HOME/bins/kyved-v1.0.0 -c kaon-1 -t 12000 -d -y + run ./build/ksync state-sync --opt-out -b $HOME/bins/kyved-v1.0.0 -c kaon-1 -t 12000 -d -y [ "$status" -eq 1 ] } @test "dYdX: state-sync exact height" { - run ./build/ksync state-sync -b $HOME/bins/dydxprotocold-v2.0.1 -c kaon-1 -t 500000 -r -d -y + run ./build/ksync state-sync --opt-out -b $HOME/bins/dydxprotocold-v2.0.1 -c kaon-1 -t 500000 -r -d -y [ "$status" -eq 0 ] } @test "Celestia: state-sync exact height" { - run ./build/ksync state-sync -b $HOME/bins/celestia-appd-v1.3.0 -t 10000 -r -d -y + run ./build/ksync state-sync --opt-out -b $HOME/bins/celestia-appd-v1.3.0 -t 10000 -r -d -y [ "$status" -eq 0 ] } diff --git a/tests/version_test.bats b/tests/version_test.bats index a332f27..2bff852 100644 --- a/tests/version_test.bats +++ b/tests/version_test.bats @@ -1,4 +1,4 @@ @test "KYVE: version" { - run ./build/ksync version + run ./build/ksync version --opt-out [ "$status" -eq 0 ] } diff --git a/types/interfaces.go b/types/interfaces.go index 85cffc9..237a0f0 100644 --- a/types/interfaces.go +++ b/types/interfaces.go @@ -1,9 +1,66 @@ package types +// BlockCollector is an interface defining common behaviour for each +// type of collecting blocks, since blocks can be either obtained +// with requesting the rpc endpoint of the source chain or with +// downloading archived bundles from KYVE +type BlockCollector interface { + // GetEarliestAvailableHeight gets the earliest available block in a block pool + GetEarliestAvailableHeight() int64 + + // GetLatestAvailableHeight gets the latest available block in a block pool + GetLatestAvailableHeight() int64 + + // GetBlock gets the block for the given height + GetBlock(height int64) ([]byte, error) + + // StreamBlocks takes a continuationHeight and a targetHeight and streams + // all blocks in order into a given block channel. This method exits once + // the target height is reached or runs indefinitely depending on the + // exitOnTargetHeight value + StreamBlocks(blockCh chan<- *BlockItem, errorCh chan<- error, continuationHeight, targetHeight int64) +} + +// SnapshotCollector is an interface defining behaviour for +// collecting snapshots +type SnapshotCollector interface { + // GetEarliestAvailableHeight gets the earliest available snapshot height in + // a snapshot pool + GetEarliestAvailableHeight() int64 + + // GetLatestAvailableHeight gets the latest available snapshot height in + // a snapshot pool + GetLatestAvailableHeight() int64 + + // GetInterval gets the snapshot interval + GetInterval() int64 + + // GetCurrentHeight gets the current height of the latest snapshot. This snapshot + // is not guaranteed to be fully available and chunks can still be missing + GetCurrentHeight() (int64, error) + + // GetSnapshotHeight gets the exact height of the nearest snapshot before the target + // height + GetSnapshotHeight(targetHeight int64) int64 + + // GetSnapshotFromBundleId gets the snapshot from the given bundle + GetSnapshotFromBundleId(bundleId int64) (*SnapshotDataItem, error) + + // DownloadChunkFromBundleId downloads the snapshot chunk from the given bundle + DownloadChunkFromBundleId(bundleId int64) ([]byte, error) + + // FindSnapshotBundleIdForHeight searches and returns the bundle id which contains the first + // snapshot chunk for the given height. + // Since we do not know how many chunks a bundle has but expect that the snapshots are ordered by height + // we can apply a binary search to minimize the amount of requests we have to make. This method fails + // if there is no bundle which contains the snapshot at the target height + FindSnapshotBundleIdForHeight(height int64) (int64, error) +} + // Engine is an interface defining common behaviour for each consensus engine. // Currently, both tendermint-v34 and cometbft-v38 are supported type Engine interface { - // GetName gets the engine name + // GetName gets the name of the engine GetName() string // LoadConfig loads and sets the config @@ -15,8 +72,8 @@ type Engine interface { // CloseDBs closes the relevant blockstore and state DBs CloseDBs() error - // GetHomePath gets the home path of the config and data folder - GetHomePath() string + // GetRpcListenAddress gets the address the rpc endpoint is hosted + GetRpcListenAddress() string // GetProxyAppAddress gets the proxy app address of the TSP connection GetProxyAppAddress() string @@ -27,30 +84,17 @@ type Engine interface { // StopProxyApp stops the proxy app connections to the app StopProxyApp() error - // GetChainId gets the chain id of the app - GetChainId() (string, error) - - // GetContinuationHeight gets the block height from the app at which - // KSYNC should proceed block-syncing - GetContinuationHeight() (int64, error) - // DoHandshake does a handshake with the app and needs to be called // before ApplyBlock DoHandshake() error - // ApplyBlock takes the block in the raw format and applies it against - // the app - ApplyBlock(runtime *string, value []byte) error + // ApplyBlock takes a block at height n and n+1 and applies it against + // the cosmos app + ApplyBlock(rawBlock, nextRawBlock []byte) error // ApplyFirstBlockOverP2P applies the first block over the P2P reactor // which is necessary, if the genesis file is bigger than 100MB - ApplyFirstBlockOverP2P(runtime string, value, nextValue []byte) error - - // GetGenesisPath gets the file path to the genesis file - GetGenesisPath() string - - // GetGenesisHeight gets the initial height defined by the genesis file - GetGenesisHeight() (int64, error) + ApplyFirstBlockOverP2P(rawBlock, nextRawBlock []byte) error // GetHeight gets the latest height stored in the blockstore.db GetHeight() int64 @@ -77,7 +121,7 @@ type Engine interface { // StartRPCServer spins up a basic rpc server of the engine which serves // /status, /block and /block_results - StartRPCServer() + StartRPCServer(port int64) // GetState rebuilds the requested state from the blockstore and state.db GetState(height int64) ([]byte, error) @@ -86,13 +130,13 @@ type Engine interface { GetSeenCommit(height int64) ([]byte, error) // OfferSnapshot offers a snapshot over ABCI to the app - OfferSnapshot(value []byte) (string, uint32, error) + OfferSnapshot(rawSnapshot, rawState []byte) error // ApplySnapshotChunk applies a snapshot chunk over ABCI to the app - ApplySnapshotChunk(chunkIndex uint32, value []byte) (string, error) + ApplySnapshotChunk(chunkIndex int64, chunk []byte) error // BootstrapState initializes the tendermint state - BootstrapState(value []byte) error + BootstrapState(rawState, rawSeenCommit, rawBlock []byte) error // PruneBlocks prunes blocks from the block store and state store // from the earliest found base height to the specified height diff --git a/types/types.go b/types/types.go index e32bda6..12def03 100644 --- a/types/types.go +++ b/types/types.go @@ -2,10 +2,9 @@ package types import ( "encoding/json" - "time" ) -type HeightResponse struct { +type AbciInfoResponse struct { Result struct { Response struct { LastBlockHeight string `json:"last_block_height"` @@ -48,6 +47,33 @@ type DataItem struct { type Bundle = []DataItem +type SnapshotDataItem struct { + Key string `json:"key"` + Value struct { + Snapshot json.RawMessage `json:"snapshot"` + Block json.RawMessage `json:"block"` + SeenCommit json.RawMessage `json:"seenCommit"` + State json.RawMessage `json:"state"` + ChunkIndex uint32 `json:"chunkIndex"` + Chunk []byte `json:"chunk"` + } `json:"value"` +} + +type SnapshotBundle = []SnapshotDataItem + +type Snapshot struct { + Height uint64 `json:"height,omitempty"` + Format uint32 `json:"format,omitempty"` + Chunks uint32 `json:"chunks,omitempty"` + Hash []byte `json:"hash,omitempty"` + Metadata []byte `json:"metadata,omitempty"` +} + +type BlockItem struct { + Height int64 + Block json.RawMessage +} + type Pagination struct { NextKey []byte `json:"next_key"` } @@ -67,10 +93,6 @@ type FinalizedBundlesResponse = struct { Pagination Pagination `json:"pagination"` } -type FinalizedBundleResponse = struct { - FinalizedBundle FinalizedBundle `json:"finalized_bundle"` -} - type SupportedChain = struct { BlockPoolId string `json:"block_pool_id"` ChainId string `json:"chain-id"` @@ -80,19 +102,6 @@ type SupportedChain = struct { StatePoolId string `json:"state_pool_id"` } -type SupportedChains = struct { - Mainnet []SupportedChain `json:"kyve-1"` - Kaon []SupportedChain `json:"kaon-1"` -} - -type BackupConfig = struct { - Interval int64 - KeepRecent int64 - Src string - Dest string - Compression string -} - type Networks struct { Kaon *NetworkProperties `yaml:"kaon-1,omitempty"` Kyve *NetworkProperties `yaml:"kyve-1,omitempty"` @@ -152,8 +161,3 @@ type Entry struct { type SourceRegistry struct { Entries map[string]Entry `yaml:",inline"` } - -type BlockRpcConfig struct { - Endpoint string - RequestTimeout time.Duration -} diff --git a/utils/binaries.go b/utils/binaries.go deleted file mode 100644 index 251416f..0000000 --- a/utils/binaries.go +++ /dev/null @@ -1,203 +0,0 @@ -package utils - -import ( - "fmt" - "github.com/KYVENetwork/ksync/types" - "os" - "os/exec" - "strings" - "syscall" -) - -func GetHomePathFromBinary(binaryPath string) string { - cmdPath, err := exec.LookPath(binaryPath) - if err != nil { - logger.Error().Msg(fmt.Sprintf("failed to lookup binary path: %s", err.Error())) - os.Exit(1) - } - - cmd := exec.Command(cmdPath) - - // if we run with cosmovisor we start with the cosmovisor run command - if strings.HasSuffix(binaryPath, "cosmovisor") { - cmd.Args = append(cmd.Args, "run") - cmd.Env = append(os.Environ(), "COSMOVISOR_DISABLE_LOGS=true") - } - - out, err := cmd.CombinedOutput() - if err != nil { - logger.Error().Msg("failed to get output of binary") - os.Exit(1) - } - - // here we search for a specific line in the binary output when simply - // executed without arguments. In the output, the default home path - // is printed, which is parsed and used by KSYNC - for _, line := range strings.Split(string(out), "\n") { - if strings.Contains(line, "--home") { - if strings.Count(line, "\"") != 2 { - logger.Error().Msg(fmt.Sprintf("did not found default home path in help line: %s", line)) - os.Exit(1) - } - - return strings.Split(line, "\"")[1] - } - } - - logger.Error().Msg("did not found default home path in entire binary output") - os.Exit(1) - return "" -} - -func GetEnginePathFromBinary(binaryPath string) string { - cmdPath, err := exec.LookPath(binaryPath) - if err != nil { - logger.Error().Msg(fmt.Sprintf("failed to lookup binary path: %s", err.Error())) - os.Exit(1) - } - - cmd := exec.Command(cmdPath) - - // if we run with cosmovisor we start with the cosmovisor run command - if strings.HasSuffix(binaryPath, "cosmovisor") { - cmd.Args = append(cmd.Args, "run") - cmd.Env = append(os.Environ(), "COSMOVISOR_DISABLE_LOGS=true") - } - - cmd.Args = append(cmd.Args, "version", "--long") - - out, err := cmd.CombinedOutput() - if err != nil { - logger.Error().Msg("failed to get output of binary") - os.Exit(1) - } - - for _, engine := range []string{"github.com/tendermint/tendermint@v", "github.com/cometbft/cometbft@v"} { - for _, line := range strings.Split(string(out), "\n") { - if strings.Contains(line, fmt.Sprintf("- %s", engine)) { - dependency := strings.Split(strings.ReplaceAll(strings.Split(line, " => ")[len(strings.Split(line, " => "))-1], "- ", ""), "@v") - - if strings.Contains(dependency[1], "0.34.") && strings.Contains(dependency[0], "celestia-core") { - return EngineCelestiaCoreV34 - } else if strings.Contains(dependency[1], "0.34.") { - return EngineTendermintV34 - } else if strings.Contains(dependency[1], "0.37.") { - return EngineCometBFTV37 - } else if strings.Contains(dependency[1], "0.38.") { - return EngineCometBFTV38 - } - } - } - } - - logger.Error().Msg("did not found engine in entire binary output") - os.Exit(1) - return "" -} - -func StartBinaryProcessForDB(engine types.Engine, binaryPath string, debug bool, args []string) (processId int, err error) { - if binaryPath == "" { - return - } - - cmdPath, err := exec.LookPath(binaryPath) - if err != nil { - return processId, fmt.Errorf("failed to lookup binary path: %w", err) - } - - cmd := exec.Command(cmdPath) - - // if we run with cosmovisor we start with the cosmovisor run command - if strings.HasSuffix(binaryPath, "cosmovisor") { - cmd.Args = append(cmd.Args, "run") - cmd.Env = append(os.Environ(), "COSMOVISOR_DISABLE_LOGS=true") - } - - if err := engine.LoadConfig(); err != nil { - return processId, fmt.Errorf("failed to load engine config: %w", err) - } - - cmd.Args = append(cmd.Args, "start", - "--home", - engine.GetHomePath(), - "--with-tendermint=false", - "--address", - engine.GetProxyAppAddress(), - ) - - cmd.Args = append(cmd.Args, args...) - - if debug { - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - } - - if err := cmd.Start(); err != nil { - return processId, fmt.Errorf("failed to start binary process: %w", err) - } - - processId = cmd.Process.Pid - return -} - -func StartBinaryProcessForP2P(engine types.Engine, binaryPath string, debug bool, args []string) (processId int, err error) { - if binaryPath == "" { - return - } - - cmdPath, err := exec.LookPath(binaryPath) - if err != nil { - return processId, fmt.Errorf("failed to lookup binary path: %w", err) - } - - cmd := exec.Command(cmdPath) - - // if we run with cosmovisor we start with the cosmovisor run command - if strings.HasSuffix(binaryPath, "cosmovisor") { - cmd.Args = append(cmd.Args, "run") - cmd.Env = append(os.Environ(), "COSMOVISOR_DISABLE_LOGS=true") - } - - cmd.Args = append(cmd.Args, "start", - "--home", - engine.GetHomePath(), - "--p2p.pex=false", - "--p2p.persistent_peers", - "", - "--p2p.private_peer_ids", - "", - "--p2p.unconditional_peer_ids", - "", - ) - - cmd.Args = append(cmd.Args, args...) - - if debug { - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - } - - if err := cmd.Start(); err != nil { - return processId, fmt.Errorf("failed to start binary process: %w", err) - } - - processId = cmd.Process.Pid - return -} - -func StopProcessByProcessId(processId int) error { - if processId == 0 { - return nil - } - - process, err := os.FindProcess(processId) - if err != nil { - return fmt.Errorf("failed to find binary process: %w", err) - } - - if err = process.Signal(syscall.SIGTERM); err != nil { - return fmt.Errorf("failed to stop binary process with SIGTERM: %w", err) - } - - return nil -} diff --git a/collectors/bundles/bundles.go b/utils/bundles.go similarity index 50% rename from collectors/bundles/bundles.go rename to utils/bundles.go index 4c60134..499a924 100644 --- a/collectors/bundles/bundles.go +++ b/utils/bundles.go @@ -1,16 +1,31 @@ -package bundles +package utils import ( "encoding/base64" "fmt" + "github.com/KYVENetwork/ksync/flags" "github.com/KYVENetwork/ksync/types" - "github.com/KYVENetwork/ksync/utils" "github.com/tendermint/tendermint/libs/json" - "strconv" + "strings" ) +func GetPool(restEndpoint string, poolId int64) (*types.PoolResponse, error) { + data, err := GetFromUrl(fmt.Sprintf("%s/kyve/query/v1beta1/pool/%d", restEndpoint, poolId)) + if err != nil { + return nil, fmt.Errorf("failed to query pool %d", poolId) + } + + var poolResponse types.PoolResponse + + if err = json.Unmarshal(data, &poolResponse); err != nil { + return nil, fmt.Errorf("failed to unmarshal pool response: %w", err) + } + + return &poolResponse, nil +} + func GetFinalizedBundlesPageWithOffset(restEndpoint string, poolId int64, paginationLimit, paginationOffset int64, paginationKey string, reverse bool) ([]types.FinalizedBundle, string, error) { - raw, err := utils.GetFromUrlWithBackoff(fmt.Sprintf( + raw, err := GetFromUrl(fmt.Sprintf( "%s/kyve/v1/bundles/%d?pagination.limit=%d&pagination.offset=%d&pagination.key=%s&pagination.reverse=%v", restEndpoint, poolId, @@ -39,7 +54,7 @@ func GetFinalizedBundlesPage(restEndpoint string, poolId int64, paginationLimit } func GetFinalizedBundleById(restEndpoint string, poolId int64, bundleId int64) (*types.FinalizedBundle, error) { - raw, err := utils.GetFromUrlWithBackoff(fmt.Sprintf( + raw, err := GetFromUrl(fmt.Sprintf( "%s/kyve/v1/bundles/%d/%d", restEndpoint, poolId, @@ -58,50 +73,18 @@ func GetFinalizedBundleById(restEndpoint string, poolId int64, bundleId int64) ( return &finalizedBundle, nil } -func GetFinalizedBundleByIndex(restEndpoint string, poolId int64, index int64) (*types.FinalizedBundle, error) { - raw, err := utils.GetFromUrlWithBackoff(fmt.Sprintf( - "%s/kyve/v1/bundles/%d?index=%d", - restEndpoint, - poolId, - index, - )) - if err != nil { - return nil, err - } - - var bundlesResponse types.FinalizedBundlesResponse - - if err := json.Unmarshal(raw, &bundlesResponse); err != nil { - return nil, err - } - - if len(bundlesResponse.FinalizedBundles) == 1 { - return &bundlesResponse.FinalizedBundles[0], nil - } - - return nil, fmt.Errorf("failed to find finalized bundle for index %d: %w", index, err) -} - -func GetFinalizedBundleForBlockHeight(chainRest string, blockPool types.PoolResponse, height int64) (*types.FinalizedBundle, error) { - startKey, err := strconv.ParseInt(blockPool.Pool.Data.StartKey, 10, 64) - if err != nil { - return nil, fmt.Errorf("failed to parse start key %s: %w", blockPool.Pool.Data.StartKey, err) - } - - // index is height - startKey - return GetFinalizedBundleByIndex(chainRest, blockPool.Pool.Id, height-startKey) -} - -func GetDataFromFinalizedBundle(bundle types.FinalizedBundle, storageRest string) ([]byte, error) { +// GetDataFromFinalizedBundle downloads the data from the provided bundle, verify if the checksum on the KYVE +// chain matches and finally decompresses it before returning +func GetDataFromFinalizedBundle(bundle types.FinalizedBundle) ([]byte, error) { // retrieve bundle from storage provider - data, err := RetrieveDataFromStorageProvider(bundle, storageRest) + data, err := RetrieveDataFromStorageProvider(bundle) if err != nil { return nil, fmt.Errorf("failed to retrieve data from storage provider with storage id %s: %w", bundle.StorageId, err) } // validate bundle with sha256 checksum - if utils.CreateSha256Checksum(data) != bundle.DataHash { - return nil, fmt.Errorf("found different sha256 checksum on bundle with storage id %s: expected = %s found = %s", bundle.StorageId, utils.CreateSha256Checksum(data), bundle.DataHash) + if CreateSha256Checksum(data) != bundle.DataHash { + return nil, fmt.Errorf("found different sha256 checksum on bundle with storage id %s: expected = %s found = %s", bundle.StorageId, CreateSha256Checksum(data), bundle.DataHash) } // decompress bundle @@ -113,39 +96,29 @@ func GetDataFromFinalizedBundle(bundle types.FinalizedBundle, storageRest string return deflated, nil } -func RetrieveDataFromStorageProvider(bundle types.FinalizedBundle, storageRest string) ([]byte, error) { - id, err := strconv.ParseUint(bundle.StorageProviderId, 10, 64) - if err != nil { - return nil, fmt.Errorf("could not parse uint from storage provider id: %w", err) +func RetrieveDataFromStorageProvider(bundle types.FinalizedBundle) ([]byte, error) { + if flags.StorageRest != "" { + return GetFromUrl(fmt.Sprintf("%s/%s", strings.TrimSuffix(flags.StorageRest, "/"), bundle.StorageId)) } - if storageRest != "" { - return utils.GetFromUrlWithBackoff(fmt.Sprintf("%s/%s", storageRest, bundle.StorageId)) - } - - switch id { - case 1: - return utils.GetFromUrlWithBackoff(fmt.Sprintf("%v/%s", utils.RestEndpointArweave, bundle.StorageId)) - case 2: - return utils.GetFromUrlWithBackoff(fmt.Sprintf("%v/%s", utils.RestEndpointBundlr, bundle.StorageId)) - case 3: - return utils.GetFromUrlWithBackoff(fmt.Sprintf("%v/%s", utils.RestEndpointKYVEStorage, bundle.StorageId)) - case 4: - return utils.GetFromUrlWithBackoff(fmt.Sprintf("%v/%s", utils.RestEndpointTurboStorage, bundle.StorageId)) + switch bundle.StorageProviderId { + case "1": + return GetFromUrl(fmt.Sprintf("%s/%s", RestEndpointArweave, bundle.StorageId)) + case "2": + return GetFromUrl(fmt.Sprintf("%s/%s", RestEndpointBundlr, bundle.StorageId)) + case "3": + return GetFromUrl(fmt.Sprintf("%s/%s", RestEndpointKYVEStorage, bundle.StorageId)) + case "4": + return GetFromUrl(fmt.Sprintf("%s/%s", RestEndpointTurboStorage, bundle.StorageId)) default: return nil, fmt.Errorf("bundle has an invalid storage provider id %s. canceling sync", bundle.StorageProviderId) } } func DecompressBundleFromStorageProvider(bundle types.FinalizedBundle, data []byte) ([]byte, error) { - id, err := strconv.ParseUint(bundle.CompressionId, 10, 64) - if err != nil { - return nil, fmt.Errorf("could not parse uint from compression id: %w", err) - } - - switch id { - case 1: - return utils.DecompressGzip(data) + switch bundle.CompressionId { + case "1": + return DecompressGzip(data) default: return nil, fmt.Errorf("bundle has an invalid compression id %s. canceling sync", bundle.CompressionId) } diff --git a/utils/constants.go b/utils/constants.go index abc61d3..14e3545 100644 --- a/utils/constants.go +++ b/utils/constants.go @@ -13,36 +13,23 @@ const ( RestEndpointBundlr = "https://arweave.net" RestEndpointKYVEStorage = "https://storage.kyve.network" RestEndpointTurboStorage = "https://arweave.net" - - SegmentKey = "quSEhAvH5fqlHyop9r9mDGxgd97ro3vQ" ) const ( - KSyncRuntimeTendermint = "@kyvejs/tendermint" - KSyncRuntimeTendermintBsync = "@kyvejs/tendermint-bsync" - KSyncRuntimeTendermintSsync = "@kyvejs/tendermint-ssync" + RuntimeTendermint = "@kyvejs/tendermint" + RuntimeTendermintBsync = "@kyvejs/tendermint-bsync" + RuntimeTendermintSsync = "@kyvejs/tendermint-ssync" ) const ( - EngineTendermintV34 = "tendermint-v0.34" - EngineCometBFTV37 = "cometbft-v0.37" - EngineCometBFTV38 = "cometbft-v0.38" - EngineCelestiaCoreV34 = "celestia-core-v0.34" - - EngineTendermintV34Legacy = "tendermint-v34" - EngineCometBFTV37Legacy = "cometbft-v37" - EngineCometBFTV38Legacy = "cometbft-v38" - EngineCelestiaCoreV34Legacy = "celestia-core-v34" - - EngineTendermintLegacy = "tendermint" - EngineCometBFTLegacy = "cometbft" - EngineCelestiaCoreLegacy = "tendermint-celestiacore" + EngineTendermintV34 = "TENDERMINT-V34" + EngineCelestiaCoreV34 = "CELESTIA-CORE-V34" + EngineCometBFTV37 = "COMETBFT-V37" + EngineCometBFTV38 = "COMETBFT-V38" ) const ( - DefaultEngine = EngineTendermintV34 DefaultChainId = ChainIdMainnet - DefaultBackupPath = "~/.ksync/backups" DefaultRpcServerPort = 7777 DefaultSnapshotServerPort = 7878 ) @@ -54,25 +41,10 @@ const ( SnapshotPruningAheadFactor = 3 SnapshotPruningWindowFactor = 6 BackoffMaxRetries = 10 - RequestTimeoutMS = 250 + RequestTimeoutMS = 100 RequestBlocksTimeoutMS = 250 ) -const ( - SYNC_STARTED = "SYNC_STARTED" - SYNC_COMPLETED = "SYNC_COMPLETED" - BLOCK_SYNC = "BLOCK_SYNC" - STATE_SYNC = "STATE_SYNC" - HEIGHT_SYNC = "HEIGHT_SYNC" - SERVE_SNAPSHOTS = "SERVE_SNAPSHOTS" - INFO = "INFO" - RESET = "RESET" - PRUNE = "PRUNE" - BACKUP = "BACKUP" - VERSION = "VERSION" - ENGINES = "ENGINES" -) - const ( DefaultRegistryURL = "https://raw.githubusercontent.com/KYVENetwork/source-registry/main/.github/registry.yml" ) diff --git a/utils/events.go b/utils/events.go deleted file mode 100644 index fd8d3ac..0000000 --- a/utils/events.go +++ /dev/null @@ -1,304 +0,0 @@ -package utils - -import ( - "fmt" - "github.com/KYVENetwork/ksync/types" - "github.com/google/uuid" - "github.com/segmentio/analytics-go" - "math" - "os" - "path/filepath" - "runtime" - "runtime/debug" - "strings" - "time" -) - -var ( - syncId = uuid.New().String() - client = analytics.New(SegmentKey) -) - -func getUserId() (string, error) { - home, err := os.UserHomeDir() - if err != nil { - return "", err - } - - ksyncDir := filepath.Join(home, ".ksync") - if _, err = os.Stat(ksyncDir); os.IsNotExist(err) { - if err := os.Mkdir(ksyncDir, 0o755); err != nil { - return "", err - } - } - - userId := uuid.New().String() - - idFile := filepath.Join(ksyncDir, "id") - if _, err = os.Stat(idFile); os.IsNotExist(err) { - if err := os.WriteFile(idFile, []byte(userId), 0o755); err != nil { - return "", err - } - } else { - data, err := os.ReadFile(idFile) - if err != nil { - return "", err - } - userId = string(data) - } - - return userId, nil -} - -func getContext() *analytics.Context { - version := "local" - build, _ := debug.ReadBuildInfo() - - if strings.TrimSpace(build.Main.Version) != "" { - version = strings.TrimSpace(build.Main.Version) - } - - timezone, _ := time.Now().Zone() - locale := os.Getenv("LANG") - - return &analytics.Context{ - App: analytics.AppInfo{ - Name: "ksync", - Version: version, - }, - Location: analytics.LocationInfo{}, - OS: analytics.OSInfo{ - Name: fmt.Sprintf("%s %s", runtime.GOOS, runtime.GOARCH), - }, - Locale: locale, - Timezone: timezone, - } -} - -func TrackVersionEvent(optOut bool) { - if optOut { - return - } - - userId, err := getUserId() - if err != nil { - return - } - - err = client.Enqueue(analytics.Track{ - UserId: userId, - Event: VERSION, - Context: getContext(), - }) - - err = client.Close() - _ = err -} - -func TrackEnginesEvent(optOut bool) { - if optOut { - return - } - - userId, err := getUserId() - if err != nil { - return - } - - err = client.Enqueue(analytics.Track{ - UserId: userId, - Event: ENGINES, - Context: getContext(), - }) - - err = client.Close() - _ = err -} - -func TrackInfoEvent(chainId string, optOut bool) { - if optOut { - return - } - - userId, err := getUserId() - if err != nil { - return - } - - err = client.Enqueue(analytics.Track{ - UserId: userId, - Event: INFO, - Properties: analytics.NewProperties().Set("chain_id", chainId), - Context: getContext(), - }) - - err = client.Close() - _ = err -} - -func TrackBackupEvent(backupCompression string, backupKeepRecent int64, optOut bool) { - if optOut { - return - } - - userId, err := getUserId() - if err != nil { - return - } - - err = client.Enqueue(analytics.Track{ - UserId: userId, - Event: BACKUP, - Properties: analytics.NewProperties(). - Set("backup_compression", backupCompression). - Set("backup_keep_recent", backupKeepRecent), - Context: getContext(), - }) - - err = client.Close() - _ = err -} - -func TrackResetEvent(optOut bool) { - if optOut { - return - } - - userId, err := getUserId() - if err != nil { - return - } - - err = client.Enqueue(analytics.Track{ - UserId: userId, - Event: RESET, - Context: getContext(), - }) - - err = client.Close() - _ = err -} - -func TrackPruningEvent(untilHeight int64, optOut bool) { - if optOut { - return - } - - userId, err := getUserId() - if err != nil { - return - } - - err = client.Enqueue(analytics.Track{ - UserId: userId, - Event: PRUNE, - Properties: analytics.NewProperties(). - Set("until_height", untilHeight), - Context: getContext(), - }) - - err = client.Close() - _ = err -} - -func TrackServeSnapshotsEvent(engine types.Engine, chainId, chainRest, storageRest string, snapshotPort int64, rpcServer bool, rpcServerPort int64, startHeight int64, pruning, keepSnapshots, debug, optOut bool) { - if optOut { - return - } - - userId, err := getUserId() - if err != nil { - return - } - - project, err := engine.GetChainId() - if err != nil { - return - } - - currentHeight := engine.GetHeight() - - err = client.Enqueue(analytics.Track{ - UserId: userId, - Event: SERVE_SNAPSHOTS, - Properties: analytics.NewProperties(). - Set("chain_id", chainId). - Set("chain_rest", chainRest). - Set("storage_rest", storageRest). - Set("project", project). - Set("current_height", currentHeight). - Set("snapshot_port", snapshotPort). - Set("rpc_server", rpcServer). - Set("rpc_server_port", rpcServerPort). - Set("start_height", startHeight). - Set("pruning", pruning). - Set("keep_snapshots", keepSnapshots). - Set("debug", debug), - Context: getContext(), - }) - - err = client.Close() - _ = err -} - -func TrackSyncStartEvent(engine types.Engine, syncType, chainId, chainRest, storageRest string, targetHeight int64, optOut bool) { - if optOut { - return - } - - userId, err := getUserId() - if err != nil { - return - } - - project, err := engine.GetChainId() - if err != nil { - return - } - - currentHeight := engine.GetHeight() - - err = client.Enqueue(analytics.Track{ - UserId: userId, - Event: SYNC_STARTED, - Properties: analytics.NewProperties(). - Set("sync_id", syncId). - Set("sync_type", syncType). - Set("chain_id", chainId). - Set("chain_rest", chainRest). - Set("storage_rest", storageRest). - Set("project", project). - Set("current_height", currentHeight). - Set("target_height", targetHeight), - Context: getContext(), - }) - _ = err - - return -} - -func TrackSyncCompletedEvent(stateSyncHeight, blocksSynced, targetHeight int64, elapsed float64, optOut bool) { - if optOut { - return - } - - userId, err := getUserId() - if err != nil { - return - } - - err = client.Enqueue(analytics.Track{ - UserId: userId, - Event: SYNC_COMPLETED, - Properties: analytics.NewProperties(). - Set("sync_id", syncId). - Set("state_sync_height", stateSyncHeight). - Set("blocks_synced", blocksSynced). - Set("target_height", targetHeight). - Set("duration", math.Floor(elapsed*100)/100), - Context: getContext(), - }) - - err = client.Close() - _ = err -} diff --git a/utils/genesis.go b/utils/genesis.go deleted file mode 100644 index 8b1ad9c..0000000 --- a/utils/genesis.go +++ /dev/null @@ -1,62 +0,0 @@ -package utils - -import ( - "encoding/json" - "fmt" - "os" - "strconv" -) - -func GetInitialHeightFromGenesisFile(genesisPath string) (int64, error) { - genesisFile, err := os.ReadFile(genesisPath) - if err != nil { - return 0, fmt.Errorf("error opening genesis.json at %s: %w", genesisPath, err) - } - - var value struct { - InitialHeight string `json:"initial_height"` - } - - if err := json.Unmarshal(genesisFile, &value); err != nil { - return 0, err - } - - return strconv.ParseInt(value.InitialHeight, 10, 64) -} - -func FormatGenesisFile(genesisPath string) error { - genesisFile, err := os.ReadFile(genesisPath) - if err != nil { - return fmt.Errorf("error opening genesis.json at %s: %w", genesisPath, err) - } - - var value struct { - InitialHeight int `json:"initial_height"` - } - - // if we can not unmarshal the initial_height to an integer it means - // that it is of type string which is desired. In this case we return - // and don't format the genesis file - if err := json.Unmarshal(genesisFile, &value); err != nil { - return nil - } - - var genesis map[string]interface{} - - if err := json.Unmarshal(genesisFile, &genesis); err != nil { - return fmt.Errorf("failed to unmarshal genesis file: %w", err) - } - - genesis["initial_height"] = strconv.Itoa(value.InitialHeight) - - genesisJson, err := json.MarshalIndent(genesis, "", " ") - if err != nil { - return fmt.Errorf("failed to marshal genesis file: %w", err) - } - - if err := os.WriteFile(genesisPath, genesisJson, os.ModePerm); err != nil { - return fmt.Errorf("failed to write genesis.json: %w", err) - } - - return nil -} diff --git a/utils/logger.go b/utils/logger.go deleted file mode 100644 index a38525a..0000000 --- a/utils/logger.go +++ /dev/null @@ -1,37 +0,0 @@ -package utils - -import ( - "fmt" - "github.com/rs/zerolog" - "io" - "os" -) - -func KsyncLogger(moduleName string) zerolog.Logger { - writer := io.MultiWriter(os.Stdout) - customConsoleWriter := zerolog.ConsoleWriter{Out: writer} - customConsoleWriter.FormatCaller = func(i interface{}) string { - return "\x1b[36m[KSYNC]\x1b[0m" - } - - logger := zerolog.New(customConsoleWriter).With().Str("module", moduleName).Timestamp().Logger() - return logger -} - -func LogFormatter(keyvals ...interface{}) zerolog.Logger { - writer := io.MultiWriter(os.Stdout) - customConsoleWriter := zerolog.ConsoleWriter{Out: writer} - customConsoleWriter.FormatCaller = func(i interface{}) string { - return "\x1b[36m[APP]\x1b[0m" - } - - logger := zerolog.New(customConsoleWriter).With() - - if len(keyvals) > 1 { - for i := 0; i < len(keyvals); i = i + 2 { - logger = logger.Str(fmt.Sprintf("%v", keyvals[i]), fmt.Sprintf("%v", keyvals[i+1])) - } - } - - return logger.Timestamp().Logger() -} diff --git a/utils/rpc.go b/utils/rpc.go deleted file mode 100644 index 9ad2009..0000000 --- a/utils/rpc.go +++ /dev/null @@ -1,22 +0,0 @@ -package utils - -import ( - "fmt" - "github.com/KYVENetwork/ksync/types" - "github.com/tendermint/tendermint/libs/json" -) - -func GetStatusFromRpc(blockRpcConfig types.BlockRpcConfig) (*types.StatusResponse, error) { - result, err := GetFromUrlWithOptions(fmt.Sprintf("%s/status", blockRpcConfig.Endpoint), - GetFromUrlOptions{SkipTLSVerification: true}, - ) - if err != nil { - return nil, err - } - var statusResponse types.StatusResponse - if err := json.Unmarshal(result, &statusResponse); err != nil { - return nil, err - } - - return &statusResponse, nil -} diff --git a/utils/utils.go b/utils/utils.go index b49cee0..b414634 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -4,8 +4,10 @@ import ( "bytes" "compress/gzip" "crypto/sha256" - "crypto/tls" + "encoding/json" "fmt" + "github.com/KYVENetwork/ksync/logger" + "github.com/KYVENetwork/ksync/metrics" "io" "math" "net/http" @@ -17,27 +19,26 @@ import ( "time" ) -var ( - logger = KsyncLogger("utils") -) - func GetVersion() string { version, ok := runtimeDebug.ReadBuildInfo() if !ok { panic("failed to get ksync version") } + if version.Main.Version == "" { + return "dev" + } + return strings.TrimSpace(version.Main.Version) } // getFromUrl tries to fetch data from url with a custom User-Agent header -func getFromUrl(url string, transport *http.Transport) ([]byte, error) { - // Create a custom http.Client with the desired User-Agent header - client := &http.Client{Transport: http.DefaultTransport} +func getFromUrl(url string) ([]byte, error) { + // Log debug info + logger.Logger.Debug().Str("url", url).Msg("GET") - if transport != nil { - client = &http.Client{Transport: transport} - } + // Create a custom http.Client with the desired User-Agent header + httpClient := &http.Client{Transport: http.DefaultTransport} // Create a new GET request request, err := http.NewRequest("GET", url, nil) @@ -52,13 +53,13 @@ func getFromUrl(url string, transport *http.Transport) ([]byte, error) { if strings.HasPrefix(version, "v") { version = strings.TrimPrefix(version, "v") } - request.Header.Set("User-Agent", fmt.Sprintf("ksync/%v (%v / %v / %v)", version, runtime.GOOS, runtime.GOARCH, runtime.Version())) + request.Header.Set("User-Agent", fmt.Sprintf("ksync/%s (%s / %s / %s)", version, runtime.GOOS, runtime.GOARCH, runtime.Version())) } else { - request.Header.Set("User-Agent", fmt.Sprintf("ksync/dev (%v / %v / %v)", runtime.GOOS, runtime.GOARCH, runtime.Version())) + request.Header.Set("User-Agent", fmt.Sprintf("ksync/dev (%s / %s / %s)", runtime.GOOS, runtime.GOARCH, runtime.Version())) } // Perform the request - response, err := client.Do(request) + response, err := httpClient.Do(request) if err != nil { return nil, err } @@ -76,60 +77,34 @@ func getFromUrl(url string, transport *http.Transport) ([]byte, error) { return data, nil } -// getFromUrlWithBackoff tries to fetch data from url with exponential backoff -func getFromUrlWithBackoff(url string, transport *http.Transport) (data []byte, err error) { +// GetFromUrl tries to fetch data from url with exponential backoff, we usually +// always want a request to succeed so it is implemented by default +func GetFromUrl(url string) (data []byte, err error) { for i := 0; i < BackoffMaxRetries; i++ { - data, err = getFromUrl(url, transport) + data, err = getFromUrl(url) if err != nil { + metrics.IncreaseFailedRequests() delaySec := math.Pow(2, float64(i)) - delay := time.Duration(delaySec) * time.Second - logger.Error().Msg(fmt.Sprintf("failed to fetch from url \"%s\" with error \"%s\", retrying in %d seconds", url, err, int(delaySec))) - time.Sleep(delay) + logger.Logger.Error().Msgf("failed to fetch from url \"%s\" with error \"%s\", retrying in %d seconds", url, err, int(delaySec)) + time.Sleep(time.Duration(delaySec) * time.Second) continue } + metrics.IncreaseSuccessfulRequests() + // only log success message if there were errors previously if i > 0 { - logger.Info().Msg(fmt.Sprintf("successfully fetch data from url %s", url)) + logger.Logger.Info().Msgf("successfully fetched data from url %s", url) } return } - logger.Error().Msg(fmt.Sprintf("failed to fetch data from url within maximum retry limit of %d", BackoffMaxRetries)) + logger.Logger.Error().Msgf("failed to fetch data from url within maximum retry limit of %d", BackoffMaxRetries) return } -// GetFromUrl tries to fetch data from url with a custom User-Agent header -func GetFromUrl(url string) ([]byte, error) { - return getFromUrl(url, nil) -} - -type GetFromUrlOptions struct { - SkipTLSVerification bool - WithBackoff bool -} - -// GetFromUrlWithOptions tries to fetch data from url with a custom User-Agent header and custom options -func GetFromUrlWithOptions(url string, options GetFromUrlOptions) ([]byte, error) { - var transport *http.Transport - if options.SkipTLSVerification { - transport = &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - } - } - if options.WithBackoff { - return getFromUrlWithBackoff(url, transport) - } - return getFromUrl(url, transport) -} - -// GetFromUrlWithBackoff tries to fetch data from url with exponential backoff -func GetFromUrlWithBackoff(url string) (data []byte, err error) { - return GetFromUrlWithOptions(url, GetFromUrlOptions{SkipTLSVerification: true, WithBackoff: true}) -} - func CreateSha256Checksum(input []byte) (hash string) { h := sha256.New() h.Write(input) @@ -151,30 +126,6 @@ func DecompressGzip(input []byte) ([]byte, error) { return out.Bytes(), nil } -func IsFileGreaterThanOrEqualTo100MB(filePath string) (bool, error) { - fileInfo, err := os.Stat(filePath) - if err != nil { - return false, err - } - - // Get file size in bytes - fileSize := fileInfo.Size() - - // Convert to MB - fileSizeMB := float64(fileSize) / (1024 * 1024) - - // Check if the file size is >= 100MB - if fileSizeMB >= 100.0 { - return true, nil - } - - return false, nil -} - -func ParseBlockHeightFromKey(key string) (int64, error) { - return strconv.ParseInt(key, 10, 64) -} - func ParseSnapshotFromKey(key string) (height int64, chunkIndex int64, err error) { // if key is empty we are at height 0 if key == "" { @@ -200,21 +151,40 @@ func ParseSnapshotFromKey(key string) (height int64, chunkIndex int64, err error return } -func GetChainRest(chainId, chainRest string) string { - if chainRest != "" { - // trim trailing slash - return strings.TrimSuffix(chainRest, "/") +func IsUpgradeHeight(homePath string, height int64) bool { + upgradeInfoPath := fmt.Sprintf("%s/data/upgrade-info.json", homePath) + + upgradeInfo, err := os.ReadFile(upgradeInfoPath) + if err != nil { + return false } - // if no custom rest endpoint was given we take it from the chainId - switch chainId { - case ChainIdMainnet: - return RestEndpointMainnet - case ChainIdKaon: - return RestEndpointKaon - case ChainIdKorellia: - return RestEndpointKorellia - default: - panic(fmt.Sprintf("flag --chain-id has to be either \"%s\", \"%s\" or \"%s\"", ChainIdMainnet, ChainIdKaon, ChainIdKorellia)) + var upgrade struct { + Height int64 `json:"height"` } + + if err := json.Unmarshal(upgradeInfo, &upgrade); err != nil { + return false + } + + return upgrade.Height == height +} + +func GetUserConfirmationInput() (bool, error) { + startTime := time.Now() + answer := "" + + if _, err := fmt.Scan(&answer); err != nil { + return false, fmt.Errorf("failed to read in user input: %w", err) + } + + metrics.SetUserConfirmationInput(answer) + metrics.SetUserConfirmationDuration(time.Since(startTime)) + + if strings.ToLower(answer) != "y" { + logger.Logger.Info().Msg("abort") + return false, nil + } + + return true, nil }