github.com/Oyster-zx/tendermint@v0.34.24-fork/test/e2e/pkg/testnet.go (about) 1 package e2e 2 3 import ( 4 "errors" 5 "fmt" 6 "io" 7 "math/rand" 8 "net" 9 "path/filepath" 10 "sort" 11 "strconv" 12 "strings" 13 14 "github.com/tendermint/tendermint/crypto" 15 "github.com/tendermint/tendermint/crypto/ed25519" 16 "github.com/tendermint/tendermint/crypto/secp256k1" 17 rpchttp "github.com/tendermint/tendermint/rpc/client/http" 18 mcs "github.com/tendermint/tendermint/test/maverick/consensus" 19 ) 20 21 const ( 22 randomSeed int64 = 2308084734268 23 proxyPortFirst uint32 = 5701 24 ) 25 26 type ( 27 Mode string 28 Protocol string 29 Perturbation string 30 ) 31 32 const ( 33 ModeValidator Mode = "validator" 34 ModeFull Mode = "full" 35 ModeLight Mode = "light" 36 ModeSeed Mode = "seed" 37 38 ProtocolBuiltin Protocol = "builtin" 39 ProtocolFile Protocol = "file" 40 ProtocolGRPC Protocol = "grpc" 41 ProtocolTCP Protocol = "tcp" 42 ProtocolUNIX Protocol = "unix" 43 44 PerturbationDisconnect Perturbation = "disconnect" 45 PerturbationKill Perturbation = "kill" 46 PerturbationPause Perturbation = "pause" 47 PerturbationRestart Perturbation = "restart" 48 ) 49 50 // Testnet represents a single testnet. 51 type Testnet struct { 52 Name string 53 File string 54 Dir string 55 IP *net.IPNet 56 InitialHeight int64 57 InitialState map[string]string 58 Validators map[*Node]int64 59 ValidatorUpdates map[int64]map[*Node]int64 60 Nodes []*Node 61 KeyType string 62 ABCIProtocol string 63 } 64 65 // Node represents a Tendermint node in a testnet. 66 type Node struct { 67 Name string 68 Testnet *Testnet 69 Mode Mode 70 PrivvalKey crypto.PrivKey 71 NodeKey crypto.PrivKey 72 IP net.IP 73 ProxyPort uint32 74 StartAt int64 75 FastSync string 76 StateSync bool 77 Mempool string 78 Database string 79 ABCIProtocol Protocol 80 PrivvalProtocol Protocol 81 PersistInterval uint64 82 SnapshotInterval uint64 83 RetainBlocks uint64 84 Seeds []*Node 85 PersistentPeers []*Node 86 Perturbations []Perturbation 87 Misbehaviors map[int64]string 88 } 89 90 // LoadTestnet loads a testnet from a manifest file, using the filename to 91 // determine the testnet name and directory (from the basename of the file). 92 // The testnet generation must be deterministic, since it is generated 93 // separately by the runner and the test cases. For this reason, testnets use a 94 // random seed to generate e.g. keys. 95 func LoadTestnet(manifest Manifest, fname string, ifd InfrastructureData) (*Testnet, error) { 96 dir := strings.TrimSuffix(fname, filepath.Ext(fname)) 97 keyGen := newKeyGenerator(randomSeed) 98 proxyPortGen := newPortGenerator(proxyPortFirst) 99 _, ipNet, err := net.ParseCIDR(ifd.Network) 100 if err != nil { 101 return nil, fmt.Errorf("invalid IP network address %q: %w", ifd.Network, err) 102 } 103 104 testnet := &Testnet{ 105 Name: filepath.Base(dir), 106 File: fname, 107 Dir: dir, 108 IP: ipNet, 109 InitialHeight: 1, 110 InitialState: manifest.InitialState, 111 Validators: map[*Node]int64{}, 112 ValidatorUpdates: map[int64]map[*Node]int64{}, 113 Nodes: []*Node{}, 114 ABCIProtocol: manifest.ABCIProtocol, 115 } 116 if len(manifest.KeyType) != 0 { 117 testnet.KeyType = manifest.KeyType 118 } 119 if manifest.InitialHeight > 0 { 120 testnet.InitialHeight = manifest.InitialHeight 121 } 122 if testnet.ABCIProtocol == "" { 123 testnet.ABCIProtocol = string(ProtocolBuiltin) 124 } 125 126 // Set up nodes, in alphabetical order (IPs and ports get same order). 127 nodeNames := []string{} 128 for name := range manifest.Nodes { 129 nodeNames = append(nodeNames, name) 130 } 131 sort.Strings(nodeNames) 132 133 for _, name := range nodeNames { 134 nodeManifest := manifest.Nodes[name] 135 ind, ok := ifd.Instances[name] 136 if !ok { 137 return nil, fmt.Errorf("information for node '%s' missing from infrastucture data", name) 138 } 139 node := &Node{ 140 Name: name, 141 Testnet: testnet, 142 PrivvalKey: keyGen.Generate(manifest.KeyType), 143 NodeKey: keyGen.Generate("ed25519"), 144 IP: ind.IPAddress, 145 ProxyPort: proxyPortGen.Next(), 146 Mode: ModeValidator, 147 Database: "goleveldb", 148 ABCIProtocol: Protocol(testnet.ABCIProtocol), 149 PrivvalProtocol: ProtocolFile, 150 StartAt: nodeManifest.StartAt, 151 FastSync: nodeManifest.FastSync, 152 Mempool: nodeManifest.Mempool, 153 StateSync: nodeManifest.StateSync, 154 PersistInterval: 1, 155 SnapshotInterval: nodeManifest.SnapshotInterval, 156 RetainBlocks: nodeManifest.RetainBlocks, 157 Perturbations: []Perturbation{}, 158 Misbehaviors: make(map[int64]string), 159 } 160 if node.StartAt == testnet.InitialHeight { 161 node.StartAt = 0 // normalize to 0 for initial nodes, since code expects this 162 } 163 if nodeManifest.Mode != "" { 164 node.Mode = Mode(nodeManifest.Mode) 165 } 166 if node.Mode == ModeLight { 167 node.ABCIProtocol = ProtocolBuiltin 168 } 169 if nodeManifest.Database != "" { 170 node.Database = nodeManifest.Database 171 } 172 if nodeManifest.PrivvalProtocol != "" { 173 node.PrivvalProtocol = Protocol(nodeManifest.PrivvalProtocol) 174 } 175 if nodeManifest.PersistInterval != nil { 176 node.PersistInterval = *nodeManifest.PersistInterval 177 } 178 for _, p := range nodeManifest.Perturb { 179 node.Perturbations = append(node.Perturbations, Perturbation(p)) 180 } 181 for heightString, misbehavior := range nodeManifest.Misbehaviors { 182 height, err := strconv.ParseInt(heightString, 10, 64) 183 if err != nil { 184 return nil, fmt.Errorf("unable to parse height %s to int64: %w", heightString, err) 185 } 186 node.Misbehaviors[height] = misbehavior 187 } 188 testnet.Nodes = append(testnet.Nodes, node) 189 } 190 191 // We do a second pass to set up seeds and persistent peers, which allows graph cycles. 192 for _, node := range testnet.Nodes { 193 nodeManifest, ok := manifest.Nodes[node.Name] 194 if !ok { 195 return nil, fmt.Errorf("failed to look up manifest for node %q", node.Name) 196 } 197 for _, seedName := range nodeManifest.Seeds { 198 seed := testnet.LookupNode(seedName) 199 if seed == nil { 200 return nil, fmt.Errorf("unknown seed %q for node %q", seedName, node.Name) 201 } 202 node.Seeds = append(node.Seeds, seed) 203 } 204 for _, peerName := range nodeManifest.PersistentPeers { 205 peer := testnet.LookupNode(peerName) 206 if peer == nil { 207 return nil, fmt.Errorf("unknown persistent peer %q for node %q", peerName, node.Name) 208 } 209 node.PersistentPeers = append(node.PersistentPeers, peer) 210 } 211 212 // If there are no seeds or persistent peers specified, default to persistent 213 // connections to all other nodes. 214 if len(node.PersistentPeers) == 0 && len(node.Seeds) == 0 { 215 for _, peer := range testnet.Nodes { 216 if peer.Name == node.Name { 217 continue 218 } 219 node.PersistentPeers = append(node.PersistentPeers, peer) 220 } 221 } 222 } 223 224 // Set up genesis validators. If not specified explicitly, use all validator nodes. 225 if manifest.Validators != nil { 226 for validatorName, power := range *manifest.Validators { 227 validator := testnet.LookupNode(validatorName) 228 if validator == nil { 229 return nil, fmt.Errorf("unknown validator %q", validatorName) 230 } 231 testnet.Validators[validator] = power 232 } 233 } else { 234 for _, node := range testnet.Nodes { 235 if node.Mode == ModeValidator { 236 testnet.Validators[node] = 100 237 } 238 } 239 } 240 241 // Set up validator updates. 242 for heightStr, validators := range manifest.ValidatorUpdates { 243 height, err := strconv.Atoi(heightStr) 244 if err != nil { 245 return nil, fmt.Errorf("invalid validator update height %q: %w", height, err) 246 } 247 valUpdate := map[*Node]int64{} 248 for name, power := range validators { 249 node := testnet.LookupNode(name) 250 if node == nil { 251 return nil, fmt.Errorf("unknown validator %q for update at height %v", name, height) 252 } 253 valUpdate[node] = power 254 } 255 testnet.ValidatorUpdates[int64(height)] = valUpdate 256 } 257 258 return testnet, testnet.Validate() 259 } 260 261 // Validate validates a testnet. 262 func (t Testnet) Validate() error { 263 if t.Name == "" { 264 return errors.New("network has no name") 265 } 266 if t.IP == nil { 267 return errors.New("network has no IP") 268 } 269 if len(t.Nodes) == 0 { 270 return errors.New("network has no nodes") 271 } 272 for _, node := range t.Nodes { 273 if err := node.Validate(t); err != nil { 274 return fmt.Errorf("invalid node %q: %w", node.Name, err) 275 } 276 } 277 return nil 278 } 279 280 // Validate validates a node. 281 func (n Node) Validate(testnet Testnet) error { 282 if n.Name == "" { 283 return errors.New("node has no name") 284 } 285 if n.IP == nil { 286 return errors.New("node has no IP address") 287 } 288 if !testnet.IP.Contains(n.IP) { 289 return fmt.Errorf("node IP %v is not in testnet network %v", n.IP, testnet.IP) 290 } 291 if n.ProxyPort > 0 { 292 if n.ProxyPort <= 1024 { 293 return fmt.Errorf("local port %v must be >1024", n.ProxyPort) 294 } 295 for _, peer := range testnet.Nodes { 296 if peer.Name != n.Name && peer.ProxyPort == n.ProxyPort { 297 return fmt.Errorf("peer %q also has local port %v", peer.Name, n.ProxyPort) 298 } 299 } 300 } 301 switch n.FastSync { 302 case "", "v0", "v1", "v2": 303 default: 304 return fmt.Errorf("invalid fast sync setting %q", n.FastSync) 305 306 } 307 switch n.Mempool { 308 case "", "v0", "v1": 309 default: 310 return fmt.Errorf("invalid mempool version %q", n.Mempool) 311 } 312 switch n.Database { 313 case "goleveldb", "cleveldb", "boltdb", "rocksdb", "badgerdb": 314 default: 315 return fmt.Errorf("invalid database setting %q", n.Database) 316 } 317 switch n.ABCIProtocol { 318 case ProtocolBuiltin, ProtocolUNIX, ProtocolTCP, ProtocolGRPC: 319 default: 320 return fmt.Errorf("invalid ABCI protocol setting %q", n.ABCIProtocol) 321 } 322 if n.Mode == ModeLight && n.ABCIProtocol != ProtocolBuiltin { 323 return errors.New("light client must use builtin protocol") 324 } 325 switch n.PrivvalProtocol { 326 case ProtocolFile, ProtocolUNIX, ProtocolTCP: 327 default: 328 return fmt.Errorf("invalid privval protocol setting %q", n.PrivvalProtocol) 329 } 330 331 if n.StartAt > 0 && n.StartAt < n.Testnet.InitialHeight { 332 return fmt.Errorf("cannot start at height %v lower than initial height %v", 333 n.StartAt, n.Testnet.InitialHeight) 334 } 335 if n.StateSync && n.StartAt == 0 { 336 return errors.New("state synced nodes cannot start at the initial height") 337 } 338 if n.PersistInterval == 0 && n.RetainBlocks > 0 { 339 return errors.New("persist_interval=0 requires retain_blocks=0") 340 } 341 if n.PersistInterval > 1 && n.RetainBlocks > 0 && n.RetainBlocks < n.PersistInterval { 342 return errors.New("persist_interval must be less than or equal to retain_blocks") 343 } 344 if n.SnapshotInterval > 0 && n.RetainBlocks > 0 && n.RetainBlocks < n.SnapshotInterval { 345 return errors.New("snapshot_interval must be less than er equal to retain_blocks") 346 } 347 348 for _, perturbation := range n.Perturbations { 349 switch perturbation { 350 case PerturbationDisconnect, PerturbationKill, PerturbationPause, PerturbationRestart: 351 default: 352 return fmt.Errorf("invalid perturbation %q", perturbation) 353 } 354 } 355 356 if (n.PrivvalProtocol != "file" || n.Mode != "validator") && len(n.Misbehaviors) != 0 { 357 return errors.New("must be using \"file\" privval protocol to implement misbehaviors") 358 } 359 360 for height, misbehavior := range n.Misbehaviors { 361 if height < n.StartAt { 362 return fmt.Errorf("misbehavior height %d is below node start height %d", 363 height, n.StartAt) 364 } 365 if height < testnet.InitialHeight { 366 return fmt.Errorf("misbehavior height %d is below network initial height %d", 367 height, testnet.InitialHeight) 368 } 369 exists := false 370 for possibleBehaviors := range mcs.MisbehaviorList { 371 if possibleBehaviors == misbehavior { 372 exists = true 373 } 374 } 375 if !exists { 376 return fmt.Errorf("misbehavior %s does not exist", misbehavior) 377 } 378 } 379 380 return nil 381 } 382 383 // LookupNode looks up a node by name. For now, simply do a linear search. 384 func (t Testnet) LookupNode(name string) *Node { 385 for _, node := range t.Nodes { 386 if node.Name == name { 387 return node 388 } 389 } 390 return nil 391 } 392 393 // ArchiveNodes returns a list of archive nodes that start at the initial height 394 // and contain the entire blockchain history. They are used e.g. as light client 395 // RPC servers. 396 func (t Testnet) ArchiveNodes() []*Node { 397 nodes := []*Node{} 398 for _, node := range t.Nodes { 399 if !node.Stateless() && node.StartAt == 0 && node.RetainBlocks == 0 { 400 nodes = append(nodes, node) 401 } 402 } 403 return nodes 404 } 405 406 // RandomNode returns a random non-seed node. 407 func (t Testnet) RandomNode() *Node { 408 for { 409 //nolint:gosec // G404: Use of weak random number generator (math/rand instead of crypto/rand) 410 node := t.Nodes[rand.Intn(len(t.Nodes))] 411 if node.Mode != ModeSeed { 412 return node 413 } 414 } 415 } 416 417 // IPv6 returns true if the testnet is an IPv6 network. 418 func (t Testnet) IPv6() bool { 419 return t.IP.IP.To4() == nil 420 } 421 422 // HasPerturbations returns whether the network has any perturbations. 423 func (t Testnet) HasPerturbations() bool { 424 for _, node := range t.Nodes { 425 if len(node.Perturbations) > 0 { 426 return true 427 } 428 } 429 return false 430 } 431 432 // LastMisbehaviorHeight returns the height of the last misbehavior. 433 func (t Testnet) LastMisbehaviorHeight() int64 { 434 lastHeight := int64(0) 435 for _, node := range t.Nodes { 436 for height := range node.Misbehaviors { 437 if height > lastHeight { 438 lastHeight = height 439 } 440 } 441 } 442 return lastHeight 443 } 444 445 // Address returns a P2P endpoint address for the node. 446 func (n Node) AddressP2P(withID bool) string { 447 ip := n.IP.String() 448 if n.IP.To4() == nil { 449 // IPv6 addresses must be wrapped in [] to avoid conflict with : port separator 450 ip = fmt.Sprintf("[%v]", ip) 451 } 452 addr := fmt.Sprintf("%v:26656", ip) 453 if withID { 454 addr = fmt.Sprintf("%x@%v", n.NodeKey.PubKey().Address().Bytes(), addr) 455 } 456 return addr 457 } 458 459 // Address returns an RPC endpoint address for the node. 460 func (n Node) AddressRPC() string { 461 ip := n.IP.String() 462 if n.IP.To4() == nil { 463 // IPv6 addresses must be wrapped in [] to avoid conflict with : port separator 464 ip = fmt.Sprintf("[%v]", ip) 465 } 466 return fmt.Sprintf("%v:26657", ip) 467 } 468 469 // Client returns an RPC client for a node. 470 func (n Node) Client() (*rpchttp.HTTP, error) { 471 return rpchttp.New(fmt.Sprintf("http://127.0.0.1:%v", n.ProxyPort), "/websocket") 472 } 473 474 // Stateless returns true if the node is either a seed node or a light node 475 func (n Node) Stateless() bool { 476 return n.Mode == ModeLight || n.Mode == ModeSeed 477 } 478 479 // keyGenerator generates pseudorandom Ed25519 keys based on a seed. 480 type keyGenerator struct { 481 random *rand.Rand 482 } 483 484 func newKeyGenerator(seed int64) *keyGenerator { 485 return &keyGenerator{ 486 random: rand.New(rand.NewSource(seed)), //nolint:gosec 487 } 488 } 489 490 func (g *keyGenerator) Generate(keyType string) crypto.PrivKey { 491 seed := make([]byte, ed25519.SeedSize) 492 493 _, err := io.ReadFull(g.random, seed) 494 if err != nil { 495 panic(err) // this shouldn't happen 496 } 497 switch keyType { 498 case "secp256k1": 499 return secp256k1.GenPrivKeySecp256k1(seed) 500 case "", "ed25519": 501 return ed25519.GenPrivKeyFromSecret(seed) 502 default: 503 panic("KeyType not supported") // should not make it this far 504 } 505 } 506 507 // portGenerator generates local Docker proxy ports for each node. 508 type portGenerator struct { 509 nextPort uint32 510 } 511 512 func newPortGenerator(firstPort uint32) *portGenerator { 513 return &portGenerator{nextPort: firstPort} 514 } 515 516 func (g *portGenerator) Next() uint32 { 517 port := g.nextPort 518 g.nextPort++ 519 if g.nextPort == 0 { 520 panic("port overflow") 521 } 522 return port 523 } 524 525 // ipGenerator generates sequential IP addresses for each node, using a random 526 // network address. 527 type ipGenerator struct { 528 network *net.IPNet 529 nextIP net.IP 530 } 531 532 func newIPGenerator(network *net.IPNet) *ipGenerator { 533 nextIP := make([]byte, len(network.IP)) 534 copy(nextIP, network.IP) 535 gen := &ipGenerator{network: network, nextIP: nextIP} 536 // Skip network and gateway addresses 537 gen.Next() 538 gen.Next() 539 return gen 540 } 541 542 func (g *ipGenerator) Network() *net.IPNet { 543 n := &net.IPNet{ 544 IP: make([]byte, len(g.network.IP)), 545 Mask: make([]byte, len(g.network.Mask)), 546 } 547 copy(n.IP, g.network.IP) 548 copy(n.Mask, g.network.Mask) 549 return n 550 } 551 552 func (g *ipGenerator) Next() net.IP { 553 ip := make([]byte, len(g.nextIP)) 554 copy(ip, g.nextIP) 555 for i := len(g.nextIP) - 1; i >= 0; i-- { 556 g.nextIP[i]++ 557 if g.nextIP[i] != 0 { 558 break 559 } 560 } 561 return ip 562 }