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

test!: refactor testnode #2871

Merged
merged 15 commits into from
Dec 4, 2023
2 changes: 1 addition & 1 deletion app/test/max_total_blob_size_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func (s *MaxTotalBlobSizeSuite) SetupSuite() {
tmConfig := testnode.DefaultTendermintConfig()
tmConfig.Mempool.MaxTxBytes = 10 * mebibyte

cParams := testnode.DefaultParams()
cParams := testnode.DefaultConsensusParams()
evan-forbes marked this conversation as resolved.
Show resolved Hide resolved
cParams.Block.MaxBytes = 10 * mebibyte

cfg := testnode.DefaultConfig().
Expand Down
2 changes: 1 addition & 1 deletion test/cmd/txsim/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func setup(t testing.TB) (keyring.Keyring, string, string) {
cdc := encoding.MakeConfig(app.ModuleEncodingRegisters...).Codec

// set the consensus params to allow for the max square size
cparams := testnode.DefaultParams()
cparams := testnode.DefaultConsensusParams()
cparams.Block.MaxBytes = int64(appconsts.DefaultSquareSizeUpperBound*appconsts.DefaultSquareSizeUpperBound) * appconsts.ContinuationSparseShareContentSize

cfg := testnode.DefaultConfig().
Expand Down
27 changes: 27 additions & 0 deletions test/util/testnode/app_options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package testnode

import (
pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types"
"github.com/cosmos/cosmos-sdk/server"
)

type KVAppOptions struct {
options map[string]interface{}
}

// Get returns the option value for the given option key.
func (ao *KVAppOptions) Get(option string) interface{} {
return ao.options[option]
}

// Set sets a key-value app option.
func (ao *KVAppOptions) Set(option string, value interface{}) {
ao.options[option] = value
}

// DefaultAppOptions returns the default application options.
func DefaultAppOptions() *KVAppOptions {
opts := &KVAppOptions{options: make(map[string]interface{})}
opts.Set(server.FlagPruning, pruningtypes.PruningOptionNothing)
return opts
}
52 changes: 14 additions & 38 deletions test/util/testnode/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (
"github.com/celestiaorg/celestia-app/cmd/celestia-appd/cmd"
"github.com/celestiaorg/celestia-app/pkg/appconsts"
"github.com/celestiaorg/celestia-app/test/util/genesis"
pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types"
"github.com/cosmos/cosmos-sdk/server"
srvconfig "github.com/cosmos/cosmos-sdk/server/config"
srvtypes "github.com/cosmos/cosmos-sdk/server/types"
tmconfig "github.com/tendermint/tendermint/config"
Expand All @@ -17,6 +15,8 @@ import (
)

const (
kibibyte = 1024 // bytes
mebibyte = 1_048_576 // bytes
DefaultValidatorAccountName = "validator"
)

Expand Down Expand Up @@ -70,7 +70,7 @@ func (c *Config) WithSupressLogs(sl bool) *Config {
return c
}

// WithTimeoutCommit sets the CommitTimeout and returns the Config.
// WithTimeoutCommit sets the TimeoutCommit and returns the Config.
func (c *Config) WithTimeoutCommit(d time.Duration) *Config {
c.TmConfig.Consensus.TimeoutCommit = d
return c
Expand Down Expand Up @@ -108,16 +108,15 @@ func (c *Config) WithConsensusParams(params *tmproto.ConsensusParams) *Config {
return c
}

// DefaultConfig returns the default configuration of a test node.
func DefaultConfig() *Config {
tmcfg := DefaultTendermintConfig()
tmcfg.Consensus.TimeoutCommit = 1 * time.Millisecond
cfg := &Config{}
return cfg.
WithGenesis(
genesis.NewDefaultGenesis().
WithChainID(tmrand.Str(6)).
WithGenesisTime(time.Now()).
WithConsensusParams(DefaultParams()).
WithConsensusParams(DefaultConsensusParams()).
WithModifiers().
WithValidators(genesis.NewDefaultValidator(DefaultValidatorAccountName)),
).
Expand All @@ -128,28 +127,7 @@ func DefaultConfig() *Config {
WithSupressLogs(true)
}

type KVAppOptions struct {
options map[string]interface{}
}

// Get implements AppOptions
func (ao *KVAppOptions) Get(o string) interface{} {
return ao.options[o]
}

// Set adds an option to the KVAppOptions
func (ao *KVAppOptions) Set(o string, v interface{}) {
ao.options[o] = v
}

// DefaultAppOptions returns the default application options.
func DefaultAppOptions() *KVAppOptions {
opts := &KVAppOptions{options: make(map[string]interface{})}
opts.Set(server.FlagPruning, pruningtypes.PruningOptionNothing)
return opts
}

func DefaultParams() *tmproto.ConsensusParams {
func DefaultConsensusParams() *tmproto.ConsensusParams {
cparams := types.DefaultConsensusParams()
cparams.Block.TimeIotaMs = 1
cparams.Block.MaxBytes = appconsts.DefaultMaxBytes
Expand All @@ -159,22 +137,20 @@ func DefaultParams() *tmproto.ConsensusParams {

func DefaultTendermintConfig() *tmconfig.Config {
tmCfg := tmconfig.DefaultConfig()
// TimeoutCommit is the duration the node waits after committing a block
// before starting the next height. This duration influences the time
// interval between blocks. A smaller TimeoutCommit value could lead to
// less time between blocks (i.e. shorter block intervals).
// Reduce the timeout commit to 1ms to speed up the rate at which the test
// node produces blocks.
tmCfg.Consensus.TimeoutCommit = 1 * time.Millisecond

// set the mempool's MaxTxBytes to allow the testnode to accept a
// Override the mempool's MaxTxBytes to allow the testnode to accept a
// transaction that fills the entire square. Any blob transaction larger
// than the square size will still fail no matter what.
upperBoundBytes := appconsts.DefaultSquareSizeUpperBound * appconsts.DefaultSquareSizeUpperBound * appconsts.ContinuationSparseShareContentSize
tmCfg.Mempool.MaxTxBytes = upperBoundBytes
maxTxBytes := appconsts.DefaultSquareSizeUpperBound * appconsts.DefaultSquareSizeUpperBound * appconsts.ContinuationSparseShareContentSize
tmCfg.Mempool.MaxTxBytes = maxTxBytes

// remove all barriers from the testnode being able to accept very large
// transactions and respond to very queries with large responses (~200MB was
// Override the MaxBodyBytes to allow the testnode to accept very large
// transactions and respond to queries with large responses (200 MiB was
// chosen only as an arbitrary large number).
tmCfg.RPC.MaxBodyBytes = 200_000_000
tmCfg.RPC.MaxBodyBytes = 200 * mebibyte

return tmCfg
}
71 changes: 7 additions & 64 deletions test/util/testnode/full_node.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
package testnode

import (
"context"
"fmt"
"net"
"os"
"path/filepath"
"testing"

"github.com/celestiaorg/celestia-app/test/util/genesis"
"github.com/cosmos/cosmos-sdk/client/flags"
srvtypes "github.com/cosmos/cosmos-sdk/server/types"
"github.com/stretchr/testify/require"
Expand All @@ -24,14 +20,7 @@ import (
// validator celestia-app network. It expects that all configuration files are
// already initialized and saved to the baseDir.
func NewCometNode(t testing.TB, baseDir string, cfg *Config) (*node.Node, srvtypes.Application, error) {
var logger log.Logger
if cfg.SupressLogs {
logger = log.NewNopLogger()
} else {
logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout))
logger = log.NewFilter(logger, log.AllowError())
}

logger := newLogger(cfg)
dbPath := filepath.Join(cfg.TmConfig.RootDir, "data")
db, err := dbm.NewGoLevelDB("application", dbPath)
require.NoError(t, err)
Expand Down Expand Up @@ -59,57 +48,11 @@ func NewCometNode(t testing.TB, baseDir string, cfg *Config) (*node.Node, srvtyp
return tmNode, app, err
}

// NewNetwork starts a single valiator celestia-app network using the provided
// configurations. Configured accounts will be funded and their keys can be
// accessed in keyring returned client.Context. All rpc, p2p, and grpc addresses
// in the provided configs are overwritten to use open ports. The node can be
// accessed via the returned client.Context or via the returned rpc and grpc
// addresses. Configured genesis options will be applied after all accounts have
// been initialized.
func NewNetwork(t testing.TB, cfg *Config) (cctx Context, rpcAddr, grpcAddr string) {
t.Helper()

tmCfg := cfg.TmConfig
tmCfg.RPC.ListenAddress = fmt.Sprintf("tcp://127.0.0.1:%d", GetFreePort())
tmCfg.P2P.ListenAddress = fmt.Sprintf("tcp://127.0.0.1:%d", GetFreePort())
tmCfg.RPC.GRPCListenAddress = fmt.Sprintf("tcp://127.0.0.1:%d", GetFreePort())

// initialize the genesis file and validator files for the first validator.
baseDir, err := genesis.InitFiles(t.TempDir(), tmCfg, cfg.Genesis, 0)
require.NoError(t, err)

tmNode, app, err := NewCometNode(t, baseDir, cfg)
require.NoError(t, err)

cctx = NewContext(context.TODO(), cfg.Genesis.Keyring(), tmCfg, cfg.Genesis.ChainID)

cctx, stopNode, err := StartNode(tmNode, cctx)
require.NoError(t, err)

appCfg := cfg.AppConfig
appCfg.GRPC.Address = fmt.Sprintf("127.0.0.1:%d", GetFreePort())
appCfg.API.Address = fmt.Sprintf("tcp://127.0.0.1:%d", GetFreePort())

cctx, cleanupGRPC, err := StartGRPCServer(app, appCfg, cctx)
require.NoError(t, err)

t.Cleanup(func() {
t.Log("tearing down testnode")
require.NoError(t, stopNode())
require.NoError(t, cleanupGRPC())
})

return cctx, tmCfg.RPC.ListenAddress, appCfg.GRPC.Address
}

func GetFreePort() int {
a, err := net.ResolveTCPAddr("tcp", "localhost:0")
if err == nil {
var l *net.TCPListener
if l, err = net.ListenTCP("tcp", a); err == nil {
defer l.Close()
return l.Addr().(*net.TCPAddr).Port
}
func newLogger(cfg *Config) log.Logger {
if cfg.SupressLogs {
return log.NewNopLogger()
}
panic("while getting free port: " + err.Error())
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
logger = log.NewFilter(logger, log.AllowError())
return logger
}
4 changes: 0 additions & 4 deletions test/util/testnode/full_node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ import (
coretypes "github.com/tendermint/tendermint/rpc/core/types"
)

const (
kibibyte = 1024
)

func TestIntegrationTestSuite(t *testing.T) {
if testing.Short() {
t.Skip("skipping full node integration test in short mode.")
Expand Down
89 changes: 89 additions & 0 deletions test/util/testnode/network.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package testnode

import (
"context"
"fmt"
"net"
"testing"

"github.com/celestiaorg/celestia-app/test/util/genesis"
"github.com/stretchr/testify/require"
)

// NewNetwork starts a single validator celestia-app network using the provided
// configurations. Configured accounts will be funded and their keys can be
// accessed in keyring returned client.Context. All rpc, p2p, and grpc addresses
// in the provided configs are overwritten to use open ports. The node can be
// accessed via the returned client.Context or via the returned rpc and grpc
// addresses. Configured genesis options will be applied after all accounts have
// been initialized.
func NewNetwork(t testing.TB, cfg *Config) (cctx Context, rpcAddr, grpcAddr string) {
t.Helper()

tmCfg := cfg.TmConfig
tmCfg.RPC.ListenAddress = fmt.Sprintf("tcp://127.0.0.1:%d", mustGetFreePort())
tmCfg.P2P.ListenAddress = fmt.Sprintf("tcp://127.0.0.1:%d", mustGetFreePort())
tmCfg.RPC.GRPCListenAddress = fmt.Sprintf("tcp://127.0.0.1:%d", mustGetFreePort())

// initialize the genesis file and validator files for the first validator.
baseDir, err := genesis.InitFiles(t.TempDir(), tmCfg, cfg.Genesis, 0)
require.NoError(t, err)

tmNode, app, err := NewCometNode(t, baseDir, cfg)
require.NoError(t, err)

cctx = NewContext(context.Background(), cfg.Genesis.Keyring(), tmCfg, cfg.Genesis.ChainID)

cctx, stopNode, err := StartNode(t, tmNode, cctx)
require.NoError(t, err)

appCfg := cfg.AppConfig
appCfg.GRPC.Address = fmt.Sprintf("127.0.0.1:%d", mustGetFreePort())
appCfg.API.Address = fmt.Sprintf("tcp://127.0.0.1:%d", mustGetFreePort())

cctx, cleanupGRPC, err := StartGRPCServer(app, appCfg, cctx)
require.NoError(t, err)

t.Cleanup(func() {
t.Log("tearing down testnode")
err := stopNode()
if err != nil {
// the test has already completed so log the error instead of
// failing the test.
t.Logf("error stopping node %v", err)
}
err = cleanupGRPC()
if err != nil {
// the test has already completed so just log the error instead of
// failing the test.
t.Logf("error when cleaning up GRPC %v", err)
}
})

return cctx, tmCfg.RPC.ListenAddress, appCfg.GRPC.Address
}

// getFreePort returns a free port and optionally an error.
func getFreePort() (int, error) {
a, err := net.ResolveTCPAddr("tcp", "localhost:0")
if err != nil {
return 0, err
}

l, err := net.ListenTCP("tcp", a)
if err != nil {
return 0, err
}
defer l.Close()
return l.Addr().(*net.TCPAddr).Port, nil
}

// mustGetFreePort returns a free port. Panics if no free ports are available or
// an error is encountered.
func mustGetFreePort() int {
port, err := getFreePort()
if err != nil {
panic(err)
}
return port
rootulp marked this conversation as resolved.
Show resolved Hide resolved
}
Loading
Loading