e2e: add evidence generation and testing (#6276)

This commit is contained in:
Callum Waters
2021-03-29 20:00:20 +02:00
committed by GitHub
parent 32ee737d42
commit cbae3613dd
15 changed files with 337 additions and 275 deletions
+6 -12
View File
@@ -51,6 +51,10 @@ type Manifest struct {
// 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"`
@@ -113,8 +117,8 @@ type ManifestNode struct {
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 and
// SnapshotInterval.
// 0, which retains all blocks. Must be greater that PersistInterval,
// SnapshotInterval and EvidenceAgeHeight.
RetainBlocks uint64 `toml:"retain_blocks"`
// Perturb lists perturbations to apply to the node after it has been
@@ -126,16 +130,6 @@ type ManifestNode struct {
// restart: restarts the node, shutting it down with SIGTERM
Perturb []string `toml:"perturb"`
// Misbehaviors sets how a validator behaves during consensus at a
// certain height. Multiple misbehaviors at different heights can be used
//
// An example of misbehaviors
// { 10 = "double-prevote", 20 = "double-prevote"}
//
// For more information, look at the readme in the maverick folder.
// A list of all behaviors can be found in ../maverick/consensus/behavior.go
Misbehaviors map[string]string `toml:"misbehaviors"`
// Log level sets the log level of the specific node i.e. "consensus:info,*:error".
// This is helpful when debugging a specific problem. This overrides the network
// level.
+10 -47
View File
@@ -11,6 +11,7 @@ import (
"sort"
"strconv"
"strings"
"time"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
@@ -46,6 +47,9 @@ const (
PerturbationKill Perturbation = "kill"
PerturbationPause Perturbation = "pause"
PerturbationRestart Perturbation = "restart"
EvidenceAgeHeight int64 = 3
EvidenceAgeTime time.Duration = 10 * time.Second
)
// Testnet represents a single testnet.
@@ -60,6 +64,7 @@ type Testnet struct {
ValidatorUpdates map[int64]map[*Node]int64
Nodes []*Node
KeyType string
Evidence int
LogLevel string
}
@@ -84,7 +89,6 @@ type Node struct {
Seeds []*Node
PersistentPeers []*Node
Perturbations []Perturbation
Misbehaviors map[int64]string
LogLevel string
}
@@ -124,6 +128,7 @@ func LoadTestnet(file string) (*Testnet, error) {
Validators: map[*Node]int64{},
ValidatorUpdates: map[int64]map[*Node]int64{},
Nodes: []*Node{},
Evidence: manifest.Evidence,
KeyType: "ed25519",
LogLevel: manifest.LogLevel,
}
@@ -161,7 +166,6 @@ func LoadTestnet(file string) (*Testnet, error) {
SnapshotInterval: nodeManifest.SnapshotInterval,
RetainBlocks: nodeManifest.RetainBlocks,
Perturbations: []Perturbation{},
Misbehaviors: make(map[int64]string),
LogLevel: manifest.LogLevel,
}
if node.StartAt == testnet.InitialHeight {
@@ -185,13 +189,6 @@ func LoadTestnet(file string) (*Testnet, error) {
for _, p := range nodeManifest.Perturb {
node.Perturbations = append(node.Perturbations, Perturbation(p))
}
for heightString, misbehavior := range nodeManifest.Misbehaviors {
height, err := strconv.ParseInt(heightString, 10, 64)
if err != nil {
return nil, fmt.Errorf("unable to parse height %s to int64: %w", heightString, err)
}
node.Misbehaviors[height] = misbehavior
}
if nodeManifest.LogLevel != "" {
node.LogLevel = nodeManifest.LogLevel
}
@@ -344,6 +341,10 @@ func (n Node) Validate(testnet Testnet) error {
if n.StateSync && n.StartAt == 0 {
return errors.New("state synced nodes cannot start at the initial height")
}
if n.RetainBlocks != 0 && n.RetainBlocks < uint64(EvidenceAgeHeight) {
return fmt.Errorf("retain_blocks must be greater or equal to max evidence age (%d)",
EvidenceAgeHeight)
}
if n.PersistInterval == 0 && n.RetainBlocks > 0 {
return errors.New("persist_interval=0 requires retain_blocks=0")
}
@@ -362,31 +363,6 @@ func (n Node) Validate(testnet Testnet) error {
}
}
if (n.PrivvalProtocol != "file" || n.Mode != "validator") && len(n.Misbehaviors) != 0 {
return errors.New("must be using \"file\" privval protocol to implement misbehaviors")
}
for height, misbehavior := range n.Misbehaviors {
if height < n.StartAt {
return fmt.Errorf("misbehavior height %d is below node start height %d",
height, n.StartAt)
}
if height < testnet.InitialHeight {
return fmt.Errorf("misbehavior height %d is below network initial height %d",
height, testnet.InitialHeight)
}
exists := false
// FIXME: Maverick has been disabled until it is redesigned
// for possibleBehaviors := range mcs.MisbehaviorList {
// if possibleBehaviors == misbehavior {
// exists = true
// }
// }
if !exists {
return fmt.Errorf("misbehavior %s does not exist", misbehavior)
}
}
return nil
}
@@ -438,19 +414,6 @@ func (t Testnet) HasPerturbations() bool {
return false
}
// LastMisbehaviorHeight returns the height of the last misbehavior.
func (t Testnet) LastMisbehaviorHeight() int64 {
lastHeight := int64(0)
for _, node := range t.Nodes {
for height := range node.Misbehaviors {
if height > lastHeight {
lastHeight = height
}
}
}
return lastHeight
}
// Address returns a P2P endpoint address for the node.
func (n Node) AddressP2P(withID bool) string {
ip := n.IP.String()