264 lines
7.2 KiB
Go
264 lines
7.2 KiB
Go
package systemtests
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/cometbft/cometbft/p2p"
|
|
"github.com/creachadair/tomledit"
|
|
"github.com/creachadair/tomledit/parser"
|
|
)
|
|
|
|
type LegacySingleNode struct {
|
|
execBinary string
|
|
workDir string
|
|
chainID string
|
|
outputDir string
|
|
minGasPrice string
|
|
log func(string)
|
|
}
|
|
|
|
// NewLegacySingleNodeInitializer constructor
|
|
func NewLegacySingleNodeInitializer(
|
|
execBinary, workDir, chainID, outputDir string,
|
|
minGasPrice string,
|
|
log func(string),
|
|
) *LegacySingleNode {
|
|
return &LegacySingleNode{
|
|
execBinary: execBinary,
|
|
workDir: workDir,
|
|
chainID: chainID,
|
|
outputDir: outputDir,
|
|
minGasPrice: minGasPrice,
|
|
log: log,
|
|
}
|
|
}
|
|
|
|
func (s LegacySingleNode) Initialize(xargs ...string) {
|
|
args := []string{
|
|
"testnet",
|
|
"init-files",
|
|
"--chain-id=" + s.chainID,
|
|
"--output-dir=" + s.outputDir,
|
|
"--v=1",
|
|
"--keyring-backend=test",
|
|
"--minimum-gas-prices=" + s.minGasPrice,
|
|
}
|
|
args = append(args, xargs...)
|
|
|
|
s.log(fmt.Sprintf("+++ %s %s\n", s.execBinary, strings.Join(args, " ")))
|
|
out, err := RunShellCmd(s.execBinary, args...)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
s.log(out)
|
|
}
|
|
|
|
// SingleHostTestnetCmdInitializer default testnet cmd that supports the --single-host param
|
|
type SingleHostTestnetCmdInitializer struct {
|
|
execBinary string
|
|
workDir string
|
|
chainID string
|
|
outputDir string
|
|
initialNodesCount int
|
|
minGasPrice string
|
|
commitTimeout time.Duration
|
|
log func(string)
|
|
}
|
|
|
|
// NewSingleHostTestnetCmdInitializer constructor
|
|
func NewSingleHostTestnetCmdInitializer(
|
|
execBinary, workDir, chainID, outputDir string,
|
|
initialNodesCount int,
|
|
minGasPrice string,
|
|
commitTimeout time.Duration,
|
|
log func(string),
|
|
) *SingleHostTestnetCmdInitializer {
|
|
return &SingleHostTestnetCmdInitializer{
|
|
execBinary: execBinary,
|
|
workDir: workDir,
|
|
chainID: chainID,
|
|
outputDir: outputDir,
|
|
initialNodesCount: initialNodesCount,
|
|
minGasPrice: minGasPrice,
|
|
commitTimeout: commitTimeout,
|
|
log: log,
|
|
}
|
|
}
|
|
|
|
func LegacyInitializerWithBinary(binary string, sut *SystemUnderTest) TestnetInitializer {
|
|
return NewLegacySingleNodeInitializer(binary, WorkDir, sut.chainID, sut.outputDir, sut.minGasPrice, sut.Log)
|
|
}
|
|
|
|
// InitializerWithBinary creates new SingleHostTestnetCmdInitializer from sut with given binary
|
|
func InitializerWithBinary(binary string, sut *SystemUnderTest) TestnetInitializer {
|
|
return NewSingleHostTestnetCmdInitializer(
|
|
binary,
|
|
WorkDir,
|
|
sut.chainID,
|
|
sut.outputDir,
|
|
sut.initialNodesCount,
|
|
sut.minGasPrice,
|
|
sut.CommitTimeout(),
|
|
sut.Log,
|
|
)
|
|
}
|
|
|
|
func (s SingleHostTestnetCmdInitializer) Initialize(xargs ...string) {
|
|
args := []string{
|
|
"testnet",
|
|
"init-files",
|
|
"--chain-id=" + s.chainID,
|
|
"--output-dir=" + s.outputDir,
|
|
"--validator-count=" + strconv.Itoa(s.initialNodesCount),
|
|
"--keyring-backend=test",
|
|
"--commit-timeout=" + s.commitTimeout.String(),
|
|
"--single-host",
|
|
"--minimum-gas-prices=" + s.minGasPrice,
|
|
}
|
|
args = append(args, xargs...)
|
|
|
|
s.log(fmt.Sprintf("+++ %s %s\n", s.execBinary, strings.Join(args, " ")))
|
|
out, err := RunShellCmd(s.execBinary, args...)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
s.log(out)
|
|
}
|
|
|
|
// ModifyConfigYamlInitializer testnet cmd prior to --single-host param. Modifies the toml files.
|
|
type ModifyConfigYamlInitializer struct {
|
|
execBinary string
|
|
workDir string
|
|
chainID string
|
|
outputDir string
|
|
initialNodesCount int
|
|
minGasPrice string
|
|
commitTimeout time.Duration
|
|
log func(string)
|
|
projectName string
|
|
}
|
|
|
|
func NewModifyConfigYamlInitializer(exec string, s *SystemUnderTest) *ModifyConfigYamlInitializer {
|
|
return &ModifyConfigYamlInitializer{
|
|
execBinary: exec,
|
|
workDir: WorkDir,
|
|
chainID: s.chainID,
|
|
outputDir: s.outputDir,
|
|
initialNodesCount: s.initialNodesCount,
|
|
minGasPrice: s.minGasPrice,
|
|
commitTimeout: s.CommitTimeout(),
|
|
log: s.Log,
|
|
projectName: s.projectName,
|
|
}
|
|
}
|
|
|
|
func (s ModifyConfigYamlInitializer) Initialize(xargs ...string) {
|
|
// init with legacy testnet command
|
|
args := []string{
|
|
"testnet",
|
|
"init-files",
|
|
"--chain-id=" + s.chainID,
|
|
"--output-dir=" + s.outputDir,
|
|
"--v=" + strconv.Itoa(s.initialNodesCount),
|
|
"--keyring-backend=test",
|
|
"--minimum-gas-prices=" + s.minGasPrice,
|
|
}
|
|
args = append(args, xargs...)
|
|
|
|
s.log(fmt.Sprintf("+++ %s %s\n", s.execBinary, strings.Join(args, " ")))
|
|
|
|
out, err := RunShellCmd(s.execBinary, args...)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
s.log(out)
|
|
|
|
nodeAddresses := make([]string, s.initialNodesCount)
|
|
for i := 0; i < s.initialNodesCount; i++ {
|
|
nodeDir := filepath.Join(WorkDir, NodePath(i, s.outputDir, s.projectName), "config")
|
|
id := mustV(p2p.LoadNodeKey(filepath.Join(nodeDir, "node_key.json"))).ID()
|
|
nodeAddresses[i] = fmt.Sprintf("%s@127.0.0.1:%d", id, DefaultP2PPort+i)
|
|
}
|
|
|
|
// then update configs
|
|
for i := 0; i < s.initialNodesCount; i++ {
|
|
nodeDir := filepath.Join(WorkDir, NodePath(i, s.outputDir, s.projectName), "config")
|
|
nodeNumber := i
|
|
EditToml(filepath.Join(nodeDir, "config.toml"), func(doc *tomledit.Document) {
|
|
UpdatePort(doc, DefaultRpcPort+i, "rpc", "laddr")
|
|
UpdatePort(doc, DefaultP2PPort+i, "p2p", "laddr")
|
|
SetBool(doc, false, "p2p", "addr_book_strict")
|
|
SetBool(doc, false, "p2p", "pex")
|
|
SetBool(doc, true, "p2p", "allow_duplicate_ip")
|
|
peers := make([]string, s.initialNodesCount)
|
|
copy(peers, nodeAddresses[0:nodeNumber])
|
|
copy(peers[nodeNumber:], nodeAddresses[nodeNumber+1:])
|
|
SetValue(doc, strings.Join(peers, ","), "p2p", "persistent_peers")
|
|
SetValue(doc, s.commitTimeout.String(), "consensus", "timeout_commit")
|
|
SetValue(doc, "goleveldb", "db_backend")
|
|
})
|
|
EditToml(filepath.Join(nodeDir, "app.toml"), func(doc *tomledit.Document) {
|
|
UpdatePort(doc, DefaultApiPort+i, "api", "address")
|
|
UpdatePort(doc, DefaultGrpcPort+i, "grpc", "address")
|
|
})
|
|
}
|
|
}
|
|
|
|
func EditToml(filename string, f func(doc *tomledit.Document)) {
|
|
tomlFile := mustV(os.OpenFile(filename, os.O_RDWR, 0o600))
|
|
defer tomlFile.Close()
|
|
doc := mustV(tomledit.Parse(tomlFile))
|
|
f(doc)
|
|
mustV(tomlFile.Seek(0, 0)) // reset the cursor to the beginning of the file
|
|
must(tomlFile.Truncate(0))
|
|
must(tomledit.Format(tomlFile, doc))
|
|
}
|
|
|
|
func SetBool(doc *tomledit.Document, newVal bool, xpath ...string) {
|
|
e := doc.First(xpath...)
|
|
if e == nil {
|
|
panic(fmt.Sprintf("not found: %v", xpath))
|
|
}
|
|
e.Value = parser.MustValue(strconv.FormatBool(newVal))
|
|
}
|
|
|
|
func SetValue(doc *tomledit.Document, newVal string, xpath ...string) {
|
|
e := doc.First(xpath...)
|
|
if e == nil {
|
|
panic(fmt.Sprintf("not found: %v", xpath))
|
|
}
|
|
e.Value = parser.MustValue(fmt.Sprintf("%q", newVal))
|
|
}
|
|
|
|
func UpdatePort(doc *tomledit.Document, newPort int, xpath ...string) {
|
|
e := doc.First(xpath...)
|
|
if e == nil {
|
|
panic(fmt.Sprintf("not found: %v", xpath))
|
|
}
|
|
data := e.Value.X.String()
|
|
pos := strings.LastIndexAny(data, ":")
|
|
if pos == -1 {
|
|
panic("column not found")
|
|
}
|
|
data = data[0:pos+1] + strconv.Itoa(newPort)
|
|
e.Value = parser.MustValue(data + "\"")
|
|
}
|
|
|
|
// mustV same as must but with value returned
|
|
func mustV[T any](r T, err error) T {
|
|
must(err)
|
|
return r
|
|
}
|
|
|
|
// must simple panic on error for fluent calls
|
|
func must(err error) {
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|