Skip to content

Commit

Permalink
test!: refactor testnode (#2871)
Browse files Browse the repository at this point in the history
Miscelaneous refactors to testnode while working on
#2858 but doesn't
actually close that issue. This PR adds more logging to help debug the
second scenario alluded to in the original post.

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
  • Loading branch information
rootulp and coderabbitai[bot] authored Dec 4, 2023
1 parent 5564837 commit 30e907f
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 114 deletions.
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()
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
}
Loading

0 comments on commit 30e907f

Please sign in to comment.