-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathmanifest.go
306 lines (254 loc) · 11.3 KB
/
manifest.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
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
package e2e
import (
"fmt"
"os"
"sort"
"time"
"github.com/BurntSushi/toml"
)
// Manifest represents a TOML testnet manifest.
type Manifest struct {
// IPv6 uses IPv6 networking instead of IPv4. Defaults to IPv4.
IPv6 bool `toml:"ipv6"`
// QuorumType represents the initial quorum type
QuorumType uint32 `toml:"quorum_type"`
// InitialHeight specifies the initial block height, set in genesis. Defaults to 1.
InitialHeight int64 `toml:"initial_height"`
// GenesisCoreChainLockedHeight specifies the initial core chain locked block height, set in genesis. Defaults to 1.
GenesisCoreChainLockedHeight uint32 `toml:"initial_core_chain_locked_height"`
// InitAppCoreChainLockedHeight specifies initial core chain locked block height, returned by the App
// in response to InitApp ABCI request. It overrides value set in GenesisCoreChainLockedHeight.
InitAppCoreChainLockedHeight uint32 `toml:"init_app_core_chain_locked_height"`
// InitialState is an initial set of key/value pairs for the application,
// set in genesis. Defaults to nothing.
InitialState string `toml:"initial_state"`
// Validators is the initial validator set in genesis, given as node names
// and power (for Dash power must all be set to default power):
//
// validators = { validator01 = 100; validator02 = 100; validator03 = 100 }
//
// Defaults to all nodes that have mode=validator at power 100. Explicitly
// specifying an empty set will start with no validators in genesis, and
// the application must return the validator set in InitChain via the
// setting validator_update.0 (see below).
Validators map[string]int64 `toml:"validators"`
// ValidatorUpdates is a map of heights to validator proTxHashes and their power,
// and will be returned by the ABCI application. For example, the following
// adds validator01 and validator02 at height 1000:
//
// [validator_update.1000]
// validator01 = 100
// validator02 = 100
//
// Specifying height 0 returns the validator update during InitChain. The
// application returns the validator updates as-is, i.e. removing a
// validator must be done by returning it with power 0, and any validators
// not specified are not changed.
ValidatorUpdates map[string]map[string]int64 `toml:"validator_update"`
// ConsensusVersionUpdates is a map of heights to consensus versions, and
// will be sent by the ABCI application as a consensus params update.
// For example, the following sets the consensus version to 1 at height 1000:
//
// [consensus_version_updates]
// 1000 = 1
ConsensusVersionUpdates map[string]int32 `toml:"consensus_version_updates"`
// ChainLockUpdates is a map of heights at which a new chain lock should be proposed
// The first number is the tendermint height, and the second is the
//
// [chainlock_updates]
// 1000 = 3450
// 1004 = 3451
// 1020 = 3454
// 1040 = 3500
ChainLockUpdates map[string]int64 `toml:"chainlock_updates"`
// Nodes specifies the network nodes. At least one node must be given.
Nodes map[string]*ManifestNode `toml:"node"`
// KeyType sets the curve that will be used by validators.
// Options are ed25519 & secp256k1
KeyType string `toml:"key_type"`
// Evidence indicates the amount of evidence that will be injected into the
// testnet via the RPC endpoint of a random node. Default is 0
Evidence int `toml:"evidence"`
// LogLevel sets the log level of the entire testnet. This can be overridden
// by individual nodes.
LogLevel string `toml:"log_level"`
// QueueType describes the type of queue that the system uses internally
QueueType string `toml:"queue_type"`
// Number of bytes per tx. Default is 1kb (1024)
TxSize int `toml:"tx_size"`
// VoteExtensionsEnableHeight configures the first height during which
// the chain will use and require vote extension data to be present
// in precommit messages.
VoteExtensionsEnableHeight int64 `toml:"vote_extensions_enable_height"`
// ABCIProtocol specifies the protocol used to communicate with the ABCI
// application: "unix", "tcp", "grpc", or "builtin". Defaults to builtin.
// builtin will build a complete Tendermint node into the application and
// launch it instead of launching a separate Tendermint process.
ABCIProtocol string `toml:"abci_protocol"`
// Add artificial delays to each of the main ABCI calls to mimic computation time
// of the application
PrepareProposalDelayMS uint64 `toml:"prepare_proposal_delay_ms"`
ProcessProposalDelayMS uint64 `toml:"process_proposal_delay_ms"`
CheckTxDelayMS uint64 `toml:"check_tx_delay_ms"`
VoteExtensionDelayMS uint64 `toml:"vote_extension_delay_ms"`
FinalizeBlockDelayMS uint64 `toml:"finalize_block_delay_ms"`
MaxBlockSize uint64 `toml:"max_block_size"`
MaxEvidenceSize uint64 `toml:"max_evidence_size"`
}
// ManifestNode represents a node in a testnet manifest.
type ManifestNode struct {
// Mode specifies the type of node: "validator", "full", "light" or "seed".
// Defaults to "validator". Full nodes do not get a signing key (a dummy key
// is generated), and seed nodes run in seed mode with the PEX reactor enabled.
Mode string `toml:"mode"`
// Seeds is the list of node names to use as P2P seed nodes. Defaults to none.
Seeds []string `toml:"seeds"`
// PersistentPeers is a list of node names to maintain persistent P2P
// connections to. If neither seeds nor persistent peers are specified,
// this defaults to all other nodes in the network. For light clients,
// this relates to the providers the light client is connected to.
PersistentPeers []string `toml:"persistent_peers"`
// Database specifies the database backend; only "goleveldb" is supported.
// Defaults to "goleveldb".
Database string `toml:"database"`
// PrivvalProtocol specifies the protocol used to sign consensus messages:
// "file", "unix", "tcp", "dashcore" or "grpc". Defaults to "file". For tcp and unix, the ABCI
// application will launch a remote signer client in a separate goroutine.
// For grpc the ABCI application will launch a remote signer server.
// Only nodes with mode=validator will actually make use of this.
PrivvalProtocol string `toml:"privval_protocol"`
// StartAt specifies the block height at which the node will be started. The
// runner will wait for the network to reach at least this block height.
StartAt int64 `toml:"start_at"`
// Mempool specifies which version of mempool to use. Either "v0" or "v1"
Mempool string `toml:"mempool_version"`
// StateSync enables state sync. The runner automatically configures trusted
// block hashes and RPC servers. At least one node in the network must have
// SnapshotInterval set to non-zero, and the state syncing node must have
// StartAt set to an appropriate height where a snapshot is available.
// StateSync can either be "p2p" or "rpc" or an empty string to disable
StateSync string `toml:"state_sync"`
// PersistInterval specifies the height interval at which the application
// will persist state to disk. Defaults to 1 (every height), setting this to
// 0 disables state persistence.
PersistInterval *uint64 `toml:"persist_interval"`
// SnapshotInterval specifies the height interval at which the application
// will take state sync snapshots. Defaults to 0 (disabled).
SnapshotInterval uint64 `toml:"snapshot_interval"`
// RetainBlocks specifies the number of recent blocks to retain. Defaults to
// 0, which retains all blocks. Must be greater that PersistInterval,
// SnapshotInterval and EvidenceAgeHeight.
RetainBlocks uint64 `toml:"retain_blocks"`
P2PMaxConnections uint16 `toml:"p2p_max_connections"`
P2PMaxOutgoingConnections uint16 `toml:"p2p_max_outgoing_connections"`
P2PMaxIncomingConnectionTime time.Duration `toml:"p2p_max_incoming_connection_time"`
P2PIncomingConnectionWindow time.Duration `toml:"p2p_incoming_connection_window"`
// Perturb lists perturbations to apply to the node after it has been
// started and synced with the network:
//
// disconnect: temporarily disconnects the node from the network
// kill: kills the node with SIGKILL then restarts it
// pause: temporarily pauses (freezes) the node
// restart: restarts the node, shutting it down with SIGTERM
Perturb []string `toml:"perturb"`
// Log level sets the log level of the specific node i.e. "info".
// This is helpful when debugging a specific problem. This overrides the network
// level.
LogLevel string `toml:"log_level"`
}
// Stateless reports whether m is a node that does not own state, including light and seed nodes.
func (m ManifestNode) Stateless() bool {
return m.Mode == string(ModeLight) || m.Mode == string(ModeSeed)
}
// Save saves the testnet manifest to a file.
func (m Manifest) Save(file string) error {
f, err := os.Create(file)
if err != nil {
return fmt.Errorf("failed to create manifest file %q: %w", file, err)
}
return toml.NewEncoder(f).Encode(m)
}
// LoadManifest loads a testnet manifest from a file.
func LoadManifest(file string) (Manifest, error) {
manifest := Manifest{}
_, err := toml.DecodeFile(file, &manifest)
if err != nil {
return manifest, fmt.Errorf("failed to load testnet manifest %q: %w", file, err)
}
return manifest, nil
}
// SortManifests orders (in-place) a list of manifests such that the
// manifests will be ordered in terms of complexity (or expected
// runtime). Complexity is determined first by the number of nodes,
// and then by the total number of perturbations in the network.
//
// If reverse is true, then the manifests are ordered with the most
// complex networks before the less complex networks.
func SortManifests(manifests []Manifest, reverse bool) {
sort.SliceStable(manifests, func(i, j int) bool {
// sort based on a point-based comparison between two
// manifests.
var (
left = manifests[i]
right = manifests[j]
)
// scores start with 100 points for each node. The
// number of nodes in a network is the most important
// factor in the complexity of the test.
leftScore := len(left.Nodes) * 100
rightScore := len(right.Nodes) * 100
// add two points for every node perturbation, and one
// point for every node that starts after genesis.
for _, n := range left.Nodes {
leftScore += (len(n.Perturb) * 2)
if n.StartAt > 0 {
leftScore += 3
}
}
for _, n := range right.Nodes {
rightScore += (len(n.Perturb) * 2)
if n.StartAt > 0 {
rightScore += 3
}
}
// add one point if the network has evidence.
if left.Evidence > 0 {
leftScore += 2
}
if right.Evidence > 0 {
rightScore += 2
}
if left.TxSize > right.TxSize {
leftScore++
}
if right.TxSize > left.TxSize {
rightScore++
}
if reverse {
return leftScore >= rightScore
}
return leftScore < rightScore
})
}
// SplitGroups divides a list of manifests into n groups of
// manifests.
func SplitGroups(groups int, manifests []Manifest) [][]Manifest {
groupSize := (len(manifests) + groups - 1) / groups
splitManifests := make([][]Manifest, 0, groups)
for i := 0; i < len(manifests); i += groupSize {
grp := make([]Manifest, groupSize)
n := copy(grp, manifests[i:])
splitManifests = append(splitManifests, grp[:n])
}
return splitManifests
}
// WriteManifests writes a collection of manifests into files with the
// specified path prefix.
func WriteManifests(prefix string, manifests []Manifest) error {
for i, manifest := range manifests {
if err := manifest.Save(fmt.Sprintf("%s-%04d.toml", prefix, i)); err != nil {
return err
}
}
return nil
}