Skip to content

Commit

Permalink
fix(axelarnet)!: allow routing messages from gov module to wasm (#2168)
Browse files Browse the repository at this point in the history
  • Loading branch information
milapsheth authored Jul 30, 2024
1 parent f8d8372 commit 9766291
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 7 deletions.
16 changes: 13 additions & 3 deletions x/axelarnet/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package axelarnet
import (
"encoding/hex"
"fmt"
"strings"

"github.com/CosmWasm/wasmd/x/wasm"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
Expand All @@ -14,7 +16,7 @@ import (
"github.com/axelarnetwork/axelar-core/x/axelarnet/keeper"
"github.com/axelarnetwork/axelar-core/x/axelarnet/types"
nexus "github.com/axelarnetwork/axelar-core/x/nexus/exported"
"github.com/axelarnetwork/utils/funcs"
tss "github.com/axelarnetwork/axelar-core/x/tss/exported"
)

// NewHandler returns the handler of the Cosmos module
Expand Down Expand Up @@ -106,10 +108,18 @@ func NewProposalHandler(k keeper.Keeper, nexusK types.Nexus, accountK types.Acco
case *types.CallContractsProposal:
for _, contractCall := range c.ContractCalls {
sender := nexus.CrossChainAddress{Chain: exported.Axelarnet, Address: accountK.GetModuleAddress(govtypes.ModuleName).String()}
recipient := nexus.CrossChainAddress{Chain: funcs.MustOk(nexusK.GetChain(ctx, contractCall.Chain)), Address: contractCall.ContractAddress}

destChain, ok := nexusK.GetChain(ctx, contractCall.Chain)
if !ok {
// Try forwarding it to wasm router if destination chain is not registered
// Wasm chain names are always lower case, so normalize it for consistency in core
destChainName := nexus.ChainName(strings.ToLower(contractCall.Chain.String()))
destChain = nexus.Chain{Name: destChainName, SupportsForeignAssets: false, KeyType: tss.None, Module: wasm.ModuleName}
}
recipient := nexus.CrossChainAddress{Chain: destChain, Address: contractCall.ContractAddress}

// axelar gateway expects keccak256 hashes for payloads
payloadHash := crypto.Keccak256(contractCall.Payload)

msgID, txID, nonce := nexusK.GenerateMessageID(ctx)
msg := nexus.NewGeneralMessage(msgID, sender, recipient, payloadHash, txID, nonce, nil)

Expand Down
125 changes: 125 additions & 0 deletions x/axelarnet/handler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package axelarnet_test

import (
"encoding/hex"
"fmt"
"strings"
"testing"

"github.com/CosmWasm/wasmd/x/wasm"
sdk "github.com/cosmos/cosmos-sdk/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/assert"

"github.com/axelarnetwork/axelar-core/testutils/rand"
"github.com/axelarnetwork/axelar-core/x/axelarnet"
"github.com/axelarnetwork/axelar-core/x/axelarnet/exported"
"github.com/axelarnetwork/axelar-core/x/axelarnet/keeper"
"github.com/axelarnetwork/axelar-core/x/axelarnet/types"
"github.com/axelarnetwork/axelar-core/x/axelarnet/types/mock"
evmtypes "github.com/axelarnetwork/axelar-core/x/evm/types"
evmtestutils "github.com/axelarnetwork/axelar-core/x/evm/types/testutils"
nexusTypes "github.com/axelarnetwork/axelar-core/x/nexus/exported"
nexustestutils "github.com/axelarnetwork/axelar-core/x/nexus/exported/testutils"
. "github.com/axelarnetwork/utils/test"
)

func TestProposalHandler(t *testing.T) {
var (
ctx sdk.Context
k keeper.Keeper
n *mock.NexusMock
a *mock.AccountKeeperMock
handler govtypes.Handler
proposal *types.CallContractsProposal

destChain nexusTypes.Chain
contractCall types.ContractCall
genMsg nexusTypes.GeneralMessage
governanceAccount sdk.AccAddress
)

givenProposal := Given("a CallContractsProposal", func() {
ctx, k, _ = setup()

destChain = nexustestutils.RandomChain()
destChain.Module = evmtypes.ModuleName
governanceAccount = rand.AccAddr()

contractCall = types.ContractCall{
Chain: destChain.Name,
ContractAddress: evmtestutils.RandomAddress().Hex(),
Payload: rand.BytesBetween(100, 500),
}

proposal = &types.CallContractsProposal{
Title: "Test Proposal",
Description: "This is a test proposal",
ContractCalls: []types.ContractCall{contractCall},
}

n = &mock.NexusMock{
SetNewMessageFunc: func(ctx sdk.Context, msg nexusTypes.GeneralMessage) error {
genMsg = msg
return nil
},
GenerateMessageIDFunc: func(ctx sdk.Context) (string, []byte, uint64) {
hash := rand.Bytes(32)
return fmt.Sprintf("%s-%d", hex.EncodeToString(hash[:]), 0), hash[:], 0
},
}

a = &mock.AccountKeeperMock{
GetModuleAddressFunc: func(name string) sdk.AccAddress {
return governanceAccount
},
}

handler = axelarnet.NewProposalHandler(k, n, a)
})

whenDestChainIsFound := givenProposal.
When("destination chain is found in nexus", func() {
n.GetChainFunc = func(ctx sdk.Context, chain nexusTypes.ChainName) (nexusTypes.Chain, bool) {
return destChain, true
}
})

whenDestChainIsNotFound := givenProposal.
When("destination chain is not found in nexus", func() {
n.GetChainFunc = func(ctx sdk.Context, chain nexusTypes.ChainName) (nexusTypes.Chain, bool) {
if chain == exported.Axelarnet.Name {
return exported.Axelarnet, true
}
return nexusTypes.Chain{}, false
}
})

whenDestChainIsFound.
Then("should set new message in nexus", func(t *testing.T) {
err := handler(ctx, proposal)
assert.NoError(t, err)

assert.Equal(t, genMsg.Sender.Address, governanceAccount.String())
assert.Equal(t, genMsg.Sender.Chain, exported.Axelarnet)
assert.Equal(t, genMsg.Recipient.Chain, destChain)
assert.Equal(t, genMsg.Recipient.Address, contractCall.ContractAddress)
assert.Equal(t, genMsg.PayloadHash, crypto.Keccak256(contractCall.Payload))
}).
Run(t)

whenDestChainIsNotFound.
Then("should set new message in nexus with wasm chain", func(t *testing.T) {
err := handler(ctx, proposal)
assert.NoError(t, err)

assert.Equal(t, genMsg.Sender.Address, governanceAccount.String())
assert.Equal(t, genMsg.Sender.Chain, exported.Axelarnet)
assert.Equal(t, genMsg.Recipient.Chain.Name, nexusTypes.ChainName(strings.ToLower(contractCall.Chain.String())))
assert.Equal(t, genMsg.Recipient.Chain.Module, wasm.ModuleName)
assert.Equal(t, genMsg.Recipient.Address, contractCall.ContractAddress)
assert.Equal(t, genMsg.PayloadHash, crypto.Keccak256(contractCall.Payload))
}).
Run(t)
}
7 changes: 4 additions & 3 deletions x/axelarnet/message_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,11 +252,12 @@ func handleMessage(ctx sdk.Context, n types.Nexus, b types.BankKeeper, sourceAdd
return err
}

chainName := nexus.ChainName(msg.DestinationChain)
destChain, ok := n.GetChain(ctx, chainName)
destChain, ok := n.GetChain(ctx, nexus.ChainName(msg.DestinationChain))
if !ok {
// try forwarding it to wasm router if destination chain is not registered
destChain = nexus.Chain{Name: chainName, SupportsForeignAssets: false, KeyType: tss.None, Module: wasm.ModuleName}
// Wasm chain names are always lower case, so normalize it for consistency in core
destChainName := nexus.ChainName(strings.ToLower(msg.DestinationChain))
destChain = nexus.Chain{Name: destChainName, SupportsForeignAssets: false, KeyType: tss.None, Module: wasm.ModuleName}
}

recipient := nexus.CrossChainAddress{Chain: destChain, Address: msg.DestinationAddress}
Expand Down
5 changes: 4 additions & 1 deletion x/evm/keeper/vote_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keeper

import (
"fmt"
"strings"

"github.com/CosmWasm/wasmd/x/wasm"
"github.com/cosmos/cosmos-sdk/codec"
Expand Down Expand Up @@ -242,7 +243,9 @@ func mustToGeneralMessage(ctx sdk.Context, n types.Nexus, event types.Event) nex
destinationChain, ok := n.GetChain(ctx, contractCall.DestinationChain)
if !ok {
// try forwarding it to wasm router if destination chain is not registered
destinationChain = nexus.Chain{Name: contractCall.DestinationChain, SupportsForeignAssets: false, KeyType: tss.None, Module: wasm.ModuleName}
// Wasm chain names are always lower case, so normalize it for consistency in core
destChainName := nexus.ChainName(strings.ToLower(contractCall.DestinationChain.String()))
destinationChain = nexus.Chain{Name: destChainName, SupportsForeignAssets: false, KeyType: tss.None, Module: wasm.ModuleName}
}
recipient := nexus.CrossChainAddress{Chain: destinationChain, Address: contractCall.ContractAddress}

Expand Down
4 changes: 4 additions & 0 deletions x/evm/keeper/vote_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package keeper_test
import (
"fmt"
mathRand "math/rand"
"strings"
"testing"

"github.com/CosmWasm/wasmd/x/wasm"
Expand Down Expand Up @@ -401,6 +402,9 @@ func TestHandleResult(t *testing.T) {

for _, call := range nexusK.SetNewMessageCalls() {
assert.Equal(t, wasm.ModuleName, call.M.Recipient.Chain.Module)

destChainName := call.M.Recipient.Chain.Name.String()
assert.Equal(t, strings.ToLower(destChainName), destChainName)
}
}),
).
Expand Down

0 comments on commit 9766291

Please sign in to comment.