Pure package detail
tendermint
gno.land/p/aib/ibc/lightclient/tendermint
Indexed deployment identity with independently loaded latest RPC source. Functions and Render are realm-only RPC capabilities.
Indexed deployment
Identity
- Package path
- gno.land/p/aib/ibc/lightclient/tendermint
- Block
- 21886
- Deployed (UTC)
- Transaction
- MptDW04iDOhGquUI7KCLniGTIIf1hanuFS7NXdHOB6g=
Latest RPC state
Source
package tendermint_test
import (
"testing"
"time"
"gno.land/p/aib/ibc/lightclient"
"gno.land/p/aib/ibc/lightclient/tendermint"
"gno.land/p/aib/ibc/types"
"gno.land/p/aib/ics23"
"gno.land/p/nt/uassert/v0"
"gno.land/p/nt/urequire/v0"
)
func TestGetNeighboringConsensusStates(t *testing.T) {
tm := tendermint.NewTMLightClient()
nextValsHash := []byte("nextVals")
height01 := types.NewHeight(0, 1)
cs01 := &tendermint.ConsensusState{
Timestamp: time.Now().UTC(),
Root: tendermint.NewMerkleRoot([]byte("hash0-1")),
NextValidatorsHash: nextValsHash,
}
clientState := tendermint.NewClientState(chainID, tendermint.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height01, ics23.GetSDKProofSpecs(), upgradePath)
err := tm.Initialize(*clientState, *cs01)
urequire.NoError(t, err)
cs04 := &tendermint.ConsensusState{
Timestamp: time.Now().UTC(),
Root: tendermint.NewMerkleRoot([]byte("hash0-4")),
NextValidatorsHash: nextValsHash,
}
cs49 := &tendermint.ConsensusState{
Timestamp: time.Now().UTC(),
Root: tendermint.NewMerkleRoot([]byte("hash4-9")),
NextValidatorsHash: nextValsHash,
}
height04 := types.NewHeight(0, 4)
height49 := types.NewHeight(4, 9)
tm.SetConsensusState(height04, cs04)
tm.SetConsensusState(height49, cs49)
// Previous height01 should return nil
prevCs01, ok := tm.GetPreviousConsensusState(height01)
urequire.True(t, prevCs01 == nil, "consensus state exists before lowest consensus state")
urequire.False(t, ok)
// Previous from non existing height02 should return cs01
prevCs02, ok := tm.GetPreviousConsensusState(types.NewHeight(0, 2))
urequire.Equal(t, string(cs01.Root.Hash), string(prevCs02.Root.Hash),
"previous consensus state is not returned correctly")
urequire.True(t, ok)
// Previous from height49 should return cs04
prevCs49, ok := tm.GetPreviousConsensusState(height49)
urequire.Equal(t, string(cs04.Root.Hash), string(prevCs49.Root.Hash),
"previous consensus state is not returned correctly")
urequire.True(t, ok)
// Next from height01 should return cs04
nextCs01, ok := tm.GetNextConsensusState(height01)
urequire.Equal(t, string(cs04.Root.Hash), string(nextCs01.Root.Hash),
"next consensus state not returned correctly")
urequire.True(t, ok)
// Next from non existing height02 should return cs04
nextCs02, ok := tm.GetNextConsensusState(types.NewHeight(0, 2))
urequire.Equal(t, string(cs04.Root.Hash), string(nextCs02.Root.Hash),
"next consensus state not returned correctly")
urequire.True(t, ok)
// Next from height49 should return nil
nextCs49, ok := tm.GetNextConsensusState(height49)
urequire.True(t, nextCs49 == nil, "next consensus state exists after highest consensus state")
urequire.False(t, ok)
}
func TestRecoverClient(t *testing.T) {
newConsState := func(root string) *tendermint.ConsensusState {
return &tendermint.ConsensusState{
Timestamp: time.Now().UTC(),
Root: tendermint.NewMerkleRoot([]byte(root)),
NextValidatorsHash: []byte("nextVals"),
}
}
// Build two clients with matching immutable parameters, different chainIDs
// and different latest heights.
newSubject := func() *tendermint.TMLightClient {
tm := tendermint.NewTMLightClient()
cs := tendermint.NewClientState("subject-chain", tendermint.DefaultTrustLevel,
trustingPeriod, ubdPeriod, maxClockDrift, types.NewHeight(0, 5),
ics23.GetSDKProofSpecs(), upgradePath)
urequire.NoError(t, tm.Initialize(*cs, *newConsState("subject-root")))
// Freeze the subject so its status becomes Frozen (for realism; not
// required by RecoverClient itself).
tm.ClientState.FrozenHeight = tendermint.FrozenHeight
return tm
}
newSubstitute := func() *tendermint.TMLightClient {
tm := tendermint.NewTMLightClient()
cs := tendermint.NewClientState("substitute-chain", tendermint.DefaultTrustLevel,
trustingPeriod, ubdPeriod, maxClockDrift, types.NewHeight(0, 10),
ics23.GetSDKProofSpecs(), upgradePath)
urequire.NoError(t, tm.Initialize(*cs, *newConsState("substitute-root")))
return tm
}
t.Run("success", func(t *testing.T) {
subject := newSubject()
substitute := newSubstitute()
err := subject.RecoverClient(substitute)
urequire.NoError(t, err)
uassert.Equal(t, "substitute-chain", subject.ClientState.ChainID)
uassert.True(t, subject.ClientState.LatestHeight.EQ(types.NewHeight(0, 10)))
uassert.True(t, subject.ClientState.FrozenHeight.IsZero())
// Substitute consensus state at height (0,10) must have been copied.
cs, found := subject.GetConsensusState(types.NewHeight(0, 10))
urequire.True(t, found, "consensus state at substitute latest height not copied")
uassert.Equal(t, "substitute-root", string(cs.Root.Hash))
})
t.Run("failure: substitute is nil", func(t *testing.T) {
subject := newSubject()
err := subject.RecoverClient(nil)
urequire.Error(t, err)
urequire.ErrorContains(t, err, "substitute must not be nil")
})
t.Run("success: substitute TrustingPeriod is adopted", func(t *testing.T) {
subject := newSubject()
substitute := newSubstitute()
substitute.ClientState.TrustingPeriod = trustingPeriod + time.Hour
err := subject.RecoverClient(substitute)
urequire.NoError(t, err)
uassert.Equal(t, int64(trustingPeriod+time.Hour), int64(subject.ClientState.TrustingPeriod))
})
t.Run("failure: mismatching max clock drift", func(t *testing.T) {
subject := newSubject()
substitute := newSubstitute()
substitute.ClientState.MaxClockDrift = maxClockDrift + time.Second
err := subject.RecoverClient(substitute)
urequire.Error(t, err)
urequire.ErrorContains(t, err, "differ on MaxClockDrift")
})
t.Run("failure: mismatching trust level", func(t *testing.T) {
subject := newSubject()
substitute := newSubstitute()
substitute.ClientState.TrustLevel = tendermint.NewFraction(2, 3)
err := subject.RecoverClient(substitute)
urequire.Error(t, err)
urequire.ErrorContains(t, err, "differ on TrustLevel")
})
t.Run("failure: mismatching unbonding period", func(t *testing.T) {
subject := newSubject()
substitute := newSubstitute()
substitute.ClientState.UnbondingPeriod = ubdPeriod + time.Hour
err := subject.RecoverClient(substitute)
urequire.Error(t, err)
urequire.ErrorContains(t, err, "differ on UnbondingPeriod")
})
t.Run("failure: mismatching proof specs", func(t *testing.T) {
subject := newSubject()
substitute := newSubstitute()
substitute.ClientState.ProofSpecs = substitute.ClientState.ProofSpecs[:1]
err := subject.RecoverClient(substitute)
urequire.Error(t, err)
urequire.ErrorContains(t, err, "differ on ProofSpecs")
})
t.Run("failure: mismatching upgrade path", func(t *testing.T) {
subject := newSubject()
substitute := newSubstitute()
substitute.ClientState.UpgradePath = []string{"otherUpgrade"}
err := subject.RecoverClient(substitute)
urequire.Error(t, err)
urequire.ErrorContains(t, err, "differ on UpgradePath")
})
t.Run("failure: missing consensus state at substitute latest height", func(t *testing.T) {
subject := newSubject()
substitute := newSubstitute()
// Drop the consensus state that Initialize stored.
substitute.ConsensusStateByHeight.Remove(substitute.ClientState.LatestHeight.StringNatSort())
err := subject.RecoverClient(substitute)
urequire.Error(t, err)
urequire.ErrorContains(t, err, "substitute consensus state not found")
})
// Assertion that interface conformance holds when calling through the
// lightclient.Interface type (catches future signature drift).
t.Run("success via Interface", func(t *testing.T) {
subject := newSubject()
var substitute lightclient.Interface = newSubstitute()
err := subject.RecoverClient(substitute)
urequire.NoError(t, err)
})
}
func TestVerifyUpgradeAndUpdateStateFailures(t *testing.T) {
currentHeight := types.NewHeight(0, 5)
upgradedHeight := types.NewHeight(0, 10)
newClient := func() *tendermint.TMLightClient {
tm := tendermint.NewTMLightClient()
cs := tendermint.NewClientState(chainID, tendermint.DefaultTrustLevel,
trustingPeriod, ubdPeriod, maxClockDrift, currentHeight,
ics23.GetSDKProofSpecs(), upgradePath)
validHash := make([]byte, 32)
for i := range validHash {
validHash[i] = byte(i + 1)
}
consState := &tendermint.ConsensusState{
Timestamp: time.Now().UTC(),
Root: tendermint.NewMerkleRoot([]byte("current-root")),
NextValidatorsHash: validHash,
}
urequire.NoError(t, tm.Initialize(*cs, *consState))
return tm
}
validUpgradedClient := tendermint.ClientState{
ChainID: "chain-after-upgrade",
TrustLevel: tendermint.DefaultTrustLevel,
TrustingPeriod: trustingPeriod,
UnbondingPeriod: ubdPeriod,
MaxClockDrift: maxClockDrift,
LatestHeight: upgradedHeight,
ProofSpecs: ics23.GetSDKProofSpecs(),
UpgradePath: upgradePath,
}
thirtyTwoBytes := make([]byte, 32)
for i := range thirtyTwoBytes {
thirtyTwoBytes[i] = byte(i)
}
validUpgradedConsState := tendermint.ConsensusState{
Timestamp: time.Now().UTC(),
Root: tendermint.NewMerkleRoot([]byte("upgraded-root")),
NextValidatorsHash: thirtyTwoBytes,
}
dummyProof := []ics23.CommitmentProof{ics23.CommitmentProof_Exist{Exist: &ics23.ExistenceProof{}}}
t.Run("failure: newClient wrong type", func(t *testing.T) {
tm := newClient()
err := tm.VerifyUpgradeAndUpdateState("not-a-client-state", validUpgradedConsState, dummyProof, dummyProof)
urequire.Error(t, err)
urequire.ErrorContains(t, err, "must be tendermint.ClientState")
})
t.Run("failure: invalid upgraded client state", func(t *testing.T) {
tm := newClient()
bad := validUpgradedClient
bad.ChainID = "" // fails ValidateBasic
err := tm.VerifyUpgradeAndUpdateState(bad, validUpgradedConsState, dummyProof, dummyProof)
urequire.Error(t, err)
urequire.ErrorContains(t, err, "invalid upgraded client state")
})
t.Run("failure: newConsState wrong type", func(t *testing.T) {
tm := newClient()
err := tm.VerifyUpgradeAndUpdateState(validUpgradedClient, "not-a-consensus-state", dummyProof, dummyProof)
urequire.Error(t, err)
urequire.ErrorContains(t, err, "must be tendermint.ConsensusState")
})
t.Run("failure: invalid upgraded consensus state", func(t *testing.T) {
tm := newClient()
bad := validUpgradedConsState
bad.Root = tendermint.MerkleRoot{} // empty root → ValidateBasic fails
err := tm.VerifyUpgradeAndUpdateState(validUpgradedClient, bad, dummyProof, dummyProof)
urequire.Error(t, err)
urequire.ErrorContains(t, err, "invalid upgraded consensus state")
})
t.Run("failure: empty UpgradePath on current client", func(t *testing.T) {
tm := newClient()
tm.ClientState.UpgradePath = nil
err := tm.VerifyUpgradeAndUpdateState(validUpgradedClient, validUpgradedConsState, dummyProof, dummyProof)
urequire.Error(t, err)
urequire.ErrorContains(t, err, "no upgrade path set")
})
t.Run("failure: upgraded latest height not greater than current", func(t *testing.T) {
tm := newClient()
notGreater := validUpgradedClient
notGreater.LatestHeight = currentHeight
err := tm.VerifyUpgradeAndUpdateState(notGreater, validUpgradedConsState, dummyProof, dummyProof)
urequire.Error(t, err)
urequire.ErrorContains(t, err, "must be greater than current latest height")
})
t.Run("failure: clientProof wrong type", func(t *testing.T) {
tm := newClient()
err := tm.VerifyUpgradeAndUpdateState(validUpgradedClient, validUpgradedConsState, []byte("raw"), dummyProof)
urequire.Error(t, err)
urequire.ErrorContains(t, err, "upgradeClientProof must be []ics23.CommitmentProof")
})
t.Run("failure: clientProof empty", func(t *testing.T) {
tm := newClient()
err := tm.VerifyUpgradeAndUpdateState(validUpgradedClient, validUpgradedConsState, []ics23.CommitmentProof{}, dummyProof)
urequire.Error(t, err)
urequire.ErrorContains(t, err, "upgradeClientProof cannot be empty")
})
t.Run("failure: consensusProof wrong type", func(t *testing.T) {
tm := newClient()
err := tm.VerifyUpgradeAndUpdateState(validUpgradedClient, validUpgradedConsState, dummyProof, "not-a-proof")
urequire.Error(t, err)
urequire.ErrorContains(t, err, "upgradeConsensusStateProof must be []ics23.CommitmentProof")
})
t.Run("failure: consensusProof empty", func(t *testing.T) {
tm := newClient()
err := tm.VerifyUpgradeAndUpdateState(validUpgradedClient, validUpgradedConsState, dummyProof, []ics23.CommitmentProof{})
urequire.Error(t, err)
urequire.ErrorContains(t, err, "upgradeConsensusStateProof cannot be empty")
})
}
The verified vm/qfuncs operation accepts realm paths only.
Pure packages expose source files but do not have Realm Render.