From 0d91408f6beae6693c1fb241b5efbc332196f869 Mon Sep 17 00:00:00 2001 From: Gui Iribarren Date: Tue, 12 Mar 2024 20:42:10 +0100 Subject: [PATCH] statesync: refactor to fetch params from RPC server instead of API * apiclient: drop DefaultAPIUrls and FetchChainHeightAndHash* * ci: drop redundant env vars --- apiclient/client.go | 10 ------ apiclient/helpers.go | 32 ----------------- cmd/node/main.go | 45 +++--------------------- config/config.go | 5 ++- dockerfiles/testsuite/docker-compose.yml | 4 --- dockerfiles/testsuite/start_test.sh | 1 - vochain/apputils.go | 14 ++++++++ vochain/start.go | 33 +++++++++++++++++ 8 files changed, 53 insertions(+), 91 deletions(-) diff --git a/apiclient/client.go b/apiclient/client.go index 4121bfa26..43099b521 100644 --- a/apiclient/client.go +++ b/apiclient/client.go @@ -36,16 +36,6 @@ const ( DefaultTimeout = 10 * time.Second ) -// DefaultAPIUrls is a map of default API URLs for each network. -var DefaultAPIUrls = map[string]string{ - "dev": "https://api-dev.vocdoni.net/v2/", - "develop": "https://api-dev.vocdoni.net/v2/", - "stg": "https://api-stg.vocdoni.net/v2/", - "stage": "https://api-stg.vocdoni.net/v2/", - "lts": "https://api.vocdoni.io/v2/", - "prod": "https://api.vocdoni.io/v2/", -} - // HTTPclient is the Vocdoni API HTTP client. type HTTPclient struct { c *http.Client diff --git a/apiclient/helpers.go b/apiclient/helpers.go index 403c4258a..f344aae45 100644 --- a/apiclient/helpers.go +++ b/apiclient/helpers.go @@ -337,35 +337,3 @@ func UnmarshalFaucetPackage(data []byte) (*models.FaucetPackage, error) { Signature: fpackage.Signature, }, nil } - -// FetchChainHeightAndHashFromDefaultAPI returns the current chain height and block hash -// from the default API url for the given network. -func FetchChainHeightAndHashFromDefaultAPI(network string) (int64, types.HexBytes, error) { - apiURL, ok := DefaultAPIUrls[network] - if !ok { - return 0, nil, fmt.Errorf("no default API URL for network %s", network) - } - height, hash, err := FetchChainHeightAndHash(apiURL) - if err != nil { - return 0, nil, fmt.Errorf("couldn't fetch info: %w", err) - } - return height, hash, nil -} - -// FetchChainHeightAndHash returns current chain height and block hash from an API endpoint. -func FetchChainHeightAndHash(apiURL string) (int64, types.HexBytes, error) { - log.Infow("requesting chain height and hash", "url", apiURL) - c, err := New(apiURL) - if err != nil { - return 0, nil, fmt.Errorf("couldn't init apiclient: %w", err) - } - chain, err := c.ChainInfo() - if err != nil { - return 0, nil, fmt.Errorf("couldn't fetch chain info: %w", err) - } - block, err := c.Block(chain.Height) - if err != nil { - return 0, nil, fmt.Errorf("couldn't fetch block: %w", err) - } - return int64(chain.Height), block.Hash, nil -} diff --git a/cmd/node/main.go b/cmd/node/main.go index 03d36e5fc..8345c8a57 100644 --- a/cmd/node/main.go +++ b/cmd/node/main.go @@ -24,7 +24,6 @@ import ( urlapi "go.vocdoni.io/dvote/api" "go.vocdoni.io/dvote/api/censusdb" "go.vocdoni.io/dvote/api/faucet" - "go.vocdoni.io/dvote/apiclient" "go.vocdoni.io/dvote/config" "go.vocdoni.io/dvote/crypto/ethereum" "go.vocdoni.io/dvote/crypto/zk/circuit" @@ -195,13 +194,13 @@ func loadConfig() *config.Config { flag.StringSlice("vochainStateSyncRPCServers", []string{}, "list of RPC servers to bootstrap the StateSync (optional, defaults to using seeds)") flag.String("vochainStateSyncTrustHash", "", - "hash of the trusted block (takes precedence over API URL and hardcoded defaults)") + "hash of the trusted block (takes precedence over RPC and hardcoded defaults)") flag.Int64("vochainStateSyncTrustHeight", 0, - "height of the trusted block (takes precedence over API URL and hardcoded defaults)") + "height of the trusted block (takes precedence over RPC and hardcoded defaults)") flag.Int64("vochainStateSyncChunkSize", 10*(1<<20), // 10 MB "cometBFT chunk size in bytes") - flag.String("vochainStateSyncFetchParamsFromAPI", "", - "API URL to fetch needed params from (by default, it will use hardcoded URLs, set to 'disabled' to skip this feature)") + flag.Bool("vochainStateSyncFetchParamsFromRPC", true, + "allow statesync to fetch TrustHash and TrustHeight from the first RPCServer") flag.Int("vochainMinerTargetBlockTimeSeconds", 10, "vochain consensus block time target (in seconds)") @@ -449,42 +448,6 @@ func main() { } } - // If StateSync is enabled but parameters are empty, try our best to populate them - // (cmdline flags take precedence if defined, of course) - if conf.Vochain.StateSyncEnabled && - conf.Vochain.StateSyncTrustHeight == 0 && conf.Vochain.StateSyncTrustHash == "" { - conf.Vochain.StateSyncTrustHeight, conf.Vochain.StateSyncTrustHash = func() (int64, string) { - // first try to fetch params from remote API endpoint - switch strings.ToLower(conf.Vochain.StateSyncFetchParamsFromAPI) { - case "disabled": - // magic keyword to skip this feature, do nothing - case "": - height, hash, err := apiclient.FetchChainHeightAndHashFromDefaultAPI(conf.Vochain.Network) - if err != nil { - log.Warnw("couldn't fetch current state sync params", "err", err) - } else { - return height, hash.String() - } - default: - height, hash, err := apiclient.FetchChainHeightAndHash(conf.Vochain.StateSyncFetchParamsFromAPI) - if err != nil { - log.Warnw("couldn't fetch current state sync params", "err", err) - } else { - return height, hash.String() - } - } - // else, fallback to hardcoded params, if defined for the current network & chainID - if g, ok := genesis.Genesis[conf.Vochain.Network]; ok { - if statesync, ok := g.StateSync[g.Genesis.ChainID]; ok { - return statesync.TrustHeight, statesync.TrustHash.String() - } - } - return 0, "" - }() - log.Infow("automatically determined statesync params", - "height", conf.Vochain.StateSyncTrustHeight, "hash", conf.Vochain.StateSyncTrustHash) - } - // // Vochain and Indexer // diff --git a/config/config.go b/config/config.go index ef363808b..1bec18521 100644 --- a/config/config.go +++ b/config/config.go @@ -140,9 +140,8 @@ type VochainCfg struct { StateSyncTrustHash string // StateSyncChunkSize defines the size of the chunks when splitting a Snapshot for sending via StateSync StateSyncChunkSize int64 - // StateSyncFetchParamsFromAPI defines an API URL to fetch the params from. - // If empty it will use default API urls, special keyword "disable" means to skip this feature altogether - StateSyncFetchParamsFromAPI string + // StateSyncFetchParamsFromRPC allows statesync to fetch TrustHash and TrustHeight from the first RPCServer + StateSyncFetchParamsFromRPC bool } // IndexerCfg handles the configuration options of the indexer diff --git a/dockerfiles/testsuite/docker-compose.yml b/dockerfiles/testsuite/docker-compose.yml index 3d2025f53..ac93e6f70 100644 --- a/dockerfiles/testsuite/docker-compose.yml +++ b/dockerfiles/testsuite/docker-compose.yml @@ -173,10 +173,6 @@ services: environment: - GOCOVERDIR=/app/run/gocoverage - LOG_PANIC_ON_INVALIDCHARS - - VOCDONI_LOGLEVEL=debug - - VOCDONI_VOCHAIN_STATESYNCENABLED=true - - VOCDONI_VOCHAIN_STATESYNCRPCSERVERS=miner0:26657,miner0:26657 - - VOCDONI_VOCHAIN_STATESYNCFETCHPARAMSFROMAPI networks: blockchain: diff --git a/dockerfiles/testsuite/start_test.sh b/dockerfiles/testsuite/start_test.sh index 2a1c5bf21..eb6103d19 100755 --- a/dockerfiles/testsuite/start_test.sh +++ b/dockerfiles/testsuite/start_test.sh @@ -160,7 +160,6 @@ e2etest_ballotelection() { } test_statesync() { - export VOCDONI_VOCHAIN_STATESYNCFETCHPARAMSFROMAPI=$APIHOST $COMPOSE_CMD up gatewaySync -d # watch logs for 2 minutes, until catching 'startup complete'. in case of timeout, or panic, or whatever, test will fail timeout 120 sh -c "($COMPOSE_CMD logs gatewaySync -f | grep -m 1 'startup complete')" diff --git a/vochain/apputils.go b/vochain/apputils.go index 4ec0a6327..ba7cdfeee 100644 --- a/vochain/apputils.go +++ b/vochain/apputils.go @@ -7,6 +7,7 @@ import ( "math" "os" "path/filepath" + "strings" "time" "go.vocdoni.io/dvote/crypto/ethereum" @@ -19,6 +20,7 @@ import ( crypto256k1 "github.com/cometbft/cometbft/crypto/secp256k1" cometp2p "github.com/cometbft/cometbft/p2p" cometprivval "github.com/cometbft/cometbft/privval" + cometrpchttp "github.com/cometbft/cometbft/rpc/client/http" comettypes "github.com/cometbft/cometbft/types" ethcommon "github.com/ethereum/go-ethereum/common" ) @@ -183,3 +185,15 @@ func NewTemplateGenesisFile(dir string, validators int) (*comettypes.GenesisDoc, gd.AppState = appStateBytes return &gd, gd.SaveAs(filepath.Join(dir, "genesis.json")) } + +// newCometRPCClient sets up a new cometbft RPC client +func newCometRPCClient(server string) (*cometrpchttp.HTTP, error) { + if !strings.Contains(server, "://") { + server = "http://" + server + } + c, err := cometrpchttp.New(server) + if err != nil { + return nil, err + } + return c, nil +} diff --git a/vochain/start.go b/vochain/start.go index 5ec5a9618..a1f9e6291 100644 --- a/vochain/start.go +++ b/vochain/start.go @@ -158,6 +158,39 @@ func newTendermint(app *BaseApplication, tconfig.StateSync.TrustHeight = localConfig.StateSyncTrustHeight tconfig.StateSync.TrustHash = localConfig.StateSyncTrustHash + + // If StateSync is enabled but parameters are empty, try our best to populate them + // first try to fetch params from remote API endpoint + if localConfig.StateSyncFetchParamsFromRPC && + tconfig.StateSync.TrustHeight == 0 && tconfig.StateSync.TrustHash == "" { + tconfig.StateSync.TrustHeight, tconfig.StateSync.TrustHash = func() (int64, string) { + cli, err := newCometRPCClient(tconfig.StateSync.RPCServers[0]) + if err != nil { + log.Warnf("cannot connect to remote RPC server: %v", err) + return 0, "" + } + status, err := cli.Status(context.TODO()) + if err != nil { + log.Warnf("cannot fetch status from remote RPC server: %v", err) + return 0, "" + } + log.Infow("fetched statesync params from remote RPC", + "height", status.SyncInfo.LatestBlockHeight, "hash", status.SyncInfo.LatestBlockHash.String()) + return status.SyncInfo.LatestBlockHeight, status.SyncInfo.LatestBlockHash.String() + }() + } + + // if still empty, fallback to hardcoded params, if defined for the current network & chainID + if tconfig.StateSync.TrustHeight == 0 && tconfig.StateSync.TrustHash == "" { + if g, ok := vocdoniGenesis.Genesis[localConfig.Network]; ok { + if statesync, ok := g.StateSync[g.Genesis.ChainID]; ok { + tconfig.StateSync.TrustHeight = statesync.TrustHeight + tconfig.StateSync.TrustHash = statesync.TrustHash.String() + log.Infow("using hardcoded statesync params", + "height", tconfig.StateSync.TrustHeight, "hash", tconfig.StateSync.TrustHash) + } + } + } } tconfig.RPC.ListenAddress = "tcp://0.0.0.0:26657"