Skip to content

Commit

Permalink
refactor: cctx validate inbound (#2340)
Browse files Browse the repository at this point in the history
  • Loading branch information
skosito authored Jun 21, 2024
1 parent ca9b90f commit e6287e2
Show file tree
Hide file tree
Showing 21 changed files with 229 additions and 228 deletions.
9 changes: 0 additions & 9 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,14 +597,6 @@ 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)

// 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
3 changes: 2 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@
* [2269](https://github.com/zeta-chain/node/pull/2269) - refactor MsgUpdateCrosschainFlags into MsgEnableCCTX, MsgDisableCCTX and MsgUpdateGasPriceIncreaseFlags
* [2306](https://github.com/zeta-chain/node/pull/2306) - refactor zetaclient outbound transaction signing logic
* [2296](https://github.com/zeta-chain/node/pull/2296) - move `testdata` package to `testutil` to organize test-related utilities
* [2344](https://github.com/zeta-chain/node/pull/2344) - group common data of EVM/Bitcoin signer and observer using base structs
* [2317](https://github.com/zeta-chain/node/pull/2317) - add ValidateOutbound method for cctx orchestrator
* [2340](https://github.com/zeta-chain/node/pull/2340) - add ValidateInbound method for cctx orchestrator
* [2344](https://github.com/zeta-chain/node/pull/2344) - group common data of EVM/Bitcoin signer and observer using base structs

### Tests

Expand Down
8 changes: 0 additions & 8 deletions testutil/keeper/crosschain.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,16 +174,8 @@ func CrosschainKeeperWithMocks(
lightclientKeeper,
)

cctxGateways := map[chains.CCTXGateway]keeper.CCTXGateway{
chains.CCTXGateway_observers: keeper.NewCCTXGatewayObservers(*k),
chains.CCTXGateway_zevm: keeper.NewCCTXGatewayZEVM(*k),
}

k.SetCCTXGateways(cctxGateways)

// 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

var ibcCrosschainKeeperTmp types.IBCCrosschainKeeper = initIBCCrosschainKeeper(
cdc,
db,
Expand Down
54 changes: 37 additions & 17 deletions x/crosschain/keeper/cctx_gateway_observers.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package keeper

import (
"fmt"

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,28 +35,45 @@ InitiateOutbound updates the store so observers can use the PendingCCTX query:
*/
func (c CCTXGatewayObservers) InitiateOutbound(
ctx sdk.Context,
cctx *types.CrossChainTx,
) (newCCTXStatus types.CctxStatus) {
config InitiateOutboundConfig,
) (newCCTXStatus types.CctxStatus, err error) {
tmpCtx, commit := ctx.CacheContext()
outboundReceiverChainID := cctx.GetCurrentOutboundParam().ReceiverChainId
err := func() error {
err := c.crosschainKeeper.PayGasAndUpdateCctx(
tmpCtx,
outboundReceiverChainID,
cctx,
cctx.InboundParams.Amount,
false,
)
if err != nil {
return err
outboundReceiverChainID := config.CCTX.GetCurrentOutboundParam().ReceiverChainId
// TODO (https://github.com/zeta-chain/node/issues/1010): workaround for this bug
noEthereumTxEvent := false
if chains.IsZetaChain(config.CCTX.InboundParams.SenderChainId) {
noEthereumTxEvent = true
}

err = func() error {
// If ShouldPayGas flag is set during ValidateInbound PayGasAndUpdateCctx should be called
// which will set GasPrice and Amount. Otherwise, use median gas price and InboundParams amount.
if config.ShouldPayGas {
err := c.crosschainKeeper.PayGasAndUpdateCctx(
tmpCtx,
outboundReceiverChainID,
config.CCTX,
config.CCTX.InboundParams.Amount,
noEthereumTxEvent,
)
if err != nil {
return err
}
} else {
gasPrice, found := c.crosschainKeeper.GetMedianGasPriceInUint(ctx, config.CCTX.GetCurrentOutboundParam().ReceiverChainId)
if !found {
return fmt.Errorf("gasprice not found for %d", config.CCTX.GetCurrentOutboundParam().ReceiverChainId)
}
config.CCTX.GetCurrentOutboundParam().GasPrice = gasPrice.String()
config.CCTX.GetCurrentOutboundParam().Amount = config.CCTX.InboundParams.Amount
}
return c.crosschainKeeper.UpdateNonce(tmpCtx, outboundReceiverChainID, cctx)
return c.crosschainKeeper.SetObserverOutboundInfo(tmpCtx, outboundReceiverChainID, config.CCTX)
}()
if err != nil {
// do not commit anything here as the CCTX should be aborted
cctx.SetAbort(err.Error())
return types.CctxStatus_Aborted
config.CCTX.SetAbort(err.Error())
return types.CctxStatus_Aborted, err
}
commit()
return types.CctxStatus_PendingOutbound
return types.CctxStatus_PendingOutbound, nil
}
15 changes: 9 additions & 6 deletions x/crosschain/keeper/cctx_gateway_zevm.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,23 @@ 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, err error) {
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())
return types.CctxStatus_Aborted
config.CCTX.SetAbort(err.Error())
return types.CctxStatus_Aborted, err
}

newCCTXStatus = c.crosschainKeeper.ValidateOutboundZEVM(ctx, cctx, err, isContractReverted)
newCCTXStatus = c.crosschainKeeper.ValidateOutboundZEVM(ctx, config.CCTX, err, isContractReverted)
if newCCTXStatus == types.CctxStatus_OutboundMined {
commit()
}

return newCCTXStatus
return newCCTXStatus, nil
}
29 changes: 29 additions & 0 deletions x/crosschain/keeper/cctx_gateways.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
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, err error)
}

var cctxGateways map[chains.CCTXGateway]CCTXGateway

// ResolveCCTXGateway respolves cctx gateway implementation based on provided cctx gateway
func ResolveCCTXGateway(c chains.CCTXGateway, keeper Keeper) (CCTXGateway, bool) {
cctxGateways = map[chains.CCTXGateway]CCTXGateway{
chains.CCTXGateway_observers: NewCCTXGatewayObservers(keeper),
chains.CCTXGateway_zevm: NewCCTXGatewayZEVM(keeper),
}

cctxGateway, ok := cctxGateways[c]
return cctxGateway, ok
}
50 changes: 50 additions & 0 deletions x/crosschain/keeper/cctx_orchestrator_validate_inbound.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package keeper

import (
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/zeta-chain/zetacore/x/crosschain/types"
observertypes "github.com/zeta-chain/zetacore/x/observer/types"
)

// ValidateInbound is the only entry-point to create new CCTX (eg. when observers voting is done or new inbound event is detected).
// It creates new CCTX object and calls InitiateOutbound method.
func (k Keeper) ValidateInbound(
ctx sdk.Context,
msg *types.MsgVoteInbound,
shouldPayGas bool,
) (*types.CrossChainTx, error) {
tss, tssFound := k.zetaObserverKeeper.GetTSS(ctx)
if !tssFound {
return nil, types.ErrCannotFindTSSKeys
}

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

// create a new CCTX from the inbound message. The status of the new CCTX is set to PendingInbound.
cctx, err := types.NewCCTX(ctx, *msg, tss.TssPubkey)
if err != nil {
return nil, err
}

// 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, InitiateOutboundConfig{
CCTX: &cctx,
ShouldPayGas: shouldPayGas,
})
if err != nil {
return nil, err
}

inCctxIndex, ok := ctx.Value(InCCTXIndexKey).(string)
if ok {
cctx.InboundParams.ObservedHash = inCctxIndex
}
k.SetCctxAndNonceToCctxAndInboundHashToCctx(ctx, cctx)

return &cctx, nil
}
2 changes: 1 addition & 1 deletion x/crosschain/keeper/cctx_orchestrator_validate_outbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ func (k Keeper) validateFailedOutbound(
if err != nil {
return err
}
err = k.UpdateNonce(ctx, cctx.InboundParams.SenderChainId, cctx)
err = k.SetObserverOutboundInfo(ctx, cctx.InboundParams.SenderChainId, cctx)
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions x/crosschain/keeper/cctx_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ import (
zetaObserverTypes "github.com/zeta-chain/zetacore/x/observer/types"
)

// UpdateNonce sets the CCTX outbound nonce to the next nonce, and updates the nonce of blockchain state.
// SetObserverOutboundInfo sets the CCTX outbound nonce to the next available nonce for the TSS address, and updates the nonce of blockchain state.
// It also updates the PendingNonces that is used to track the unfulfilled outbound txs.
func (k Keeper) UpdateNonce(ctx sdk.Context, receiveChainID int64, cctx *types.CrossChainTx) error {
func (k Keeper) SetObserverOutboundInfo(ctx sdk.Context, receiveChainID int64, cctx *types.CrossChainTx) error {
chain := k.GetObserverKeeper().GetSupportedChainFromChainID(ctx, receiveChainID)
if chain == nil {
return zetaObserverTypes.ErrSupportedChains
Expand Down
14 changes: 7 additions & 7 deletions x/crosschain/keeper/cctx_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ func Test_IsPending(t *testing.T) {
}
}

func TestKeeper_UpdateNonce(t *testing.T) {
func TestKeeper_SetObserverOutboundInfo(t *testing.T) {
t.Run("should error if supported chain is nil", func(t *testing.T) {
k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{
UseObserverMock: true,
Expand All @@ -236,7 +236,7 @@ func TestKeeper_UpdateNonce(t *testing.T) {
// mock failed GetSupportedChainFromChainID
keepertest.MockFailedGetSupportedChainFromChainID(observerMock, nil)

err := k.UpdateNonce(ctx, 5, nil)
err := k.SetObserverOutboundInfo(ctx, 5, nil)
require.Error(t, err)
})

Expand All @@ -262,7 +262,7 @@ func TestKeeper_UpdateNonce(t *testing.T) {
{Amount: sdkmath.NewUint(1)},
},
}
err := k.UpdateNonce(ctx, 5, &cctx)
err := k.SetObserverOutboundInfo(ctx, 5, &cctx)
require.Error(t, err)
})

Expand Down Expand Up @@ -291,7 +291,7 @@ func TestKeeper_UpdateNonce(t *testing.T) {
{Amount: sdkmath.NewUint(1)},
},
}
err := k.UpdateNonce(ctx, 5, &cctx)
err := k.SetObserverOutboundInfo(ctx, 5, &cctx)
require.Error(t, err)
require.Equal(t, uint64(100), cctx.GetCurrentOutboundParam().TssNonce)
})
Expand Down Expand Up @@ -324,7 +324,7 @@ func TestKeeper_UpdateNonce(t *testing.T) {
{Amount: sdkmath.NewUint(1)},
},
}
err := k.UpdateNonce(ctx, 5, &cctx)
err := k.SetObserverOutboundInfo(ctx, 5, &cctx)
require.Error(t, err)
})

Expand Down Expand Up @@ -358,7 +358,7 @@ func TestKeeper_UpdateNonce(t *testing.T) {
{Amount: sdkmath.NewUint(1)},
},
}
err := k.UpdateNonce(ctx, 5, &cctx)
err := k.SetObserverOutboundInfo(ctx, 5, &cctx)
require.Error(t, err)
})

Expand Down Expand Up @@ -395,7 +395,7 @@ func TestKeeper_UpdateNonce(t *testing.T) {
{Amount: sdkmath.NewUint(1)},
},
}
err := k.UpdateNonce(ctx, 5, &cctx)
err := k.SetObserverOutboundInfo(ctx, 5, &cctx)
require.NoError(t, err)
})
}
Expand Down
4 changes: 3 additions & 1 deletion x/crosschain/keeper/evm_deposit.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types"
)

const InCCTXIndexKey = "inCctxIndex"

// HandleEVMDeposit handles a deposit from an inbound tx
// returns (isContractReverted, err)
// (true, non-nil) means CallEVM() reverted
Expand Down Expand Up @@ -102,7 +104,7 @@ func (k Keeper) HandleEVMDeposit(ctx sdk.Context, cctx *types.CrossChainTx) (boo
if !evmTxResponse.Failed() && contractCall {
logs := evmtypes.LogsToEthereum(evmTxResponse.Logs)
if len(logs) > 0 {
ctx = ctx.WithValue("inCctxIndex", cctx.Index)
ctx = ctx.WithValue(InCCTXIndexKey, cctx.Index)
txOrigin := cctx.InboundParams.TxOrigin
if txOrigin == "" {
txOrigin = inboundSender
Expand Down
Loading

0 comments on commit e6287e2

Please sign in to comment.