Skip to content

Commit

Permalink
Move cctx gateway outside of crosschain keeper wip
Browse files Browse the repository at this point in the history
  • Loading branch information
skosito committed Jun 12, 2024
1 parent 59c6d5f commit 36b38f8
Show file tree
Hide file tree
Showing 10 changed files with 611 additions and 583 deletions.
9 changes: 1 addition & 8 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ import (

"github.com/zeta-chain/zetacore/app/ante"
"github.com/zeta-chain/zetacore/docs/openapi"
"github.com/zeta-chain/zetacore/pkg/chains"
zetamempool "github.com/zeta-chain/zetacore/pkg/mempool"
srvflags "github.com/zeta-chain/zetacore/server/flags"
authoritymodule "github.com/zeta-chain/zetacore/x/authority"
Expand Down Expand Up @@ -598,13 +597,7 @@ func New(
app.LightclientKeeper,
)

// initializing map of cctx gateways so crosschain module can decide which one to use
// based on chain info of destination chain
cctxGateways := map[chains.CCTXGateway]crosschainkeeper.CCTXGateway{
chains.CCTXGateway_observers: crosschainkeeper.NewCCTXGatewayObservers(app.CrosschainKeeper),
chains.CCTXGateway_zevm: crosschainkeeper.NewCCTXGatewayZEVM(app.CrosschainKeeper),
}
app.CrosschainKeeper.SetCCTXGateways(cctxGateways)
crosschainkeeper.InitCCTXGateways(app.CrosschainKeeper)

// initialize ibccrosschain keeper and set it to the crosschain keeper
// there is a circular dependency between the two keepers, crosschain keeper must be initialized first
Expand Down
37 changes: 23 additions & 14 deletions x/crosschain/keeper/cctx_gateway_observers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package keeper
import (
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/zeta-chain/zetacore/pkg/chains"
"github.com/zeta-chain/zetacore/x/crosschain/types"
)

Expand Down Expand Up @@ -32,29 +33,37 @@ InitiateOutbound updates the store so observers can use the PendingCCTX query:
*/
func (c CCTXGatewayObservers) InitiateOutbound(
ctx sdk.Context,
cctx *types.CrossChainTx,
config InitiateOutboundConfig,
) (newCCTXStatus types.CctxStatus) {
tmpCtx, commit := ctx.CacheContext()
outboundReceiverChainID := cctx.GetCurrentOutboundParam().ReceiverChainId
outboundReceiverChainID := config.CCTX.GetCurrentOutboundParam().ReceiverChainId
// TODO: does this condition make sense?
noEthereumTxEvent := false
if chains.IsZetaChain(config.CCTX.InboundParams.SenderChainId) {
noEthereumTxEvent = true
}

err := func() error {
err := c.crosschainKeeper.PayGasAndUpdateCctx(
tmpCtx,
outboundReceiverChainID,
cctx,
cctx.InboundParams.Amount,
false,
)
if err != nil {
return err
if config.PayGas {
err := c.crosschainKeeper.PayGasAndUpdateCctx(
tmpCtx,
outboundReceiverChainID,
config.CCTX,
config.CCTX.InboundParams.Amount,
noEthereumTxEvent,
)
if err != nil {
return err
}
}
return c.crosschainKeeper.UpdateNonce(tmpCtx, outboundReceiverChainID, cctx)
return c.crosschainKeeper.UpdateNonce(tmpCtx, outboundReceiverChainID, config.CCTX)
}()
if err != nil {
// do not commit anything here as the CCTX should be aborted
cctx.SetAbort(err.Error())
config.CCTX.SetAbort(err.Error())
return types.CctxStatus_Aborted
}
commit()
cctx.SetPendingOutbound("")
config.CCTX.SetPendingOutbound("")
return types.CctxStatus_PendingOutbound
}
10 changes: 5 additions & 5 deletions x/crosschain/keeper/cctx_gateway_zevm.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@ func NewCCTXGatewayZEVM(crosschainKeeper Keeper) CCTXGatewayZEVM {
}

// InitiateOutbound handles evm deposit and immediately validates pending outbound
func (c CCTXGatewayZEVM) InitiateOutbound(ctx sdk.Context, cctx *types.CrossChainTx) (newCCTXStatus types.CctxStatus) {
func (c CCTXGatewayZEVM) InitiateOutbound(ctx sdk.Context, config InitiateOutboundConfig) (newCCTXStatus types.CctxStatus) {
tmpCtx, commit := ctx.CacheContext()
isContractReverted, err := c.crosschainKeeper.HandleEVMDeposit(tmpCtx, cctx)
isContractReverted, err := c.crosschainKeeper.HandleEVMDeposit(tmpCtx, config.CCTX)

if err != nil && !isContractReverted {
// exceptional case; internal error; should abort CCTX
cctx.SetAbort(err.Error())
config.CCTX.SetAbort(err.Error())
return types.CctxStatus_Aborted
}

cctx.SetPendingOutbound("")
newCCTXStatus = c.crosschainKeeper.ValidateOutboundZEVM(ctx, cctx, err, isContractReverted)
config.CCTX.SetPendingOutbound("")
newCCTXStatus = c.crosschainKeeper.ValidateOutboundZEVM(ctx, config.CCTX, err, isContractReverted)
if newCCTXStatus == types.CctxStatus_OutboundMined {
commit()
}
Expand Down
31 changes: 31 additions & 0 deletions x/crosschain/keeper/cctx_gateways.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package keeper

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/zeta-chain/zetacore/pkg/chains"
"github.com/zeta-chain/zetacore/x/crosschain/types"
)

// CCTXGateway is interface implemented by every gateway. It is one of interfaces used for communication
// between CCTX gateways and crosschain module, and it is called by crosschain module.
type CCTXGateway interface {
// Initiate a new outbound, this tells the CCTXGateway to carry out the action to execute the outbound.
// It is the only entry point to initiate an outbound and it returns new CCTX status after it is completed.
InitiateOutbound(ctx sdk.Context, config InitiateOutboundConfig) (newCCTXStatus types.CctxStatus)
}

var cctxGateways map[chains.CCTXGateway]CCTXGateway

// initializing map of cctx gateways so crosschain module can decide which one to use
// based on chain info of destination chain
func InitCCTXGateways(keeper Keeper) {
cctxGateways = map[chains.CCTXGateway]CCTXGateway{
chains.CCTXGateway_observers: NewCCTXGatewayObservers(keeper),
chains.CCTXGateway_zevm: NewCCTXGatewayZEVM(keeper),
}
}

func ResolveCCTXGateway(c chains.CCTXGateway) (CCTXGateway, bool) {
cctxGateway, ok := cctxGateways[c]
return cctxGateway, ok
}
7 changes: 5 additions & 2 deletions x/crosschain/keeper/cctx_orchestrator_validate_inbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"github.com/zeta-chain/zetacore/x/crosschain/types"
)

func (k Keeper) ValidateInboundObservers(ctx sdk.Context, msg *types.MsgVoteInbound) (*types.CrossChainTx, error) {
func (k Keeper) ValidateInboundObservers(ctx sdk.Context, msg *types.MsgVoteInbound, payGas bool) (*types.CrossChainTx, error) {
tss, tssFound := k.zetaObserverKeeper.GetTSS(ctx)
if !tssFound {
return nil, types.ErrCannotFindTSSKeys
Expand All @@ -17,7 +17,10 @@ func (k Keeper) ValidateInboundObservers(ctx sdk.Context, msg *types.MsgVoteInbo
}
// Initiate outbound, the process function manages the state commit and cctx status change.
// If the process fails, the changes to the evm state are rolled back.
_, err = k.InitiateOutbound(ctx, &cctx)
_, err = k.InitiateOutbound(ctx, InitiateOutboundConfig{
CCTX: &cctx,
PayGas: payGas,
})
if err != nil {
return nil, err
}
Expand Down
67 changes: 29 additions & 38 deletions x/crosschain/keeper/evm_hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package keeper
import (
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"math/big"

Expand Down Expand Up @@ -76,6 +77,18 @@ func (k Keeper) ProcessLogs(
if connectorZEVMAddr == (ethcommon.Address{}) {
return fmt.Errorf("connectorZEVM address is empty")
}

// These cannot be processed without TSS keys, return an error if TSS is not found
tss, found := k.zetaObserverKeeper.GetTSS(ctx)
if !found {
return errorsmod.Wrap(types.ErrCannotFindTSSKeys, "Cannot process logs without TSS keys")
}

// Do not process withdrawal events if inbound is disabled
if !k.zetaObserverKeeper.IsInboundEnabled(ctx) {
return observertypes.ErrInboundDisabled
}

for _, log := range logs {
eventZrc20Withdrawal, errZrc20 := ParseZRC20WithdrawalEvent(*log)
eventZetaSent, errZetaSent := ParseZetaSentEvent(*log, connectorZEVMAddr)
Expand All @@ -90,18 +103,6 @@ func (k Keeper) ProcessLogs(
continue
}

// We have found either eventZrc20Withdrawal or eventZetaSent
// These cannot be processed without TSS keys, return an error if TSS is not found
tss, found := k.zetaObserverKeeper.GetTSS(ctx)
if !found {
return errorsmod.Wrap(types.ErrCannotFindTSSKeys, "Cannot process logs without TSS keys")
}

// Do not process withdrawal events if inbound is disabled
if !k.zetaObserverKeeper.IsInboundEnabled(ctx) {
return observertypes.ErrInboundDisabled
}

// if eventZrc20Withdrawal is not nil we will try to validate it and see if it can be processed
if eventZrc20Withdrawal != nil {
// Check if the contract is a registered ZRC20 contract. If its not a registered ZRC20 contract, we can discard this event as it is not relevant
Expand Down Expand Up @@ -188,22 +189,25 @@ func (k Keeper) ProcessZRC20WithdrawalEvent(
event.Raw.Index,
)

// Create a new cctx with status as pending Inbound, this is created directly from the event without waiting for any observer votes
cctx, err := types.NewCCTX(ctx, *msg, tss.TssPubkey)
cctx, err := k.ValidateInboundObservers(ctx, msg, false)
if err != nil {
return fmt.Errorf("ProcessZRC20WithdrawalEvent: failed to initialize cctx: %s", err.Error())
return err
}
cctx.SetPendingOutbound("ZRC20 withdrawal event setting to pending outbound directly")
// Get gas price and amount

if cctx.CctxStatus.Status == types.CctxStatus_Aborted {
return errors.New("cctx aborted")
}

gasprice, found := k.GetGasPrice(ctx, receiverChain.ChainId)
if !found {
return fmt.Errorf("gasprice not found for %s", receiverChain)
}
cctx.GetCurrentOutboundParam().GasPrice = fmt.Sprintf("%d", gasprice.Prices[gasprice.MedianIndex])
cctx.GetCurrentOutboundParam().Amount = cctx.InboundParams.Amount

EmitZRCWithdrawCreated(ctx, cctx)
return k.ProcessCCTX(ctx, cctx, receiverChain)
EmitZRCWithdrawCreated(ctx, *cctx)

return k.ProcessCCTX(ctx, *cctx, receiverChain)
}

func (k Keeper) ProcessZetaSentEvent(
Expand Down Expand Up @@ -267,26 +271,17 @@ func (k Keeper) ProcessZetaSentEvent(
event.Raw.Index,
)

// create a new cctx with status as pending Inbound,
// this is created directly from the event without waiting for any observer votes
cctx, err := types.NewCCTX(ctx, *msg, tss.TssPubkey)
cctx, err := k.ValidateInboundObservers(ctx, msg, true)
if err != nil {
return fmt.Errorf("ProcessZetaSentEvent: failed to initialize cctx: %s", err.Error())
return err
}
cctx.SetPendingOutbound("ZetaSent event setting to pending outbound directly")

if err := k.PayGasAndUpdateCctx(
ctx,
receiverChain.ChainId,
&cctx,
amount,
true,
); err != nil {
return fmt.Errorf("ProcessWithdrawalEvent: pay gas failed: %s", err.Error())
if cctx.CctxStatus.Status == types.CctxStatus_Aborted {
return errors.New("cctx aborted")
}

EmitZetaWithdrawCreated(ctx, cctx)
return k.ProcessCCTX(ctx, cctx, receiverChain)
EmitZetaWithdrawCreated(ctx, *cctx)
return k.ProcessCCTX(ctx, *cctx, receiverChain)
}

func (k Keeper) ProcessCCTX(ctx sdk.Context, cctx types.CrossChainTx, receiverChain *chains.Chain) error {

Check warning on line 287 in x/crosschain/keeper/evm_hooks.go

View workflow job for this annotation

GitHub Actions / lint

unused-parameter: parameter 'receiverChain' seems to be unused, consider removing or renaming it as _ (revive)
Expand All @@ -295,10 +290,6 @@ func (k Keeper) ProcessCCTX(ctx sdk.Context, cctx types.CrossChainTx, receiverCh
cctx.InboundParams.ObservedHash = inCctxIndex
}

if err := k.UpdateNonce(ctx, receiverChain.ChainId, &cctx); err != nil {
return fmt.Errorf("ProcessWithdrawalEvent: update nonce failed: %s", err.Error())
}

k.SetCctxAndNonceToCctxAndInboundHashToCctx(ctx, cctx)
ctx.Logger().Debug("ProcessCCTX successful \n")
return nil
Expand Down
23 changes: 16 additions & 7 deletions x/crosschain/keeper/initiate_outbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,39 @@ import (
"github.com/zeta-chain/zetacore/x/crosschain/types"
)

// TODO: this is just a tmp solution, tbd if info can be passed to CCTX constructor somehow
// and not initialize CCTX using MsgVoteInbound but for example (InboundParams, OutboundParams)
// then PayGas can be decided based on GasPrice already presend in OutboundParams
// check if msg.Digest can be replaced to calculate index
type InitiateOutboundConfig struct {
CCTX *types.CrossChainTx
PayGas bool
}

// InitiateOutbound initiates the outbound for the CCTX depending on the CCTX gateway.
// It does a conditional dispatch to correct CCTX gateway based on the receiver chain
// which handles the state changes and error handling.
func (k Keeper) InitiateOutbound(ctx sdk.Context, cctx *types.CrossChainTx) (types.CctxStatus, error) {
receiverChainID := cctx.GetCurrentOutboundParam().ReceiverChainId
func (k Keeper) InitiateOutbound(ctx sdk.Context, config InitiateOutboundConfig) (types.CctxStatus, error) {
receiverChainID := config.CCTX.GetCurrentOutboundParam().ReceiverChainId
chainInfo := chains.GetChainFromChainID(receiverChainID)
if chainInfo == nil {
return cctx.CctxStatus.Status, cosmoserrors.Wrap(
return config.CCTX.CctxStatus.Status, cosmoserrors.Wrap(
types.ErrInitiatitingOutbound,
fmt.Sprintf(
"chain info not found for %d", receiverChainID,
),
)
}

cctxGateway, ok := k.cctxGateways[chainInfo.CctxGateway]
if !ok {
return cctx.CctxStatus.Status, cosmoserrors.Wrap(
cctxGateway, found := ResolveCCTXGateway(chainInfo.CctxGateway)
if !found {
return config.CCTX.CctxStatus.Status, cosmoserrors.Wrap(
types.ErrInitiatitingOutbound,
fmt.Sprintf(
"CCTXGateway not defined for receiver chain %d", receiverChainID,
),
)
}

return cctxGateway.InitiateOutbound(ctx, cctx), nil
return cctxGateway.InitiateOutbound(ctx, config), nil
}
Loading

0 comments on commit 36b38f8

Please sign in to comment.