mukan-ibc/testing/chain.go
Mukan Erkin Törük 88dd97a9f8
Some checks failed
CodeQL / Analyze (push) Waiting to run
golangci-lint / lint (push) Waiting to run
Tests / Code Coverage / build (amd64) (push) Waiting to run
Tests / Code Coverage / build (arm64) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[additional-args:-tags="test_e2e" name:e2e path:./e2e]) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[name:08-wasm path:./modules/light-clients/08-wasm]) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[name:ibc-go path:.]) (push) Waiting to run
Docker Build & Push Simapp (main) / docker-build (push) Has been cancelled
refactor: replace all github.com upstream refs with git.cw.tr/mukan-network
2026-05-11 03:36:22 +03:00

630 lines
24 KiB
Go

package ibctesting
import (
"encoding/json"
"fmt"
"testing"
"time"
"github.com/stretchr/testify/require"
errorsmod "cosmossdk.io/errors"
sdkmath "cosmossdk.io/math"
"git.cw.tr/mukan-network/mukan-sdk/client"
"git.cw.tr/mukan-network/mukan-sdk/codec"
"git.cw.tr/mukan-network/mukan-sdk/crypto/keys/secp256k1"
cryptotypes "git.cw.tr/mukan-network/mukan-sdk/crypto/types"
sdk "git.cw.tr/mukan-network/mukan-sdk/types"
authtypes "git.cw.tr/mukan-network/mukan-sdk/x/auth/types"
banktypes "git.cw.tr/mukan-network/mukan-sdk/x/bank/types"
abci "git.cw.tr/mukan-network/mukan-consensus/abci/types"
"git.cw.tr/mukan-network/mukan-consensus/crypto/tmhash"
cmtproto "git.cw.tr/mukan-network/mukan-consensus/proto/tendermint/types"
cmtprotoversion "git.cw.tr/mukan-network/mukan-consensus/proto/tendermint/version"
cmttypes "git.cw.tr/mukan-network/mukan-consensus/types"
cmtversion "git.cw.tr/mukan-network/mukan-consensus/version"
clienttypes "git.cw.tr/mukan-network/mukan-ibc/modules/core/02-client/types"
channeltypes "git.cw.tr/mukan-network/mukan-ibc/modules/core/04-channel/types"
commitmenttypes "git.cw.tr/mukan-network/mukan-ibc/modules/core/23-commitment/types"
host "git.cw.tr/mukan-network/mukan-ibc/modules/core/24-host"
"git.cw.tr/mukan-network/mukan-ibc/modules/core/exported"
ibctm "git.cw.tr/mukan-network/mukan-ibc/modules/light-clients/07-tendermint"
"git.cw.tr/mukan-network/mukan-ibc/testing/simapp"
)
var MaxAccounts = 10
type SenderAccount struct {
SenderPrivKey cryptotypes.PrivKey
SenderAccount sdk.AccountI
}
const (
DefaultGenesisAccBalance = "10000000000000000000"
)
// TestChain is a testing struct that wraps a simapp with the last TM Header, the current ABCI
// header and the validators of the TestChain. It also contains a field called ChainID. This
// is the clientID that *other* chains use to refer to this TestChain. The SenderAccount
// is used for delivering transactions through the application state.
// NOTE: the actual application uses an empty chain-id for ease of testing.
type TestChain struct {
testing.TB
Coordinator *Coordinator
App TestingApp
ChainID string
LatestCommittedHeader *ibctm.Header // header for last block height committed
ProposedHeader cmtproto.Header // proposed (uncommitted) header for current block height
TxConfig client.TxConfig
Codec codec.Codec
Vals *cmttypes.ValidatorSet
NextVals *cmttypes.ValidatorSet
// Signers is a map from validator address to the PrivValidator
// The map is converted into an array that is the same order as the validators right before signing commit
// This ensures that signers will always be in correct order even as validator powers change.
// If a test adds a new validator after chain creation, then the signer map must be updated to include
// the new PrivValidator entry.
Signers map[string]cmttypes.PrivValidator
// TrustedValidators is a mapping used to obtain the validator set from which we can prove a header update.
// It maps from a header height to the next validator set associated with that header.
TrustedValidators map[uint64]*cmttypes.ValidatorSet
// autogenerated sender private key
SenderPrivKey cryptotypes.PrivKey
SenderAccount sdk.AccountI
SenderAccounts []SenderAccount
// Short-term solution to override the logic of the standard SendMsgs function.
// See issue https://github.com/cosmos/ibc-go/issues/3123 for more information.
SendMsgsOverride func(msgs ...sdk.Msg) (*abci.ExecTxResult, error)
}
// 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.
//
// Time management is handled by the Coordinator in order to ensure synchrony between chains.
// Each update of any chain increments the block header time for all chains by 5 seconds.
//
// NOTE: to use a custom sender privkey and account for testing purposes, replace and modify this
// constructor function.
//
// CONTRACT: Validator array must be provided in the order expected by Tendermint.
// i.e. sorted first by power and then lexicographically by address.
func NewTestChainWithValSet(tb testing.TB, coord *Coordinator, chainID string, valSet *cmttypes.ValidatorSet, signers map[string]cmttypes.PrivValidator) *TestChain {
tb.Helper()
return newTestChainWithValSet(tb, coord, chainID, valSet, signers, DefaultTestingAppInit)
}
func newTestChainWithValSet(tb testing.TB, coord *Coordinator, chainID string, valSet *cmttypes.ValidatorSet, signers map[string]cmttypes.PrivValidator, appCreator AppCreator) *TestChain {
tb.Helper()
genAccs := []authtypes.GenesisAccount{}
genBals := []banktypes.Balance{}
senderAccs := []SenderAccount{}
// generate genesis accounts
for i := range MaxAccounts {
senderPrivKey := secp256k1.GenPrivKey()
acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), uint64(i), 0)
amount, ok := sdkmath.NewIntFromString(DefaultGenesisAccBalance)
require.True(tb, ok)
// add sender account
balance := banktypes.Balance{
Address: acc.GetAddress().String(),
Coins: sdk.NewCoins(
sdk.NewCoin(sdk.DefaultBondDenom, amount),
sdk.NewCoin(SecondaryDenom, amount),
),
}
genAccs = append(genAccs, acc)
genBals = append(genBals, balance)
senderAcc := SenderAccount{
SenderAccount: acc,
SenderPrivKey: senderPrivKey,
}
senderAccs = append(senderAccs, senderAcc)
}
app := setupWithGenesisValSet(tb, valSet, genAccs, chainID, sdk.DefaultPowerReduction, appCreator, genBals...)
// create current header and call begin block
header := cmtproto.Header{
ChainID: chainID,
Height: 1,
Time: coord.CurrentTime.UTC(),
}
txConfig := app.GetTxConfig()
// create an account to send transactions from
chain := &TestChain{
TB: tb,
Coordinator: coord,
ChainID: chainID,
App: app,
ProposedHeader: header,
TxConfig: txConfig,
Codec: app.AppCodec(),
Vals: valSet,
NextVals: valSet,
Signers: signers,
TrustedValidators: make(map[uint64]*cmttypes.ValidatorSet, 0),
SenderPrivKey: senderAccs[0].SenderPrivKey,
SenderAccount: senderAccs[0].SenderAccount,
SenderAccounts: senderAccs,
}
// commit genesis block
chain.NextBlock()
return chain
}
// AppCreator is a function which returns a TestingApp and a GenesisState
type AppCreator func() (TestingApp, map[string]json.RawMessage)
// NewCustomAppTestChain creates a TestChain instance with the provided AppCreator function.
func NewCustomAppTestChain(t *testing.T, coord *Coordinator, chainID string, appCreator AppCreator) *TestChain {
t.Helper()
// generate validators private/public key
var (
validatorsPerChain = 4
validators []*cmttypes.Validator
signersByAddress = make(map[string]cmttypes.PrivValidator, validatorsPerChain)
)
for range validatorsPerChain {
_, privVal := cmttypes.RandValidator(false, 100)
pubKey, err := privVal.GetPubKey()
require.NoError(t, err)
validators = append(validators, cmttypes.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 := cmttypes.NewValidatorSet(validators)
return newTestChainWithValSet(t, coord, chainID, valSet, signersByAddress, appCreator)
}
// 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 {
t.Helper()
return NewCustomAppTestChain(t, coord, chainID, DefaultTestingAppInit)
}
// GetContext returns the current context for the application.
func (chain *TestChain) GetContext() sdk.Context {
return chain.App.GetBaseApp().NewUncachedContext(false, chain.ProposedHeader)
}
// GetSimApp returns the SimApp to allow usage ofnon-interface fields.
// CONTRACT: This function should not be called by third parties implementing
// their own SimApp.
func (chain *TestChain) GetSimApp() *simapp.SimApp {
app, ok := chain.App.(*simapp.SimApp)
require.True(chain.TB, ok)
return app
}
// QueryProof performs an abci query with the given key and returns the proto encoded merkle proof
// for the query and the height at which the proof will succeed on a tendermint verifier.
func (chain *TestChain) QueryProof(key []byte) ([]byte, clienttypes.Height) {
return chain.QueryProofAtHeight(key, chain.App.LastBlockHeight())
}
// QueryProofAtHeight performs an abci query with the given key and returns the proto encoded merkle proof
// for the query and the height at which the proof will succeed on a tendermint verifier. Only the IBC
// store is supported
func (chain *TestChain) QueryProofAtHeight(key []byte, height int64) ([]byte, clienttypes.Height) {
return chain.QueryProofForStore(exported.StoreKey, key, height)
}
// QueryProofForStore performs an abci query with the given key and returns the proto encoded merkle proof
// for the query and the height at which the proof will succeed on a tendermint verifier.
func (chain *TestChain) QueryProofForStore(storeKey string, key []byte, height int64) ([]byte, clienttypes.Height) {
res, err := chain.App.Query(
chain.GetContext().Context(),
&abci.RequestQuery{
Path: fmt.Sprintf("store/%s/key", storeKey),
Height: height - 1,
Data: key,
Prove: true,
})
require.NoError(chain.TB, err)
merkleProof, err := commitmenttypes.ConvertProofs(res.ProofOps)
require.NoError(chain.TB, err)
proof, err := chain.App.AppCodec().Marshal(&merkleProof)
require.NoError(chain.TB, err)
revision := clienttypes.ParseChainID(chain.ChainID)
// proof height + 1 is returned as the proof created corresponds to the height the proof
// was created in the IAVL tree. Tendermint and subsequently the clients that rely on it
// have heights 1 above the IAVL tree. Thus we return proof height + 1
return proof, clienttypes.NewHeight(revision, uint64(res.Height)+1)
}
// QueryUpgradeProof performs an abci query with the given key and returns the proto encoded merkle proof
// for the query and the height at which the proof will succeed on a tendermint verifier.
func (chain *TestChain) QueryUpgradeProof(key []byte, height uint64) ([]byte, clienttypes.Height) {
res, err := chain.App.Query(
chain.GetContext().Context(),
&abci.RequestQuery{
Path: "store/upgrade/key",
Height: int64(height - 1),
Data: key,
Prove: true,
})
require.NoError(chain.TB, err)
merkleProof, err := commitmenttypes.ConvertProofs(res.ProofOps)
require.NoError(chain.TB, err)
proof, err := chain.App.AppCodec().Marshal(&merkleProof)
require.NoError(chain.TB, err)
revision := clienttypes.ParseChainID(chain.ChainID)
// proof height + 1 is returned as the proof created corresponds to the height the proof
// was created in the IAVL tree. Tendermint and subsequently the clients that rely on it
// have heights 1 above the IAVL tree. Thus we return proof height + 1
return proof, clienttypes.NewHeight(revision, uint64(res.Height+1))
}
// QueryConsensusStateProof performs an abci query for a consensus state
// stored on the given clientID. The proof and consensusHeight are returned.
func (chain *TestChain) QueryConsensusStateProof(clientID string) ([]byte, clienttypes.Height) {
consensusHeight, ok := chain.GetClientLatestHeight(clientID).(clienttypes.Height)
require.True(chain.TB, ok)
consensusKey := host.FullConsensusStateKey(clientID, consensusHeight)
consensusProof, _ := chain.QueryProof(consensusKey)
return consensusProof, consensusHeight
}
// NextBlock sets the last header to the current header and increments the current header to be
// at the next block height. It does not update the time as that is handled by the Coordinator.
// It will call FinalizeBlock and Commit and apply the validator set changes to the next validators
// of the next block being created. This follows the Tendermint protocol of applying valset changes
// returned on block `n` to the validators of block `n+2`.
// It calls BeginBlock with the new block created before returning.
func (chain *TestChain) NextBlock() {
res, err := chain.App.FinalizeBlock(&abci.RequestFinalizeBlock{
Height: chain.ProposedHeader.Height,
Time: chain.ProposedHeader.GetTime(),
NextValidatorsHash: chain.NextVals.Hash(),
})
require.NoError(chain.TB, err)
chain.commitBlock(res)
}
func (chain *TestChain) commitBlock(res *abci.ResponseFinalizeBlock) {
_, err := chain.App.Commit()
require.NoError(chain.TB, err)
// set the last header to the current header
// use nil trusted fields
chain.LatestCommittedHeader = chain.CurrentTMClientHeader()
// set the trusted validator set to the next validator set
// The latest trusted validator set is the next validator set
// associated with the header being committed in storage. This will
// allow for header updates to be proved against these validators.
chain.TrustedValidators[uint64(chain.ProposedHeader.Height)] = chain.NextVals
// val set changes returned from previous block get applied to the next validators
// of this block. See tendermint spec for details.
chain.Vals = chain.NextVals
chain.NextVals = ApplyValSetChanges(chain, chain.Vals, res.ValidatorUpdates)
// increment the proposer priority of validators
chain.Vals.IncrementProposerPriority(1)
// increment the current header
chain.ProposedHeader = cmtproto.Header{
ChainID: chain.ChainID,
Height: chain.App.LastBlockHeight() + 1,
AppHash: chain.App.LastCommitID().Hash,
// NOTE: the time is increased by the coordinator to maintain time synchrony amongst
// chains.
Time: chain.ProposedHeader.Time,
ValidatorsHash: chain.Vals.Hash(),
NextValidatorsHash: chain.NextVals.Hash(),
ProposerAddress: chain.Vals.Proposer.Address,
}
}
// sendMsgs delivers a transaction through the application without returning the result.
func (chain *TestChain) sendMsgs(msgs ...sdk.Msg) error {
_, err := chain.SendMsgs(msgs...)
return err
}
// SendMsgs delivers a transaction through the application using a predefined sender.
// It updates the senders sequence number and updates the TestChain's headers.
// It returns the result and error if one occurred.
func (chain *TestChain) SendMsgs(msgs ...sdk.Msg) (*abci.ExecTxResult, error) {
senderAccount := SenderAccount{
SenderPrivKey: chain.SenderPrivKey,
SenderAccount: chain.SenderAccount,
}
return chain.SendMsgsWithSender(senderAccount, msgs...)
}
// SendMsgsWithSender delivers a transaction through the application using the provided sender.
func (chain *TestChain) SendMsgsWithSender(sender SenderAccount, msgs ...sdk.Msg) (*abci.ExecTxResult, error) {
if chain.SendMsgsOverride != nil {
return chain.SendMsgsOverride(msgs...)
}
// ensure the chain has the latest time
chain.Coordinator.UpdateTimeForChain(chain)
// increment acc sequence regardless of success or failure tx execution
defer func() {
err := sender.SenderAccount.SetSequence(sender.SenderAccount.GetSequence() + 1)
if err != nil {
panic(err)
}
}()
resp, err := simapp.SignAndDeliver(
chain.TB,
chain.TxConfig,
chain.App.GetBaseApp(),
msgs,
chain.ChainID,
[]uint64{sender.SenderAccount.GetAccountNumber()},
[]uint64{sender.SenderAccount.GetSequence()},
true,
chain.ProposedHeader.GetTime(),
chain.NextVals.Hash(),
sender.SenderPrivKey,
)
if err != nil {
return nil, err
}
chain.commitBlock(resp)
require.Len(chain.TB, resp.TxResults, 1)
txResult := resp.TxResults[0]
if txResult.Code != 0 {
return txResult, fmt.Errorf("%s/%d: %q", txResult.Codespace, txResult.Code, txResult.Log)
}
chain.Coordinator.IncrementTime()
return txResult, nil
}
// GetClientState retrieves the client state for the provided clientID. The client is
// expected to exist otherwise testing will fail.
func (chain *TestChain) GetClientState(clientID string) exported.ClientState {
clientState, found := chain.App.GetIBCKeeper().ClientKeeper.GetClientState(chain.GetContext(), clientID)
require.True(chain.TB, found)
return clientState
}
// GetConsensusState retrieves the consensus state for the provided clientID and height.
// It will return a success boolean depending on if consensus state exists or not.
func (chain *TestChain) GetConsensusState(clientID string, height exported.Height) (exported.ConsensusState, bool) {
return chain.App.GetIBCKeeper().ClientKeeper.GetClientConsensusState(chain.GetContext(), clientID, height)
}
// GetAcknowledgement retrieves an acknowledgement for the provided packet. If the
// acknowledgement does not exist then testing will fail.
func (chain *TestChain) GetAcknowledgement(packet channeltypes.Packet) []byte {
ack, found := chain.App.GetIBCKeeper().ChannelKeeper.GetPacketAcknowledgement(chain.GetContext(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
require.True(chain.TB, found)
return ack
}
// GetPrefix returns the prefix for used by a chain in connection creation
func (chain *TestChain) GetPrefix() commitmenttypes.MerklePrefix {
return commitmenttypes.NewMerklePrefix(chain.App.GetIBCKeeper().ConnectionKeeper.GetCommitmentPrefix().Bytes())
}
// ExpireClient fast forwards the chain's block time by the provided amount of time which will
// expire any clients with a trusting period less than or equal to this amount of time.
func (chain *TestChain) ExpireClient(amount time.Duration) {
chain.Coordinator.IncrementTimeBy(amount)
}
// CurrentTMClientHeader creates a TM header using the current header parameters
// on the chain. The trusted fields in the header are set to nil.
func (chain *TestChain) CurrentTMClientHeader() *ibctm.Header {
return chain.CreateTMClientHeader(
chain.ChainID,
chain.ProposedHeader.Height,
clienttypes.Height{},
chain.ProposedHeader.Time,
chain.Vals,
chain.NextVals,
nil,
chain.Signers,
)
}
// CommitHeader takes in a proposed header and returns a signed cometbft header.
// The signers passed in must match the validator set provided. The signers will
// be used to sign over the proposed header.
func CommitHeader(proposedHeader cmttypes.Header, valSet *cmttypes.ValidatorSet, signers map[string]cmttypes.PrivValidator) (*cmtproto.SignedHeader, error) {
hhash := proposedHeader.Hash()
blockID := MakeBlockID(hhash, 3, unusedHash)
voteSet := cmttypes.NewVoteSet(proposedHeader.ChainID, proposedHeader.Height, 1, cmtproto.PrecommitType, valSet)
// MakeExtCommit expects a signer array in the same order as the validator array.
// Thus we iterate over the ordered validator set and construct a signer array
// from the signer map in the same order.
signerArr := make([]cmttypes.PrivValidator, len(valSet.Validators))
for i, v := range valSet.Validators { //nolint:staticcheck // need to check for nil validator set
signerArr[i] = signers[v.Address.String()]
}
extCommit, err := cmttypes.MakeExtCommit(blockID, proposedHeader.Height, 1, voteSet, signerArr, proposedHeader.Time, false)
if err != nil {
return nil, err
}
signedHeader := &cmtproto.SignedHeader{
Header: proposedHeader.ToProto(),
Commit: extCommit.ToCommit().ToProto(),
}
return signedHeader, nil
}
// CreateTMClientHeader creates a TM header to update the TM client. Args are passed in to allow
// caller flexibility to use params that differ from the chain.
func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, trustedHeight clienttypes.Height, timestamp time.Time, cmtValSet, nextVals, cmtTrustedVals *cmttypes.ValidatorSet, signers map[string]cmttypes.PrivValidator) *ibctm.Header {
var (
valSet *cmtproto.ValidatorSet
trustedVals *cmtproto.ValidatorSet
)
require.NotNil(chain.TB, cmtValSet)
proposedHeader := cmttypes.Header{
Version: cmtprotoversion.Consensus{Block: cmtversion.BlockProtocol, App: 2},
ChainID: chainID,
Height: blockHeight,
Time: timestamp,
LastBlockID: MakeBlockID(make([]byte, tmhash.Size), 10_000, make([]byte, tmhash.Size)),
LastCommitHash: chain.App.LastCommitID().Hash,
DataHash: unusedHash,
ValidatorsHash: cmtValSet.Hash(),
NextValidatorsHash: nextVals.Hash(),
ConsensusHash: unusedHash,
AppHash: chain.ProposedHeader.AppHash,
LastResultsHash: unusedHash,
EvidenceHash: unusedHash,
ProposerAddress: cmtValSet.Proposer.Address, //nolint:staticcheck
}
signedHeader, err := CommitHeader(proposedHeader, cmtValSet, signers)
require.NoError(chain.TB, err)
if cmtValSet != nil { //nolint:staticcheck
valSet, err = cmtValSet.ToProto()
require.NoError(chain.TB, err)
valSet.TotalVotingPower = cmtValSet.TotalVotingPower()
}
if cmtTrustedVals != nil {
trustedVals, err = cmtTrustedVals.ToProto()
require.NoError(chain.TB, err)
trustedVals.TotalVotingPower = cmtTrustedVals.TotalVotingPower()
}
// The trusted fields may be nil. They may be filled before relaying messages to a client.
// The relayer is responsible for querying client and injecting appropriate trusted fields.
return &ibctm.Header{
SignedHeader: signedHeader,
ValidatorSet: valSet,
TrustedHeight: trustedHeight,
TrustedValidators: trustedVals,
}
}
// MakeBlockID copied unimported test functions from cmttypes to use them here
func MakeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) cmttypes.BlockID {
return cmttypes.BlockID{
Hash: hash,
PartSetHeader: cmttypes.PartSetHeader{
Total: partSetSize,
Hash: partSetHash,
},
}
}
// GetClientLatestHeight returns the latest height for the client state with the given client identifier.
// If an invalid client identifier is provided then a zero value height will be returned and testing will fail.
func (chain *TestChain) GetClientLatestHeight(clientID string) exported.Height {
latestHeight := chain.App.GetIBCKeeper().ClientKeeper.GetClientLatestHeight(chain.GetContext(), clientID)
require.False(chain.TB, latestHeight.IsZero())
return latestHeight
}
// GetTimeoutHeight is a convenience function which returns a IBC packet timeout height
// to be used for testing. It returns the current IBC height + 100 blocks
func (chain *TestChain) GetTimeoutHeight() clienttypes.Height {
return clienttypes.NewHeight(clienttypes.ParseChainID(chain.ChainID), uint64(chain.GetContext().BlockHeight())+100)
}
// GetTimeoutTimestamp is a convenience function which returns a IBC packet timeout timestamp
// to be used for testing. It returns the current block timestamp + default timestamp delta (1 hour).
func (chain *TestChain) GetTimeoutTimestamp() uint64 {
return uint64(chain.GetContext().BlockTime().UnixNano()) + DefaultTimeoutTimestampDelta
}
// GetTimeoutTimestampSecs is a convenience function which returns a IBC packet timeout timestamp in seconds
// to be used for testing. It returns the current block timestamp + default timestamp delta (1 hour).
func (chain *TestChain) GetTimeoutTimestampSecs() uint64 {
return uint64(chain.GetContext().BlockTime().Unix()) + uint64(time.Hour.Seconds())
}
// DeleteKey deletes the specified key from the ibc store.
func (chain *TestChain) DeleteKey(key []byte) {
storeKey := chain.GetSimApp().GetKey(exported.StoreKey)
kvStore := chain.GetContext().KVStore(storeKey)
kvStore.Delete(key)
}
// IBCClientHeader will construct a 07-tendermint Header to update the light client
// on the counterparty chain. The trustedHeight must be passed in as a non-zero height.
func (chain *TestChain) IBCClientHeader(header *ibctm.Header, trustedHeight clienttypes.Height) (*ibctm.Header, error) {
if trustedHeight.IsZero() {
return nil, errorsmod.Wrap(ibctm.ErrInvalidHeaderHeight, "trustedHeight must be a non-zero height")
}
cmtTrustedVals, ok := chain.TrustedValidators[trustedHeight.RevisionHeight]
if !ok {
return nil, fmt.Errorf("unable to find trusted validators at height %d", trustedHeight.RevisionHeight)
}
trustedVals, err := cmtTrustedVals.ToProto()
if err != nil {
return nil, err
}
header.TrustedHeight = trustedHeight
trustedVals.TotalVotingPower = cmtTrustedVals.TotalVotingPower()
header.TrustedValidators = trustedVals
return header, nil
}
// GetSenderAccount returns the sender account associated with the provided private key.
func (chain *TestChain) GetSenderAccount(privKey cryptotypes.PrivKey) SenderAccount {
account := chain.GetSimApp().AccountKeeper.GetAccount(chain.GetContext(), sdk.AccAddress(privKey.PubKey().Address()))
return SenderAccount{
SenderPrivKey: privKey,
SenderAccount: account,
}
}