Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"Bug Fixes" for any bug fixes.
"Client Breaking" for breaking CLI commands and REST routes used by end-users.
"API Breaking" for breaking exported APIs used by developers building on SDK.
"State Machine Breaking" for any changes that result in a different AppState given same genesisState and txList.
"State Machine Breaking" for any changes that result in a different AppState given the same genesisState and txList.

-->

Expand All @@ -16,9 +16,13 @@ An '!' indicates a state machine breaking change.

## Unreleased

### Improvements

- ! [#154](https://github.com/bcp-innovations/hyperlane-cosmos/pull/154) Charge gas for signature verification.

### Bug Fixes

- [#153](https://github.com/bcp-innovations/hyperlane-cosmos/pull/153) Fix SetDomain for RoutingISM.
- ! [#153](https://github.com/bcp-innovations/hyperlane-cosmos/pull/153) Fix SetDomain for RoutingISM.

## [v1.0.1](https://github.com/bcp-innovations/hyperlane-cosmos/releases/tag/v1.0.1) - 2025-06-05

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import (
"fmt"
"slices"

storetypes "cosmossdk.io/store/types"
"github.com/bcp-innovations/hyperlane-cosmos/util"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/crypto"
)

Expand All @@ -20,7 +22,7 @@ func (m *MerkleRootMultisigISM) ModuleType() uint8 {
return INTERCHAIN_SECURITY_MODULE_TYPE_MERKLE_ROOT_MULTISIG
}

func (m *MerkleRootMultisigISM) Verify(_ context.Context, rawMetadata []byte, message util.HyperlaneMessage) (bool, error) {
func (m *MerkleRootMultisigISM) Verify(ctx context.Context, rawMetadata []byte, message util.HyperlaneMessage) (bool, error) {
metadata, err := NewMerkleRootMultisigMetadata(rawMetadata)
if err != nil {
return false, err
Expand All @@ -32,6 +34,9 @@ func (m *MerkleRootMultisigISM) Verify(_ context.Context, rawMetadata []byte, me

digest := metadata.Digest(&message)

// Charge Cosmos gas for each signature verification.
sdk.UnwrapSDKContext(ctx).GasMeter().ConsumeGas(storetypes.Gas(1000*len(metadata.Signatures)), "ism signature verification")

return VerifyMultisig(m.Validators, m.Threshold, metadata.Signatures, digest)
}

Expand Down
28 changes: 18 additions & 10 deletions x/core/01_interchain_security/types/merkle_root_multisig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package types_test
import (
"fmt"

i "github.com/bcp-innovations/hyperlane-cosmos/tests/integration"
"github.com/bcp-innovations/hyperlane-cosmos/util"
"github.com/bcp-innovations/hyperlane-cosmos/x/core/01_interchain_security/types"
sdk "github.com/cosmos/cosmos-sdk/types"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
Expand Down Expand Up @@ -33,6 +33,12 @@ TEST CASES - merkle_root_multisig.go
*/

var _ = Describe("merkle_root_multisig.go", Ordered, func() {
var s *i.KeeperTestSuite

BeforeEach(func() {
s = i.NewCleanChain()
})

It("Validate (invalid) invalid validators", func() {
// Arrange
validators := []string{
Expand Down Expand Up @@ -158,7 +164,7 @@ var _ = Describe("merkle_root_multisig.go", Ordered, func() {
metadata := bytesFromHexString("")

// Act
verify, err := merkleRootMultisigIsm.Verify(sdk.Context{}, metadata, util.HyperlaneMessage{})
verify, err := merkleRootMultisigIsm.Verify(s.Ctx(), metadata, util.HyperlaneMessage{})

// Assert
Expect(err.Error()).To(Equal("invalid metadata length: got 0, expected at least 1096 bytes"))
Expand Down Expand Up @@ -202,7 +208,7 @@ var _ = Describe("merkle_root_multisig.go", Ordered, func() {
metadata.Signatures = signatures

// Act
verify, err := merkleRootMultisigIsm.Verify(sdk.Context{}, metadata.Bytes(), message)
verify, err := merkleRootMultisigIsm.Verify(s.Ctx(), metadata.Bytes(), message)

// Assert
Expect(err.Error()).To(Equal("invalid signatures length in metadata"))
Expand Down Expand Up @@ -245,7 +251,7 @@ var _ = Describe("merkle_root_multisig.go", Ordered, func() {
metadata.Signatures = signatures

// Act
verify, err := merkleRootMultisigIsm.Verify(sdk.Context{}, metadata.Bytes(), message)
verify, err := merkleRootMultisigIsm.Verify(s.Ctx(), metadata.Bytes(), message)

// Assert
Expect(err.Error()).To(Equal("invalid signed index"))
Expand Down Expand Up @@ -288,7 +294,7 @@ var _ = Describe("merkle_root_multisig.go", Ordered, func() {
metadata.Signatures = signatures

// Act
verify, err := merkleRootMultisigIsm.Verify(sdk.Context{}, metadata.Bytes(), message)
verify, err := merkleRootMultisigIsm.Verify(s.Ctx(), metadata.Bytes(), message)

// Assert
Expect(err.Error()).To(Equal("threshold can not be reached"))
Expand Down Expand Up @@ -329,7 +335,7 @@ var _ = Describe("merkle_root_multisig.go", Ordered, func() {
metadata.Signatures = signatures

// Act
verify, err := merkleRootMultisigIsm.Verify(sdk.Context{}, metadata.Bytes(), message)
verify, err := merkleRootMultisigIsm.Verify(s.Ctx(), metadata.Bytes(), message)

// Assert
Expect(err.Error()).To(Equal("failed to recover validator signature: invalid signature recovery id"))
Expand Down Expand Up @@ -372,7 +378,7 @@ var _ = Describe("merkle_root_multisig.go", Ordered, func() {
metadata.Signatures = signatures

// Act
verify, err := merkleRootMultisigIsm.Verify(sdk.Context{}, metadata.Bytes(), message)
verify, err := merkleRootMultisigIsm.Verify(s.Ctx(), metadata.Bytes(), message)

// Assert
Expect(err).To(BeNil())
Expand Down Expand Up @@ -422,7 +428,7 @@ var _ = Describe("merkle_root_multisig.go", Ordered, func() {
metadata.Signatures = duplicatedSignatures

// Act
verify, err := merkleRootMultisigIsm.Verify(sdk.Context{}, metadata.Bytes(), message)
verify, err := merkleRootMultisigIsm.Verify(s.Ctx(), metadata.Bytes(), message)

// Assert
Expect(err).To(BeNil())
Expand Down Expand Up @@ -473,11 +479,12 @@ var _ = Describe("merkle_root_multisig.go", Ordered, func() {
metadata.Signatures = signatures

// Act
verify, err := merkleRootMultisigIsm.Verify(sdk.Context{}, metadata.Bytes(), message)
verify, err := merkleRootMultisigIsm.Verify(s.Ctx(), metadata.Bytes(), message)

// Assert
Expect(err).To(BeNil())
Expect(verify).To(BeTrue())
Expect(int(s.Ctx().GasMeter().GasConsumed())).To(Equal(3000))
})

// Verifies metadata and messages submitted by a Hyperlane Relayer.
Expand All @@ -497,9 +504,10 @@ var _ = Describe("merkle_root_multisig.go", Ordered, func() {
}

// Act
verify, err := merkleRootMultiSig.Verify(sdk.Context{}, validMetadata, validMessage)
verify, err := merkleRootMultiSig.Verify(s.Ctx(), validMetadata, validMessage)

// Assert
Expect(int(s.Ctx().GasMeter().GasConsumed())).To(Equal(1000))
Expect(err).To(BeNil())
Expect(verify).To(BeTrue())
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import (
"fmt"
"slices"

storetypes "cosmossdk.io/store/types"
"github.com/bcp-innovations/hyperlane-cosmos/util"
sdk "github.com/cosmos/cosmos-sdk/types"
)

var _ HyperlaneInterchainSecurityModule = &MessageIdMultisigISM{}
Expand All @@ -19,14 +21,17 @@ func (m *MessageIdMultisigISM) ModuleType() uint8 {
return INTERCHAIN_SECURITY_MODULE_TYPE_MESSAGE_ID_MULTISIG
}

func (m *MessageIdMultisigISM) Verify(_ context.Context, rawMetadata []byte, message util.HyperlaneMessage) (bool, error) {
func (m *MessageIdMultisigISM) Verify(ctx context.Context, rawMetadata []byte, message util.HyperlaneMessage) (bool, error) {
metadata, err := NewMessageIdMultisigMetadata(rawMetadata)
if err != nil {
return false, err
}

digest := metadata.Digest(&message)

// Charge Cosmos gas for each signature verification.
sdk.UnwrapSDKContext(ctx).GasMeter().ConsumeGas(storetypes.Gas(1000*len(metadata.Signatures)), "ism signature verification")

return VerifyMultisig(m.Validators, m.Threshold, metadata.Signatures, digest)
}

Expand Down
23 changes: 15 additions & 8 deletions x/core/01_interchain_security/types/message_id_multisig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package types_test
import (
"fmt"

i "github.com/bcp-innovations/hyperlane-cosmos/tests/integration"
"github.com/bcp-innovations/hyperlane-cosmos/util"
"github.com/bcp-innovations/hyperlane-cosmos/x/core/01_interchain_security/types"
sdk "github.com/cosmos/cosmos-sdk/types"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
Expand All @@ -31,6 +31,12 @@ TEST CASES - message_id_multisig.go
*/

var _ = Describe("message_id_multisig.go", Ordered, func() {
var s *i.KeeperTestSuite

BeforeEach(func() {
s = i.NewCleanChain()
})

It("Validate (invalid) invalid validators", func() {
// Arrange
validators := []string{
Expand Down Expand Up @@ -155,7 +161,7 @@ var _ = Describe("message_id_multisig.go", Ordered, func() {
metadata := bytesFromHexString("")

// Act
verify, err := messageIdMultisigIsm.Verify(sdk.Context{}, metadata, util.HyperlaneMessage{})
verify, err := messageIdMultisigIsm.Verify(s.Ctx(), metadata, util.HyperlaneMessage{})

// Assert
Expect(err.Error()).To(Equal("invalid metadata length: got 0, expected at least 68 bytes"))
Expand Down Expand Up @@ -197,7 +203,7 @@ var _ = Describe("message_id_multisig.go", Ordered, func() {
metadata.Signatures = signatures

// Act
verify, err := merkleRootMultisigIsm.Verify(sdk.Context{}, metadata.Bytes(), message)
verify, err := merkleRootMultisigIsm.Verify(s.Ctx(), metadata.Bytes(), message)

// Assert
Expect(err.Error()).To(Equal("invalid signatures length in metadata"))
Expand Down Expand Up @@ -237,7 +243,7 @@ var _ = Describe("message_id_multisig.go", Ordered, func() {
metadata.Signatures = signatures

// Act
verify, err := messageIdMultisigIsm.Verify(sdk.Context{}, metadata.Bytes(), message)
verify, err := messageIdMultisigIsm.Verify(s.Ctx(), metadata.Bytes(), message)

// Assert
Expect(err.Error()).To(Equal("threshold can not be reached"))
Expand Down Expand Up @@ -275,7 +281,7 @@ var _ = Describe("message_id_multisig.go", Ordered, func() {
metadata.Signatures = signatures

// Act
verify, err := messageIdMultisigIsm.Verify(sdk.Context{}, metadata.Bytes(), message)
verify, err := messageIdMultisigIsm.Verify(s.Ctx(), metadata.Bytes(), message)

// Assert
Expect(err.Error()).To(Equal("failed to recover validator signature: invalid signature recovery id"))
Expand Down Expand Up @@ -315,7 +321,7 @@ var _ = Describe("message_id_multisig.go", Ordered, func() {
metadata.Signatures = signatures

// Act
verify, err := messageIdMultisigIsm.Verify(sdk.Context{}, metadata.Bytes(), message)
verify, err := messageIdMultisigIsm.Verify(s.Ctx(), metadata.Bytes(), message)

// Assert
Expect(err).To(BeNil())
Expand Down Expand Up @@ -362,7 +368,7 @@ var _ = Describe("message_id_multisig.go", Ordered, func() {
metadata.Signatures = duplicatedSignatures

// Act
verify, err := messageIdMultisigIsm.Verify(sdk.Context{}, metadata.Bytes(), message)
verify, err := messageIdMultisigIsm.Verify(s.Ctx(), metadata.Bytes(), message)

// Assert
Expect(err).To(BeNil())
Expand Down Expand Up @@ -409,9 +415,10 @@ var _ = Describe("message_id_multisig.go", Ordered, func() {
metadata.Signatures = signatures

// Act
verify, err := messageIdMultisigIsm.Verify(sdk.Context{}, metadata.Bytes(), message)
verify, err := messageIdMultisigIsm.Verify(s.Ctx(), metadata.Bytes(), message)

// Assert
Expect(int(s.Ctx().GasMeter().GasConsumed())).To(Equal(3000))
Expect(err).To(BeNil())
Expect(verify).To(BeTrue())
})
Expand Down