Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parameterize genesis and config through testnet command flags #115

Merged
merged 3 commits into from
Sep 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 75 additions & 8 deletions cmd/babylond/cmd/testnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ package cmd
import (
"bufio"
"encoding/json"
"errors"
"fmt"
txformat "github.com/babylonchain/babylon/btctxformatter"
btclightclienttypes "github.com/babylonchain/babylon/x/btclightclient/types"
epochingtypes "github.com/babylonchain/babylon/x/epoching/types"
"net"
"os"
"path/filepath"
Expand Down Expand Up @@ -42,11 +46,16 @@ import (
)

var (
flagNodeDirPrefix = "node-dir-prefix"
flagNumValidators = "v"
flagOutputDir = "output-dir"
flagNodeDaemonHome = "node-daemon-home"
flagStartingIPAddress = "starting-ip-address"
flagNodeDirPrefix = "node-dir-prefix"
flagNumValidators = "v"
flagOutputDir = "output-dir"
flagNodeDaemonHome = "node-daemon-home"
flagStartingIPAddress = "starting-ip-address"
flagBtcNetwork = "btc-network"
flagBtcCheckpointTag = "btc-checkpoint-tag"
flagEpochInterval = "epoch-interval"
flagBaseBtcHeaderHex = "btc-base-header"
flagBaseBtcHeaderHeight = "btc-base-header-height"
)

// get cmd to initialize all files for tendermint testnet and application
Expand Down Expand Up @@ -80,10 +89,23 @@ Example:
startingIPAddress, _ := cmd.Flags().GetString(flagStartingIPAddress)
numValidators, _ := cmd.Flags().GetInt(flagNumValidators)
algo, _ := cmd.Flags().GetString(flags.FlagKeyAlgorithm)
btcNetwork, _ := cmd.Flags().GetString(flagBtcNetwork)
btcCheckpointTag, _ := cmd.Flags().GetString(flagBtcCheckpointTag)
// No need to error check, since an invalid uint64 will
epochInterval, err := cmd.Flags().GetUint64(flagEpochInterval)
if err != nil {
return err
}
baseBtcHeaderHex, _ := cmd.Flags().GetString(flagBaseBtcHeaderHex)
baseBtcHeaderHeight, err := cmd.Flags().GetUint64(flagBaseBtcHeaderHeight)
if err != nil {
return errors.New("base Bitcoin header height should be a uint64")
}

return InitTestnet(
clientCtx, cmd, config, mbm, genBalIterator, outputDir, chainID, minGasPrices,
nodeDirPrefix, nodeDaemonHome, startingIPAddress, keyringBackend, algo, numValidators,
btcNetwork, btcCheckpointTag, epochInterval, baseBtcHeaderHex, baseBtcHeaderHeight,
)
},
}
Expand All @@ -93,6 +115,12 @@ Example:
cmd.Flags().String(flagNodeDirPrefix, "node", "Prefix the directory name for each node with (node results in node0, node1, ...)")
cmd.Flags().String(flagNodeDaemonHome, "babylond", "Home directory of the node's daemon configuration")
cmd.Flags().String(flagStartingIPAddress, "192.168.0.1", "Starting IP address (192.168.0.1 results in persistent peers list [email protected]:46656, [email protected]:46656, ...)")
cmd.Flags().String(flagBtcNetwork, string(bbn.BtcSimnet), "Bitcoin network to use. Available networks: simnet, testnet, mainnet")
cmd.Flags().String(flagBtcCheckpointTag, string(txformat.TestTag), "Tag to use for Bitcoin checkpoints. Available tags: BBT, BBN")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tags make me think that if you use BBT, if you want to restart your testnet, and you use the same BBT tag again, the clients will be confused that Bitcoin already has checkpoints for BBT; the new testnet will look like a long range attack.

Maybe a counter like BBT01, hoping there won't be more than 99 testnets? Or maybe a different letters like BBA, BBB, BBC. In any case I would not hardcode too much that it can be BBT or BBN.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently I think it is not allowed to have a tag other than that. Is that right @KonradStaniec ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep we can have only BBN or BBT for now and we can use any tag on any network.

Main use case being, that on any btc network you can put test tags (BBT) just to test babylon nodes with them so you can run babylon testnet against bitcoin mainnet and not have tags mix with each other. Then when running babylon mainnet against btc mainnet tag won't mix together.

if we would like multiple testnets against some long living btc nets (mainnet/testnet) then probably we would need more tags. Imo only requirement here is that tag have max 3bytes as this greatly reduces encoding/decoding complexity.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, although I think what Akosh suggests would be super useful, especially when using the testnet. However, even if we allow the testnet flag to be larger (e.g. BBT01-BBT99), we still restrict ourselves to the number of testnets that we can deploy using the BTC testnet. We need to specify a format for this case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the checkpoint have a version, just in case you change your mind about the content?

Regarding the counter: it could be an actual u8, so you have up to 256 nets with the same tag.

My point is that the BBT checkpoints will not disappear from the BTC testnet at the same time as you want to restart testnet, so if everything works well you might not even be able to run a testnet a second time. So it's not a long-lived testnet I'm worried about but rather the short lived ones.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, agreed. I suggest we extend the checkpoint format to allow for multiple testnets.

cmd.Flags().Uint64(flagEpochInterval, 10, "Number of blocks between epochs. Must be more than 0.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How often does it create a block by default? Isn't it something like 2 seconds?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think yes. Added this as a default parameter since the default param for the genesis module is 10.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then maybe the default should reflect the time we actually want our epoch to last, which I assume is not 20 seconds.

// Simnet genesis header
cmd.Flags().String(flagBaseBtcHeaderHex, "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a45068653ffff7f2002000000", "Hex of the base Bitcoin header.")
cmd.Flags().Uint64(flagBaseBtcHeaderHeight, 0, "Height of the base Bitcoin header.")
cmd.Flags().String(flags.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
cmd.Flags().String(server.FlagMinGasPrices, fmt.Sprintf("0.000006%s", sdk.DefaultBondDenom), "Minimum gas prices to accept for transactions; All fees in a tx must meet this minimum (e.g. 0.01photino,0.001stake)")
cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)")
Expand All @@ -119,6 +147,11 @@ func InitTestnet(
keyringBackend,
algoStr string,
numValidators int,
btcNetwork string,
btcCheckpointTag string,
epochInterval uint64,
baseBtcHeaderHex string,
baseBtcHeaderHeight uint64,
) error {

if chainID == "" {
Expand All @@ -135,8 +168,11 @@ func InitTestnet(
babylonConfig.Telemetry.PrometheusRetentionTime = 60
babylonConfig.Telemetry.EnableHostnameLabel = false
babylonConfig.Telemetry.GlobalLabels = [][]string{{"chain_id", chainID}}
// it makes sense in integration tests to use simnet due to lower difficulty
babylonConfig.BtcConfig.Network = string(bbn.BtcSimnet)
// BTC related config. Default values "simnet" and "BBT"
babylonConfig.BtcConfig.Network = btcNetwork
babylonConfig.BtcConfig.CheckpointTag = btcCheckpointTag
// Explorer related config. Allow CORS connections.
babylonConfig.API.EnableUnsafeCORS = true

var (
genAccounts []authtypes.GenesisAccount
Expand All @@ -155,6 +191,14 @@ func InitTestnet(
nodeConfig.SetRoot(nodeDir)
nodeConfig.RPC.ListenAddress = "tcp://0.0.0.0:26657"

// Explorer related config
// Allow all CORS requests
nodeConfig.RPC.CORSAllowedOrigins = []string{"*"}
// Enable Prometheus
nodeConfig.Instrumentation.Prometheus = true
// Set the number of simultaneous connections to unlimited
nodeConfig.Instrumentation.MaxOpenConnections = 0

if err := os.MkdirAll(filepath.Join(nodeDir, "config"), nodeDirPerm); err != nil {
_ = os.RemoveAll(outputDir)
return err
Expand Down Expand Up @@ -275,7 +319,8 @@ func InitTestnet(
srvconfig.WriteConfigFile(filepath.Join(nodeDir, "config/app.toml"), babylonConfig)
}

if err := initGenFiles(clientCtx, mbm, chainID, genAccounts, genBalances, genFiles, genKeys, numValidators); err != nil {
if err := initGenFiles(clientCtx, mbm, chainID, genAccounts, genBalances, genFiles,
genKeys, numValidators, epochInterval, baseBtcHeaderHex, baseBtcHeaderHeight); err != nil {
return err
}

Expand All @@ -295,6 +340,7 @@ func initGenFiles(
clientCtx client.Context, mbm module.BasicManager, chainID string,
genAccounts []authtypes.GenesisAccount, genBalances []banktypes.Balance,
genFiles []string, genKeys []*checkpointingtypes.GenesisKey, numValidators int,
epochInterval uint64, baseBtcHeaderHex string, baseBtcHeaderHeight uint64,
) error {

appGenState := mbm.DefaultGenesis(clientCtx.Codec)
Expand Down Expand Up @@ -328,6 +374,27 @@ func initGenFiles(
checkpointGenState.GenesisKeys = genKeys
appGenState[checkpointingtypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(&checkpointGenState)

// set the base BTC header in the genesis state
baseBtcHeader, err := bbn.NewBTCHeaderBytesFromHex(baseBtcHeaderHex)
if err != nil {
return err
}
work := btclightclienttypes.CalcWork(&baseBtcHeader)
baseBtcHeaderInfo := btclightclienttypes.NewBTCHeaderInfo(&baseBtcHeader, baseBtcHeader.Hash(), baseBtcHeaderHeight, &work)
var btclightclientGenState btclightclienttypes.GenesisState
clientCtx.Codec.MustUnmarshalJSON(appGenState[btclightclienttypes.ModuleName], &btclightclientGenState)
btclightclientGenState.BaseBtcHeader = *baseBtcHeaderInfo
appGenState[btclightclienttypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(&btclightclientGenState)

// set the epoch interval in the genesis state
if epochInterval == 0 {
return errors.New(fmt.Sprintf("Invalid epoch interval %d", epochInterval))
}
var epochingGenState epochingtypes.GenesisState
clientCtx.Codec.MustUnmarshalJSON(appGenState[epochingtypes.ModuleName], &epochingGenState)
epochingGenState.Params.EpochInterval = epochInterval
appGenState[epochingtypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(&epochingGenState)

appGenStateJSON, err := json.MarshalIndent(appGenState, "", " ")
if err != nil {
return err
Expand Down
13 changes: 6 additions & 7 deletions test/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,10 @@ func TestTestnetRuninng(t *testing.T) {
// Check all nodes are properly initialized to genesis
// TODO ultimatly we would like to check genesis related to all modules here.
func TestBtcLightClientGenesis(t *testing.T) {
// TODO currently btclightclient hardcodes this header in some function. Ultimately
// we would like to get it from config file, and assert here that each node
// start with genesis header from this config file
hardcodedHeaderHash, _ := bbn.NewBTCHeaderHashBytesFromHex("00000000000000000002bf1c218853bc920f41f74491e6c92c6bc6fdc881ab47")
hardcodedHeaderHeight := uint64(736056)
// The default testnet directory uses the simnet genesis header as its base
// with height 0.
hardcodedHeader, _ := bbn.NewBTCHeaderBytesFromHex("0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a45068653ffff7f2002000000")
hardcodedHeaderHeight := uint64(0)

for i, c := range clients {
lc := lightclient.NewQueryClient(c)
Expand All @@ -145,13 +144,13 @@ func TestBtcLightClientGenesis(t *testing.T) {
t.Fatalf("Test failed due to client error: %v to node with address %s", err, addresses[i])
}

if res.Header.Height != hardcodedHeaderHeight || !res.Header.Hash.Eq(&hardcodedHeaderHash) {
if res.Header.Height != hardcodedHeaderHeight || !res.Header.Hash.Eq(hardcodedHeader.Hash()) {
t.Errorf("Node with address %s started with unexpected header", addresses[i])
}
}
}

func TestNodeProgres(t *testing.T) {
func TestNodeProgress(t *testing.T) {

// most probably nodes are after block 1 at this point, but to make sure we are waiting
// for block 1
Expand Down