You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

470 lines
13 KiB

  1. //nolint: gosec
  2. package e2e
  3. import (
  4. "errors"
  5. "fmt"
  6. "io"
  7. "math/rand"
  8. "net"
  9. "path/filepath"
  10. "sort"
  11. "strconv"
  12. "strings"
  13. "github.com/tendermint/tendermint/crypto"
  14. "github.com/tendermint/tendermint/crypto/ed25519"
  15. rpchttp "github.com/tendermint/tendermint/rpc/client/http"
  16. )
  17. const (
  18. randomSeed int64 = 2308084734268
  19. proxyPortFirst uint32 = 5701
  20. networkIPv4 = "10.186.73.0/24"
  21. networkIPv6 = "fd80:b10c::/48"
  22. )
  23. type Mode string
  24. type Protocol string
  25. type Perturbation string
  26. const (
  27. ModeValidator Mode = "validator"
  28. ModeFull Mode = "full"
  29. ModeSeed Mode = "seed"
  30. ProtocolBuiltin Protocol = "builtin"
  31. ProtocolFile Protocol = "file"
  32. ProtocolGRPC Protocol = "grpc"
  33. ProtocolTCP Protocol = "tcp"
  34. ProtocolUNIX Protocol = "unix"
  35. PerturbationDisconnect Perturbation = "disconnect"
  36. PerturbationKill Perturbation = "kill"
  37. PerturbationPause Perturbation = "pause"
  38. PerturbationRestart Perturbation = "restart"
  39. )
  40. // Testnet represents a single testnet.
  41. type Testnet struct {
  42. Name string
  43. File string
  44. Dir string
  45. IP *net.IPNet
  46. InitialHeight int64
  47. InitialState map[string]string
  48. Validators map[*Node]int64
  49. ValidatorUpdates map[int64]map[*Node]int64
  50. Nodes []*Node
  51. }
  52. // Node represents a Tendermint node in a testnet.
  53. type Node struct {
  54. Name string
  55. Testnet *Testnet
  56. Mode Mode
  57. Key crypto.PrivKey
  58. IP net.IP
  59. ProxyPort uint32
  60. StartAt int64
  61. FastSync string
  62. StateSync bool
  63. Database string
  64. ABCIProtocol Protocol
  65. PrivvalProtocol Protocol
  66. PersistInterval uint64
  67. SnapshotInterval uint64
  68. RetainBlocks uint64
  69. Seeds []*Node
  70. PersistentPeers []*Node
  71. Perturbations []Perturbation
  72. }
  73. // LoadTestnet loads a testnet from a manifest file, using the filename to
  74. // determine the testnet name and directory (from the basename of the file).
  75. // The testnet generation must be deterministic, since it is generated
  76. // separately by the runner and the test cases. For this reason, testnets use a
  77. // random seed to generate e.g. keys.
  78. func LoadTestnet(file string) (*Testnet, error) {
  79. manifest, err := LoadManifest(file)
  80. if err != nil {
  81. return nil, err
  82. }
  83. dir := strings.TrimSuffix(file, filepath.Ext(file))
  84. // Set up resource generators. These must be deterministic.
  85. netAddress := networkIPv4
  86. if manifest.IPv6 {
  87. netAddress = networkIPv6
  88. }
  89. _, ipNet, err := net.ParseCIDR(netAddress)
  90. if err != nil {
  91. return nil, fmt.Errorf("invalid IP network address %q: %w", netAddress, err)
  92. }
  93. ipGen := newIPGenerator(ipNet)
  94. keyGen := newKeyGenerator(randomSeed)
  95. proxyPortGen := newPortGenerator(proxyPortFirst)
  96. testnet := &Testnet{
  97. Name: filepath.Base(dir),
  98. File: file,
  99. Dir: dir,
  100. IP: ipGen.Network(),
  101. InitialHeight: 1,
  102. InitialState: manifest.InitialState,
  103. Validators: map[*Node]int64{},
  104. ValidatorUpdates: map[int64]map[*Node]int64{},
  105. Nodes: []*Node{},
  106. }
  107. if manifest.InitialHeight > 0 {
  108. testnet.InitialHeight = manifest.InitialHeight
  109. }
  110. // Set up nodes, in alphabetical order (IPs and ports get same order).
  111. nodeNames := []string{}
  112. for name := range manifest.Nodes {
  113. nodeNames = append(nodeNames, name)
  114. }
  115. sort.Strings(nodeNames)
  116. for _, name := range nodeNames {
  117. nodeManifest := manifest.Nodes[name]
  118. node := &Node{
  119. Name: name,
  120. Testnet: testnet,
  121. Key: keyGen.Generate(),
  122. IP: ipGen.Next(),
  123. ProxyPort: proxyPortGen.Next(),
  124. Mode: ModeValidator,
  125. Database: "goleveldb",
  126. ABCIProtocol: ProtocolUNIX,
  127. PrivvalProtocol: ProtocolFile,
  128. StartAt: nodeManifest.StartAt,
  129. FastSync: nodeManifest.FastSync,
  130. StateSync: nodeManifest.StateSync,
  131. PersistInterval: 1,
  132. SnapshotInterval: nodeManifest.SnapshotInterval,
  133. RetainBlocks: nodeManifest.RetainBlocks,
  134. Perturbations: []Perturbation{},
  135. }
  136. if nodeManifest.Mode != "" {
  137. node.Mode = Mode(nodeManifest.Mode)
  138. }
  139. if nodeManifest.Database != "" {
  140. node.Database = nodeManifest.Database
  141. }
  142. if nodeManifest.ABCIProtocol != "" {
  143. node.ABCIProtocol = Protocol(nodeManifest.ABCIProtocol)
  144. }
  145. if nodeManifest.PrivvalProtocol != "" {
  146. node.PrivvalProtocol = Protocol(nodeManifest.PrivvalProtocol)
  147. }
  148. if nodeManifest.PersistInterval != nil {
  149. node.PersistInterval = *nodeManifest.PersistInterval
  150. }
  151. for _, p := range nodeManifest.Perturb {
  152. node.Perturbations = append(node.Perturbations, Perturbation(p))
  153. }
  154. testnet.Nodes = append(testnet.Nodes, node)
  155. }
  156. // We do a second pass to set up seeds and persistent peers, which allows graph cycles.
  157. for _, node := range testnet.Nodes {
  158. nodeManifest, ok := manifest.Nodes[node.Name]
  159. if !ok {
  160. return nil, fmt.Errorf("failed to look up manifest for node %q", node.Name)
  161. }
  162. for _, seedName := range nodeManifest.Seeds {
  163. seed := testnet.LookupNode(seedName)
  164. if seed == nil {
  165. return nil, fmt.Errorf("unknown seed %q for node %q", seedName, node.Name)
  166. }
  167. node.Seeds = append(node.Seeds, seed)
  168. }
  169. for _, peerName := range nodeManifest.PersistentPeers {
  170. peer := testnet.LookupNode(peerName)
  171. if peer == nil {
  172. return nil, fmt.Errorf("unknown persistent peer %q for node %q", peerName, node.Name)
  173. }
  174. node.PersistentPeers = append(node.PersistentPeers, peer)
  175. }
  176. // If there are no seeds or persistent peers specified, default to persistent
  177. // connections to all other nodes.
  178. if len(node.PersistentPeers) == 0 && len(node.Seeds) == 0 {
  179. for _, peer := range testnet.Nodes {
  180. if peer.Name == node.Name {
  181. continue
  182. }
  183. node.PersistentPeers = append(node.PersistentPeers, peer)
  184. }
  185. }
  186. }
  187. // Set up genesis validators. If not specified explicitly, use all validator nodes.
  188. if manifest.Validators != nil {
  189. for validatorName, power := range *manifest.Validators {
  190. validator := testnet.LookupNode(validatorName)
  191. if validator == nil {
  192. return nil, fmt.Errorf("unknown validator %q", validatorName)
  193. }
  194. testnet.Validators[validator] = power
  195. }
  196. } else {
  197. for _, node := range testnet.Nodes {
  198. if node.Mode == ModeValidator {
  199. testnet.Validators[node] = 100
  200. }
  201. }
  202. }
  203. // Set up validator updates.
  204. for heightStr, validators := range manifest.ValidatorUpdates {
  205. height, err := strconv.Atoi(heightStr)
  206. if err != nil {
  207. return nil, fmt.Errorf("invalid validator update height %q: %w", height, err)
  208. }
  209. valUpdate := map[*Node]int64{}
  210. for name, power := range validators {
  211. node := testnet.LookupNode(name)
  212. if node == nil {
  213. return nil, fmt.Errorf("unknown validator %q for update at height %v", name, height)
  214. }
  215. valUpdate[node] = power
  216. }
  217. testnet.ValidatorUpdates[int64(height)] = valUpdate
  218. }
  219. return testnet, testnet.Validate()
  220. }
  221. // Validate validates a testnet.
  222. func (t Testnet) Validate() error {
  223. if t.Name == "" {
  224. return errors.New("network has no name")
  225. }
  226. if t.IP == nil {
  227. return errors.New("network has no IP")
  228. }
  229. if len(t.Nodes) == 0 {
  230. return errors.New("network has no nodes")
  231. }
  232. for _, node := range t.Nodes {
  233. if err := node.Validate(t); err != nil {
  234. return fmt.Errorf("invalid node %q: %w", node.Name, err)
  235. }
  236. }
  237. return nil
  238. }
  239. // Validate validates a node.
  240. func (n Node) Validate(testnet Testnet) error {
  241. if n.Name == "" {
  242. return errors.New("node has no name")
  243. }
  244. if n.IP == nil {
  245. return errors.New("node has no IP address")
  246. }
  247. if !testnet.IP.Contains(n.IP) {
  248. return fmt.Errorf("node IP %v is not in testnet network %v", n.IP, testnet.IP)
  249. }
  250. if n.ProxyPort > 0 {
  251. if n.ProxyPort <= 1024 {
  252. return fmt.Errorf("local port %v must be >1024", n.ProxyPort)
  253. }
  254. for _, peer := range testnet.Nodes {
  255. if peer.Name != n.Name && peer.ProxyPort == n.ProxyPort {
  256. return fmt.Errorf("peer %q also has local port %v", peer.Name, n.ProxyPort)
  257. }
  258. }
  259. }
  260. switch n.FastSync {
  261. case "", "v0", "v1", "v2":
  262. default:
  263. return fmt.Errorf("invalid fast sync setting %q", n.FastSync)
  264. }
  265. switch n.Database {
  266. case "goleveldb", "cleveldb", "boltdb", "rocksdb", "badgerdb":
  267. default:
  268. return fmt.Errorf("invalid database setting %q", n.Database)
  269. }
  270. switch n.ABCIProtocol {
  271. case ProtocolBuiltin, ProtocolUNIX, ProtocolTCP, ProtocolGRPC:
  272. default:
  273. return fmt.Errorf("invalid ABCI protocol setting %q", n.ABCIProtocol)
  274. }
  275. switch n.PrivvalProtocol {
  276. case ProtocolFile, ProtocolUNIX, ProtocolTCP:
  277. default:
  278. return fmt.Errorf("invalid privval protocol setting %q", n.PrivvalProtocol)
  279. }
  280. if n.StateSync && n.StartAt == 0 {
  281. return errors.New("state synced nodes cannot start at the initial height")
  282. }
  283. if n.PersistInterval == 0 && n.RetainBlocks > 0 {
  284. return errors.New("persist_interval=0 requires retain_blocks=0")
  285. }
  286. if n.PersistInterval > 1 && n.RetainBlocks > 0 && n.RetainBlocks < n.PersistInterval {
  287. return errors.New("persist_interval must be less than or equal to retain_blocks")
  288. }
  289. if n.SnapshotInterval > 0 && n.RetainBlocks > 0 && n.RetainBlocks < n.SnapshotInterval {
  290. return errors.New("snapshot_interval must be less than er equal to retain_blocks")
  291. }
  292. for _, perturbation := range n.Perturbations {
  293. switch perturbation {
  294. case PerturbationDisconnect, PerturbationKill, PerturbationPause, PerturbationRestart:
  295. default:
  296. return fmt.Errorf("invalid perturbation %q", perturbation)
  297. }
  298. }
  299. return nil
  300. }
  301. // LookupNode looks up a node by name. For now, simply do a linear search.
  302. func (t Testnet) LookupNode(name string) *Node {
  303. for _, node := range t.Nodes {
  304. if node.Name == name {
  305. return node
  306. }
  307. }
  308. return nil
  309. }
  310. // ArchiveNodes returns a list of archive nodes that start at the initial height
  311. // and contain the entire blockchain history. They are used e.g. as light client
  312. // RPC servers.
  313. func (t Testnet) ArchiveNodes() []*Node {
  314. nodes := []*Node{}
  315. for _, node := range t.Nodes {
  316. if node.Mode != ModeSeed && node.StartAt == 0 && node.RetainBlocks == 0 {
  317. nodes = append(nodes, node)
  318. }
  319. }
  320. return nodes
  321. }
  322. // RandomNode returns a random non-seed node.
  323. func (t Testnet) RandomNode() *Node {
  324. for {
  325. node := t.Nodes[rand.Intn(len(t.Nodes))]
  326. if node.Mode != ModeSeed {
  327. return node
  328. }
  329. }
  330. }
  331. // IPv6 returns true if the testnet is an IPv6 network.
  332. func (t Testnet) IPv6() bool {
  333. return t.IP.IP.To4() == nil
  334. }
  335. // Address returns a P2P endpoint address for the node.
  336. func (n Node) AddressP2P(withID bool) string {
  337. ip := n.IP.String()
  338. if n.IP.To4() == nil {
  339. // IPv6 addresses must be wrapped in [] to avoid conflict with : port separator
  340. ip = fmt.Sprintf("[%v]", ip)
  341. }
  342. addr := fmt.Sprintf("%v:26656", ip)
  343. if withID {
  344. addr = fmt.Sprintf("%x@%v", n.Key.PubKey().Address().Bytes(), addr)
  345. }
  346. return addr
  347. }
  348. // Address returns an RPC endpoint address for the node.
  349. func (n Node) AddressRPC() string {
  350. ip := n.IP.String()
  351. if n.IP.To4() == nil {
  352. // IPv6 addresses must be wrapped in [] to avoid conflict with : port separator
  353. ip = fmt.Sprintf("[%v]", ip)
  354. }
  355. return fmt.Sprintf("%v:26657", ip)
  356. }
  357. // Client returns an RPC client for a node.
  358. func (n Node) Client() (*rpchttp.HTTP, error) {
  359. return rpchttp.New(fmt.Sprintf("http://127.0.0.1:%v", n.ProxyPort), "/websocket")
  360. }
  361. // keyGenerator generates pseudorandom Ed25519 keys based on a seed.
  362. type keyGenerator struct {
  363. random *rand.Rand
  364. }
  365. func newKeyGenerator(seed int64) *keyGenerator {
  366. return &keyGenerator{
  367. random: rand.New(rand.NewSource(seed)),
  368. }
  369. }
  370. func (g *keyGenerator) Generate() crypto.PrivKey {
  371. seed := make([]byte, ed25519.SeedSize)
  372. _, err := io.ReadFull(g.random, seed)
  373. if err != nil {
  374. panic(err) // this shouldn't happen
  375. }
  376. return ed25519.GenPrivKeyFromSecret(seed)
  377. }
  378. // portGenerator generates local Docker proxy ports for each node.
  379. type portGenerator struct {
  380. nextPort uint32
  381. }
  382. func newPortGenerator(firstPort uint32) *portGenerator {
  383. return &portGenerator{nextPort: firstPort}
  384. }
  385. func (g *portGenerator) Next() uint32 {
  386. port := g.nextPort
  387. g.nextPort++
  388. if g.nextPort == 0 {
  389. panic("port overflow")
  390. }
  391. return port
  392. }
  393. // ipGenerator generates sequential IP addresses for each node, using a random
  394. // network address.
  395. type ipGenerator struct {
  396. network *net.IPNet
  397. nextIP net.IP
  398. }
  399. func newIPGenerator(network *net.IPNet) *ipGenerator {
  400. nextIP := make([]byte, len(network.IP))
  401. copy(nextIP, network.IP)
  402. gen := &ipGenerator{network: network, nextIP: nextIP}
  403. // Skip network and gateway addresses
  404. gen.Next()
  405. gen.Next()
  406. return gen
  407. }
  408. func (g *ipGenerator) Network() *net.IPNet {
  409. n := &net.IPNet{
  410. IP: make([]byte, len(g.network.IP)),
  411. Mask: make([]byte, len(g.network.Mask)),
  412. }
  413. copy(n.IP, g.network.IP)
  414. copy(n.Mask, g.network.Mask)
  415. return n
  416. }
  417. func (g *ipGenerator) Next() net.IP {
  418. ip := make([]byte, len(g.nextIP))
  419. copy(ip, g.nextIP)
  420. for i := len(g.nextIP) - 1; i >= 0; i-- {
  421. g.nextIP[i]++
  422. if g.nextIP[i] != 0 {
  423. break
  424. }
  425. }
  426. return ip
  427. }