Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create test chain with multiple validators #942

Merged
merged 9 commits into from
Feb 17, 2022
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Improvements

* (testing) [\#942](https://github.com/cosmos/ibc-go/pull/942) `NewTestChain` will create 4 validators in validator set by default. A new constructor function `NewTestChainWithValSet` is provided for test writers who want custom control over the validator set of test chains.
* (testing) [\#904](https://github.com/cosmos/ibc-go/pull/904) Add `ParsePacketFromEvents` function to the testing package. Useful when sending/relaying packets via the testing package.
* (testing) [\#893](https://github.com/cosmos/ibc-go/pull/893) Support custom private keys for testing.
* (testing) [\#810](https://github.com/cosmos/ibc-go/pull/810) Additional testing function added to `Endpoint` type called `RecvPacketWithResult`. Performs the same functionality as the existing `RecvPacket` function but also returns the message result. `path.RelayPacket` no longer uses the provided acknowledgement argument and instead obtains the acknowledgement via MsgRecvPacket events.
Expand Down
54 changes: 40 additions & 14 deletions testing/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ type TestChain struct {
SenderAccounts []SenderAccount
}

// NewTestChain initializes a new TestChain instance with a single validator set using a
// generated secp256k1 Tendermint private key. It also creates a sender BaseAccount to be used for
// delivering transactions.
// NewTestChainWithValSet initializes a new TestChain instance with the given validator set
// and signer array. It also initializes 10 Sender accounts with a balance of 10000000000000000000 coins of
// bond denom to use for tests.
//
// The first block height is committed to state in order to allow for client creations on
// counterparty chains. The TestChain will return with a block height starting at 2.
Expand All @@ -84,17 +84,11 @@ type TestChain struct {
//
// NOTE: to use a custom sender privkey and account for testing purposes, replace and modify this
// constructor function.
func NewTestChain(t *testing.T, coord *Coordinator, chainID string) *TestChain {
// generate validator private/public key
privVal := mock.NewPV()
pubKey, err := privVal.GetPubKey()
require.NoError(t, err)

// create validator set with single validator
validator := tmtypes.NewValidator(pubKey, 1)
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})
signers := []tmtypes.PrivValidator{privVal}

//
// CONTRACT: Validator and signer array must be provided in the order expected by Tendermint.
// i.e. sorted first by power and then lexicographically by address.
func NewTestChainWithValSet(t *testing.T, coord *Coordinator, chainID string, valSet *tmtypes.ValidatorSet, signers []tmtypes.PrivValidator) *TestChain {

genAccs := []authtypes.GenesisAccount{}
genBals := []banktypes.Balance{}
senderAccs := []SenderAccount{}
Expand Down Expand Up @@ -155,6 +149,38 @@ func NewTestChain(t *testing.T, coord *Coordinator, chainID string) *TestChain {
return chain
}

// NewTestChain initializes a new test chain with a default of 4 validators
// Use this function if the tests do not need custom control over the validator set
func NewTestChain(t *testing.T, coord *Coordinator, chainID string) *TestChain {
// generate validators private/public key
var (
validatorsPerChain = 4
validators []*tmtypes.Validator
signersByAddress = make(map[string]tmtypes.PrivValidator, validatorsPerChain)
)

for i := 0; i < validatorsPerChain; i++ {
privVal := mock.NewPV()
pubKey, err := privVal.GetPubKey()
require.NoError(t, err)
validators = append(validators, tmtypes.NewValidator(pubKey, 1))
signersByAddress[pubKey.Address().String()] = privVal
}

// construct validator set;
// Note that the validators are sorted by voting power
// or, if equal, by address lexical order
valSet := tmtypes.NewValidatorSet(validators)

// create signers indexed by the valSet validators's order
signers := []tmtypes.PrivValidator{}
for _, val := range valSet.Validators {
signers = append(signers, signersByAddress[val.PubKey.Address().String()])
}

return NewTestChainWithValSet(t, coord, chainID, valSet, signers)
}

// GetContext returns the current context for the application.
func (chain *TestChain) GetContext() sdk.Context {
return chain.App.GetBaseApp().NewContext(false, chain.CurrentHeader)
Expand Down