diff --git a/app/app.go b/app/app.go index 134da07ea5..884d40c11d 100644 --- a/app/app.go +++ b/app/app.go @@ -570,6 +570,7 @@ func (app *App) InitChain(req abci.RequestInitChain) (res abci.ResponseInitChain // mountKeysAndInit mounts the keys for the provided app version and then // invokes baseapp.Init(). func (app *App) mountKeysAndInit(appVersion uint64) { + app.BaseApp.Logger().Debug(fmt.Sprintf("mounting KV stores for app version %v", appVersion)) app.MountKVStores(app.versionedKeys(appVersion)) // Invoke load latest version for it's side-effect of invoking baseapp.Init() @@ -784,3 +785,29 @@ func (app *App) InitializeAppVersion(ctx sdk.Context) { app.SetAppVersion(ctx, appVersion) } } + +// OfferSnapshot is a wrapper around the baseapp's OfferSnapshot method. It is +// needed to mount stores for the appropriate app version. +func (app *App) OfferSnapshot(req abci.RequestOfferSnapshot) abci.ResponseOfferSnapshot { + if app.IsSealed() { + // If the app is sealed, keys have already been mounted so this can + // delegate to the baseapp's OfferSnapshot. + return app.BaseApp.OfferSnapshot(req) + } + + if app.upgradeHeightV2 == 0 { + app.Logger().Debug("v2 upgrade height not set, assuming app version 2") + app.mountKeysAndInit(v2) + return app.BaseApp.OfferSnapshot(req) + } + + if req.Snapshot.Height >= uint64(app.upgradeHeightV2) { + app.Logger().Debug("snapshot height is greater than or equal to upgrade height, assuming app version 2") + app.mountKeysAndInit(v2) + return app.BaseApp.OfferSnapshot(req) + } + + app.Logger().Debug("snapshot height is less than upgrade height, assuming app version 1") + app.mountKeysAndInit(v1) + return app.BaseApp.OfferSnapshot(req) +} diff --git a/app/app_test.go b/app/app_test.go index a991981d41..c9fb31c1dc 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -6,7 +6,12 @@ import ( "github.com/celestiaorg/celestia-app/v2/app" "github.com/celestiaorg/celestia-app/v2/app/encoding" "github.com/celestiaorg/celestia-app/v2/x/minfee" + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/snapshots" + snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" tmdb "github.com/tendermint/tm-db" ) @@ -47,6 +52,45 @@ func TestNew(t *testing.T) { }) } +func TestOfferSnapshot(t *testing.T) { + logger := log.NewNopLogger() + db := tmdb.NewMemDB() + traceStore := &NoopWriter{} + invCheckPeriod := uint(1) + encodingConfig := encoding.MakeConfig(app.ModuleEncodingRegisters...) + upgradeHeight := int64(0) + appOptions := NoopAppOptions{} + snapshotOption := getSnapshotOption(t) + app := app.New(logger, db, traceStore, invCheckPeriod, encodingConfig, upgradeHeight, appOptions, snapshotOption) + + t.Run("should return ACCEPT", func(t *testing.T) { + request := abci.RequestOfferSnapshot{ + Snapshot: &abci.Snapshot{ + Height: 0x1b07ec, + Format: 0x2, + Chunks: 0x1, + Hash: []uint8{0xaf, 0xa5, 0xe, 0x16, 0x45, 0x4, 0x2e, 0x45, 0xd3, 0x49, 0xdf, 0x83, 0x2a, 0x57, 0x9d, 0x64, 0xc8, 0xad, 0xa5, 0xb, 0x65, 0x1b, 0x46, 0xd6, 0xc3, 0x85, 0x6, 0x51, 0xd7, 0x45, 0x8e, 0xb8}, + Metadata: []uint8{0xa, 0x20, 0xaf, 0xa5, 0xe, 0x16, 0x45, 0x4, 0x2e, 0x45, 0xd3, 0x49, 0xdf, 0x83, 0x2a, 0x57, 0x9d, 0x64, 0xc8, 0xad, 0xa5, 0xb, 0x65, 0x1b, 0x46, 0xd6, 0xc3, 0x85, 0x6, 0x51, 0xd7, 0x45, 0x8e, 0xb8}, + }, + AppHash: []byte("apphash"), + } + want := abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_ACCEPT} + got := app.OfferSnapshot(request) + assert.Equal(t, want, got) + }) +} + +func getSnapshotOption(t *testing.T) func(*baseapp.BaseApp) { + snapshotDir := t.TempDir() + snapshotDB, err := tmdb.NewDB("metadata", tmdb.GoLevelDBBackend, t.TempDir()) + require.NoError(t, err) + snapshotStore, err := snapshots.NewStore(snapshotDB, snapshotDir) + require.NoError(t, err) + interval := uint64(10) + keepRecent := uint32(10) + return baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(interval, keepRecent)) +} + // NoopWriter is a no-op implementation of a writer. type NoopWriter struct{} diff --git a/scripts/arabica.sh b/scripts/arabica.sh new file mode 100755 index 0000000000..831c785245 --- /dev/null +++ b/scripts/arabica.sh @@ -0,0 +1,59 @@ +#!/bin/sh + +# This script starts a consensus node on Arabica and state syncs to the tip of +# the chain. + +# Stop script execution if an error is encountered +set -o errexit +# Stop script execution if an undefined variable is used +set -o nounset + +CHAIN_ID="arabica-11" +NODE_NAME="node-name" +SEEDS="827583022cc6ce65cf762115642258f937c954cd@validator-1.celestia-arabica-11.com:26656,74e42b39f512f844492ff09e30af23d54579b7bc@validator-2.celestia-arabica-11.com:26656,00d577159b2eb1f524ef9c37cb389c020a2c38d2@validator-3.celestia-arabica-11.com:26656,b2871b6dc2e18916d07264af0e87c456c2bba04f@validator-4.celestia-arabica-11.com:26656" +RPC="https://rpc.celestia-arabica-11.com:443" + +CELESTIA_APP_HOME="${HOME}/.celestia-app" +CELESTIA_APP_VERSION=$(celestia-appd version 2>&1) + +echo "celestia-app home: ${CELESTIA_APP_HOME}" +echo "celestia-app version: ${CELESTIA_APP_VERSION}" +echo "" + +# Ask the user for confirmation before deleting the existing celestia-app home +# directory. +read -p "Are you sure you want to delete: $CELESTIA_APP_HOME? [y/n] " response + +# Check the user's response +if [ "$response" != "y" ]; then + # Exit if the user did not respond with "y" + echo "You must delete $CELESTIA_APP_HOME to continue." + exit 1 +fi + +echo "Deleting $CELESTIA_APP_HOME..." +rm -r "$CELESTIA_APP_HOME" + +echo "Initializing config files..." +celestia-appd init ${NODE_NAME} --chain-id ${CHAIN_ID} > /dev/null 2>&1 # Hide output to reduce terminal noise + +echo "Settings seeds in config.toml..." +sed -i.bak -e "s/^seeds *=.*/seeds = \"$SEEDS\"/" $CELESTIA_APP_HOME/config/config.toml + +# LATEST_HEIGHT=$(curl -s $RPC/block | jq -r .result.block.header.height); +BLOCK_HEIGHT=1751700 +TRUST_HASH=$(curl -s "$RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash) + +echo "Block height: $BLOCK_HEIGHT" +echo "Trust hash: $TRUST_HASH" +echo "Enabling state sync in config.toml..." +sed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\1true| ; \ +s|^(rpc_servers[[:space:]]+=[[:space:]]+).*$|\1\"$RPC,$RPC\"| ; \ +s|^(trust_height[[:space:]]+=[[:space:]]+).*$|\1$BLOCK_HEIGHT| ; \ +s|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\1\"$TRUST_HASH\"|" $HOME/.celestia-app/config/config.toml + +echo "Downloading genesis file..." +celestia-appd download-genesis ${CHAIN_ID} + +echo "Starting celestia-appd..." +celestia-appd start --v2-upgrade-height 1751707 diff --git a/scripts/mocha.sh b/scripts/mocha.sh new file mode 100755 index 0000000000..d64921b2a8 --- /dev/null +++ b/scripts/mocha.sh @@ -0,0 +1,59 @@ +#!/bin/sh + +# This script starts a consensus node on Mocha and state syncs to the tip of the +# chain. + +# Stop script execution if an error is encountered +set -o errexit +# Stop script execution if an undefined variable is used +set -o nounset + +CHAIN_ID="mocha-4" +NODE_NAME="node-name" +SEEDS="ee9f90974f85c59d3861fc7f7edb10894f6ac3c8@seed-mocha.pops.one:26656,258f523c96efde50d5fe0a9faeea8a3e83be22ca@seed.mocha-4.celestia.aviaone.com:20279,5d0bf034d6e6a8b5ee31a2f42f753f1107b3a00e@celestia-testnet-seed.itrocket.net:11656,7da0fb48d6ef0823bc9770c0c8068dd7c89ed4ee@celest-test-seed.theamsolutions.info:443" +RPC="https://celestia-testnet-rpc.itrocket.net:443" + +CELESTIA_APP_HOME="${HOME}/.celestia-app" +CELESTIA_APP_VERSION=$(celestia-appd version 2>&1) + +echo "celestia-app home: ${CELESTIA_APP_HOME}" +echo "celestia-app version: ${CELESTIA_APP_VERSION}" +echo "" + +# Ask the user for confirmation before deleting the existing celestia-app home +# directory. +read -p "Are you sure you want to delete: $CELESTIA_APP_HOME? [y/n] " response + +# Check the user's response +if [ "$response" != "y" ]; then + # Exit if the user did not respond with "y" + echo "You must delete $CELESTIA_APP_HOME to continue." + exit 1 +fi + +echo "Deleting $CELESTIA_APP_HOME..." +rm -r "$CELESTIA_APP_HOME" + +echo "Initializing config files..." +celestia-appd init ${NODE_NAME} --chain-id ${CHAIN_ID} > /dev/null 2>&1 # Hide output to reduce terminal noise + +echo "Settings seeds in config.toml..." +sed -i.bak -e "s/^seeds *=.*/seeds = \"$SEEDS\"/" $CELESTIA_APP_HOME/config/config.toml + +LATEST_HEIGHT=$(curl -s $RPC/block | jq -r .result.block.header.height); +BLOCK_HEIGHT=$((LATEST_HEIGHT - 2000)); \ +TRUST_HASH=$(curl -s "$RPC/block?height=$BLOCK_HEIGHT" | jq -r .result.block_id.hash) + +echo "Block height: $BLOCK_HEIGHT" +echo "Trust hash: $TRUST_HASH" +echo "Enabling state sync in config.toml..." +sed -i.bak -E "s|^(enable[[:space:]]+=[[:space:]]+).*$|\1true| ; \ +s|^(rpc_servers[[:space:]]+=[[:space:]]+).*$|\1\"$RPC,$RPC\"| ; \ +s|^(trust_height[[:space:]]+=[[:space:]]+).*$|\1$BLOCK_HEIGHT| ; \ +s|^(trust_hash[[:space:]]+=[[:space:]]+).*$|\1\"$TRUST_HASH\"|" $HOME/.celestia-app/config/config.toml + +echo "Downloading genesis file..." +celestia-appd download-genesis ${CHAIN_ID} > /dev/null 2>&1 # Hide output to reduce terminal noise + +echo "Starting celestia-appd..." +celestia-appd start --v2-upgrade-height 2585031