diff --git a/test/e2e/app/app.go b/test/e2e/app/app.go index b48242ffc..f1c19d63b 100644 --- a/test/e2e/app/app.go +++ b/test/e2e/app/app.go @@ -8,6 +8,7 @@ import ( "os" "path/filepath" "strconv" + "time" "github.com/tendermint/tendermint/abci/example/code" abci "github.com/tendermint/tendermint/abci/types" @@ -70,6 +71,13 @@ type Config struct { // // height <-> pubkey <-> voting power ValidatorUpdates map[string]map[string]uint8 `toml:"validator_update"` + + // Add artificial delays to each of the main ABCI calls to mimic computation time + // of the application + PrepareProposalDelay time.Duration `toml:"prepare_proposal_delay"` + ProcessProposalDelay time.Duration `toml:"process_proposal_delay"` + CheckTxDelay time.Duration `toml:"check_tx_delay"` + // TODO: add vote extension and finalize block delays once completed (@cmwaters) } func DefaultConfig(dir string) *Config { @@ -136,6 +144,11 @@ func (app *Application) CheckTx(req abci.RequestCheckTx) abci.ResponseCheckTx { Log: err.Error(), } } + + if app.cfg.CheckTxDelay != 0 { + time.Sleep(app.cfg.CheckTxDelay) + } + return abci.ResponseCheckTx{Code: code.CodeTypeOK, GasWanted: 1} } @@ -268,6 +281,11 @@ func (app *Application) PrepareProposal( } txs = append(txs, tx) } + + if app.cfg.PrepareProposalDelay != 0 { + time.Sleep(app.cfg.PrepareProposalDelay) + } + return abci.ResponsePrepareProposal{Txs: txs} } @@ -280,6 +298,11 @@ func (app *Application) ProcessProposal(req abci.RequestProcessProposal) abci.Re return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT} } } + + if app.cfg.ProcessProposalDelay != 0 { + time.Sleep(app.cfg.ProcessProposalDelay) + } + return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT} } diff --git a/test/e2e/generator/generate.go b/test/e2e/generator/generate.go index e203e4d6b..911c8e58f 100644 --- a/test/e2e/generator/generate.go +++ b/test/e2e/generator/generate.go @@ -5,6 +5,7 @@ import ( "math/rand" "sort" "strings" + "time" e2e "github.com/tendermint/tendermint/test/e2e/pkg" ) @@ -34,6 +35,7 @@ var ( nodePersistIntervals = uniformChoice{0, 1, 5} nodeSnapshotIntervals = uniformChoice{0, 3} nodeRetainBlocks = uniformChoice{0, 1, 5} + abciDelays = uniformChoice{"none", "small", "large"} nodePerturbations = probSetChoice{ "disconnect": 0.1, "pause": 0.1, @@ -67,6 +69,17 @@ func generateTestnet(r *rand.Rand, opt map[string]interface{}) (e2e.Manifest, er Nodes: map[string]*e2e.ManifestNode{}, } + switch abciDelays.Choose(r).(string) { + case "none": + case "small": + manifest.PrepareProposalDelay = 100 * time.Millisecond + manifest.ProcessProposalDelay = 100 * time.Millisecond + case "large": + manifest.PrepareProposalDelay = 200 * time.Millisecond + manifest.ProcessProposalDelay = 200 * time.Millisecond + manifest.CheckTxDelay = 20 * time.Millisecond + } + var numSeeds, numValidators, numFulls, numLightClients int switch opt["topology"].(string) { case "single": diff --git a/test/e2e/networks/ci.toml b/test/e2e/networks/ci.toml index 1fff574ca..c40a83814 100644 --- a/test/e2e/networks/ci.toml +++ b/test/e2e/networks/ci.toml @@ -4,6 +4,9 @@ ipv6 = true initial_height = 1000 initial_state = { initial01 = "a", initial02 = "b", initial03 = "c" } +prepare_proposal_delay = "100ms" +process_proposal_delay = "100ms" +check_tx_delay = "0ms" [validators] validator01 = 100 diff --git a/test/e2e/pkg/manifest.go b/test/e2e/pkg/manifest.go index 44c8e9118..5f2206a6a 100644 --- a/test/e2e/pkg/manifest.go +++ b/test/e2e/pkg/manifest.go @@ -3,6 +3,7 @@ package e2e import ( "fmt" "os" + "time" "github.com/BurntSushi/toml" ) @@ -56,6 +57,13 @@ type Manifest struct { // 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 + PrepareProposalDelay time.Duration `toml:"prepare_proposal_delay"` + ProcessProposalDelay time.Duration `toml:"process_proposal_delay"` + CheckTxDelay time.Duration `toml:"check_tx_delay"` + // TODO: add vote extension and finalize block delay (@cmwaters) } // ManifestNode represents a node in a testnet manifest. diff --git a/test/e2e/pkg/testnet.go b/test/e2e/pkg/testnet.go index 1123c26a9..9b9bfc801 100644 --- a/test/e2e/pkg/testnet.go +++ b/test/e2e/pkg/testnet.go @@ -11,6 +11,7 @@ import ( "sort" "strconv" "strings" + "time" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" @@ -49,17 +50,20 @@ const ( // Testnet represents a single testnet. type Testnet struct { - Name string - File string - Dir string - IP *net.IPNet - InitialHeight int64 - InitialState map[string]string - Validators map[*Node]int64 - ValidatorUpdates map[int64]map[*Node]int64 - Nodes []*Node - KeyType string - ABCIProtocol string + Name string + File string + Dir string + IP *net.IPNet + InitialHeight int64 + InitialState map[string]string + Validators map[*Node]int64 + ValidatorUpdates map[int64]map[*Node]int64 + Nodes []*Node + KeyType string + ABCIProtocol string + PrepareProposalDelay time.Duration + ProcessProposalDelay time.Duration + CheckTxDelay time.Duration } // Node represents a Tendermint node in a testnet. @@ -113,16 +117,19 @@ func LoadTestnet(file string) (*Testnet, error) { proxyPortGen := newPortGenerator(proxyPortFirst) testnet := &Testnet{ - Name: filepath.Base(dir), - File: file, - Dir: dir, - IP: ipGen.Network(), - InitialHeight: 1, - InitialState: manifest.InitialState, - Validators: map[*Node]int64{}, - ValidatorUpdates: map[int64]map[*Node]int64{}, - Nodes: []*Node{}, - ABCIProtocol: manifest.ABCIProtocol, + Name: filepath.Base(dir), + File: file, + Dir: dir, + IP: ipGen.Network(), + InitialHeight: 1, + InitialState: manifest.InitialState, + Validators: map[*Node]int64{}, + ValidatorUpdates: map[int64]map[*Node]int64{}, + Nodes: []*Node{}, + ABCIProtocol: manifest.ABCIProtocol, + PrepareProposalDelay: manifest.PrepareProposalDelay, + ProcessProposalDelay: manifest.ProcessProposalDelay, + CheckTxDelay: manifest.CheckTxDelay, } if len(manifest.KeyType) != 0 { testnet.KeyType = manifest.KeyType diff --git a/test/e2e/runner/setup.go b/test/e2e/runner/setup.go index 2dd84eaf2..87d749618 100644 --- a/test/e2e/runner/setup.go +++ b/test/e2e/runner/setup.go @@ -320,16 +320,19 @@ func MakeConfig(node *e2e.Node) (*config.Config, error) { // MakeAppConfig generates an ABCI application config for a node. func MakeAppConfig(node *e2e.Node) ([]byte, error) { cfg := map[string]interface{}{ - "chain_id": node.Testnet.Name, - "dir": "data/app", - "listen": AppAddressUNIX, - "mode": node.Mode, - "proxy_port": node.ProxyPort, - "protocol": "socket", - "persist_interval": node.PersistInterval, - "snapshot_interval": node.SnapshotInterval, - "retain_blocks": node.RetainBlocks, - "key_type": node.PrivvalKey.Type(), + "chain_id": node.Testnet.Name, + "dir": "data/app", + "listen": AppAddressUNIX, + "mode": node.Mode, + "proxy_port": node.ProxyPort, + "protocol": "socket", + "persist_interval": node.PersistInterval, + "snapshot_interval": node.SnapshotInterval, + "retain_blocks": node.RetainBlocks, + "key_type": node.PrivvalKey.Type(), + "prepare_proposal_delay": node.Testnet.PrepareProposalDelay, + "process_proposal_delay": node.Testnet.ProcessProposalDelay, + "check_tx_delay": node.Testnet.CheckTxDelay, } switch node.ABCIProtocol { case e2e.ProtocolUNIX: