-
Notifications
You must be signed in to change notification settings - Fork 3.8k
/
Copy pathtestnet_init.go
227 lines (204 loc) · 6.32 KB
/
testnet_init.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
package systemtests
import (
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/cometbft/cometbft/p2p"
"github.com/creachadair/tomledit"
"github.com/creachadair/tomledit/parser"
)
// IsV2 checks if the tests run with simapp v2
func IsV2() bool {
buildOptions := os.Getenv("COSMOS_BUILD_OPTIONS")
return strings.Contains(buildOptions, "v2")
}
// 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,
}
}
// 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() {
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",
}
if IsV2() {
args = append(args, "--server.minimum-gas-prices="+s.minGasPrice)
} else {
args = append(args, "--minimum-gas-prices="+s.minGasPrice)
}
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() {
// 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",
}
if IsV2() {
args = append(args, "--server.minimum-gas-prices="+s.minGasPrice)
} else {
args = append(args, "--minimum-gas-prices="+s.minGasPrice)
}
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 := string(mustV(p2p.LoadNodeKey(filepath.Join(nodeDir, "node_key.json"))).ID())
nodeAddresses[i] = fmt.Sprintf("%[email protected]:%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")
})
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)
}
}