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

feat(evm): route contract call via the nexus module #2012

Merged
Show file tree
Hide file tree
Changes from all 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
36 changes: 27 additions & 9 deletions x/evm/keeper/chainKeeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -857,22 +857,14 @@ func (k chainKeeper) GetEvent(ctx sdk.Context, eventID types.EventID) (event typ
return event, event.Status != types.EventNonExistent
}

// SetConfirmedEvent sets the event as confirmed
func (k chainKeeper) SetConfirmedEvent(ctx sdk.Context, event types.Event) error {
eventID := event.GetID()
if _, ok := k.GetEvent(ctx, eventID); ok {
return fmt.Errorf("event %s is already confirmed", eventID)
}

event.Status = types.EventConfirmed

switch event.GetEvent().(type) {
case *types.Event_ContractCall, *types.Event_ContractCallWithToken, *types.Event_TokenSent,
*types.Event_Transfer, *types.Event_TokenDeployed, *types.Event_MultisigOperatorshipTransferred:
k.GetConfirmedEventQueue(ctx).Enqueue(getEventKey(eventID), &event)
default:
return fmt.Errorf("unsupported event type %T", event)
}
k.setEvent(ctx, event)

events.Emit(ctx, &types.EVMEventConfirmed{
Chain: event.Chain,
Expand All @@ -883,6 +875,32 @@ func (k chainKeeper) SetConfirmedEvent(ctx sdk.Context, event types.Event) error
return nil
}

// EnqueueConfirmedEvent enqueues the confirmed event
func (k chainKeeper) EnqueueConfirmedEvent(ctx sdk.Context, id types.EventID) error {
event, ok := k.GetEvent(ctx, id)
if !ok {
return fmt.Errorf("event %s does not exist", id)
}
if event.Status != types.EventConfirmed {
return fmt.Errorf("event %s is not confirmed", id)
}

switch event.GetEvent().(type) {
// the missing Event_ContractCall is no longer allowed to be enqueued in the
// EVM module, it must be routed through the nexus module instead
case *types.Event_ContractCallWithToken,
*types.Event_TokenSent,
*types.Event_Transfer,
*types.Event_TokenDeployed,
*types.Event_MultisigOperatorshipTransferred:
k.GetConfirmedEventQueue(ctx).Enqueue(getEventKey(id), &event)
default:
return fmt.Errorf("unsupported event type %T", event)
}

return nil
}

// SetEventCompleted sets the event as completed
func (k chainKeeper) SetEventCompleted(ctx sdk.Context, eventID types.EventID) error {
event, ok := k.GetEvent(ctx, eventID)
Expand Down
67 changes: 58 additions & 9 deletions x/evm/keeper/vote_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ package keeper
import (
"fmt"

"github.com/CosmWasm/wasmd/x/wasm"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/axelarnetwork/axelar-core/utils"
"github.com/axelarnetwork/axelar-core/utils/events"
"github.com/axelarnetwork/axelar-core/x/evm/types"
nexus "github.com/axelarnetwork/axelar-core/x/nexus/exported"
tss "github.com/axelarnetwork/axelar-core/x/tss/exported"
vote "github.com/axelarnetwork/axelar-core/x/vote/exported"
"github.com/axelarnetwork/utils/funcs"
)
Expand Down Expand Up @@ -177,24 +180,31 @@ func (v voteHandler) HandleResult(ctx sdk.Context, result codec.ProtoMarshaler)
}

for _, event := range voteEvents.Events {
if err := handleEvent(ctx, ck, event, chain); err != nil {
if err := v.handleEvent(ctx, ck, event, chain); err != nil {
return err
}
}

return nil
}

func handleEvent(ctx sdk.Context, ck types.ChainKeeper, event types.Event, chain nexus.Chain) error {
// check if event confirmed before
eventID := event.GetID()
if _, ok := ck.GetEvent(ctx, eventID); ok {
return fmt.Errorf("event %s is already confirmed", eventID)
}
func (v voteHandler) handleEvent(ctx sdk.Context, ck types.ChainKeeper, event types.Event, chain nexus.Chain) error {
if err := ck.SetConfirmedEvent(ctx, event); err != nil {
panic(err)
return err
}
ck.Logger(ctx).Info(fmt.Sprintf("confirmed %s event %s in transaction %s", chain.Name, eventID, event.TxID.Hex()))

// Event_ContractCall is no longer directly handled by the EVM module,
// which bypassed nexus routing
switch event.GetEvent().(type) {
case *types.Event_ContractCall:
if err := v.handleContractCall(ctx, event); err != nil {
return err
}
default:
funcs.MustNoErr(ck.EnqueueConfirmedEvent(ctx, event.GetID()))
}
cgorenflo marked this conversation as resolved.
Show resolved Hide resolved
fish-sammy marked this conversation as resolved.
Show resolved Hide resolved

ck.Logger(ctx).Info(fmt.Sprintf("confirmed %s event %s in transaction %s", chain.Name, event.GetID(), event.TxID.Hex()))

// Deprecated
ctx.EventManager().EmitEvent(
Expand All @@ -210,6 +220,45 @@ func handleEvent(ctx sdk.Context, ck types.ChainKeeper, event types.Event, chain
return nil
}

func (v voteHandler) handleContractCall(ctx sdk.Context, event types.Event) error {
msg := mustToGeneralMessage(ctx, v.nexus, event)

if err := v.nexus.SetNewMessage(ctx, msg); err != nil {
return err
}

if !msg.Recipient.Chain.IsFrom(types.ModuleName) {
return nil
}

// if the message is sent to an EVM chain, try setting the message processing
// so that the end blocker can pick it up
_ = utils.RunCached(ctx, v.keeper, func(ctx sdk.Context) (bool, error) {
err := v.nexus.SetMessageProcessing(ctx, msg.ID)

return err == nil, err
})

return nil
}

func mustToGeneralMessage(ctx sdk.Context, n types.Nexus, event types.Event) nexus.GeneralMessage {
id := string(event.GetID())
contractCall := event.GetEvent().(*types.Event_ContractCall).ContractCall

sourceChain := funcs.MustOk(n.GetChain(ctx, event.Chain))
sender := nexus.CrossChainAddress{Chain: sourceChain, Address: contractCall.Sender.Hex()}

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}
}
recipient := nexus.CrossChainAddress{Chain: destinationChain, Address: contractCall.ContractAddress}

return nexus.NewGeneralMessage(id, sender, recipient, contractCall.PayloadHash.Bytes(), event.TxID.Bytes(), event.Index, nil)
}

func mustGetMetadata(poll vote.Poll) types.PollMetadata {
md := funcs.MustOk(poll.GetMetaData())
metadata, ok := md.(*types.PollMetadata)
Expand Down
Loading
Loading