Skip to content

Commit

Permalink
initialize revert
Browse files Browse the repository at this point in the history
  • Loading branch information
lumtis committed Aug 11, 2024
1 parent 17e084e commit 4a977fb
Show file tree
Hide file tree
Showing 24 changed files with 1,199 additions and 214 deletions.
12 changes: 12 additions & 0 deletions docs/openapi/openapi.swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57125,6 +57125,8 @@ definitions:
$ref: '#/definitions/crosschainOutboundParams'
protocol_contract_version:
$ref: '#/definitions/crosschainProtocolContractVersion'
revert_options:
$ref: '#/definitions/crosschainRevertOptions'
crosschainGasPrice:
type: object
properties:
Expand Down Expand Up @@ -57550,6 +57552,16 @@ definitions:
type: object
$ref: '#/definitions/crosschainConversion'
title: conversion in azeta per token
crosschainRevertOptions:
type: object
properties:
revert_address:
type: string
call_on_revert:
type: boolean
abort_address:
type: string
title: RevertOptions represents the options for reverting a cctx
crosschainTxFinalizationStatus:
type: string
enum:
Expand Down
1 change: 1 addition & 0 deletions docs/spec/crosschain/messages.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ message MsgVoteInbound {
string asset = 14;
uint64 event_index = 15;
ProtocolContractVersion protocol_contract_version = 16;
RevertOptions revert_options = 17;
}
```

Expand Down
8 changes: 8 additions & 0 deletions proto/zetachain/zetacore/crosschain/cross_chain_tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@ enum ProtocolContractVersion {
V2 = 1;
}

// RevertOptions represents the options for reverting a cctx
message RevertOptions {
string revert_address = 1;
bool call_on_revert = 2;
string abort_address = 3;
}

message CrossChainTx {
string creator = 1;
string index = 2;
Expand All @@ -112,4 +119,5 @@ message CrossChainTx {
InboundParams inbound_params = 9;
repeated OutboundParams outbound_params = 10;
ProtocolContractVersion protocol_contract_version = 11;
RevertOptions revert_options = 12 [ (gogoproto.nullable) = false ];
}
3 changes: 3 additions & 0 deletions proto/zetachain/zetacore/crosschain/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@ message MsgVoteInbound {

// protocol contract version to use for the cctx workflow
ProtocolContractVersion protocol_contract_version = 16;

// revert options provided by the sender
RevertOptions revert_options = 17 [ (gogoproto.nullable) = false ];
}

message MsgVoteInboundResponse {}
Expand Down
41 changes: 41 additions & 0 deletions typescript/zetachain/zetacore/crosschain/cross_chain_tx_pb.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,42 @@ export declare class Status extends Message<Status> {
static equals(a: Status | PlainMessage<Status> | undefined, b: Status | PlainMessage<Status> | undefined): boolean;
}

/**
* RevertOptions represents the options for reverting a cctx
*
* @generated from message zetachain.zetacore.crosschain.RevertOptions
*/
export declare class RevertOptions extends Message<RevertOptions> {
/**
* @generated from field: string revert_address = 1;
*/
revertAddress: string;

/**
* @generated from field: bool call_on_revert = 2;
*/
callOnRevert: boolean;

/**
* @generated from field: string abort_address = 3;
*/
abortAddress: string;

constructor(data?: PartialMessage<RevertOptions>);

static readonly runtime: typeof proto3;
static readonly typeName = "zetachain.zetacore.crosschain.RevertOptions";
static readonly fields: FieldList;

static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): RevertOptions;

static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): RevertOptions;

static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): RevertOptions;

static equals(a: RevertOptions | PlainMessage<RevertOptions> | undefined, b: RevertOptions | PlainMessage<RevertOptions> | undefined): boolean;
}

/**
* @generated from message zetachain.zetacore.crosschain.CrossChainTx
*/
Expand Down Expand Up @@ -394,6 +430,11 @@ export declare class CrossChainTx extends Message<CrossChainTx> {
*/
protocolContractVersion: ProtocolContractVersion;

/**
* @generated from field: zetachain.zetacore.crosschain.RevertOptions revert_options = 12;
*/
revertOptions?: RevertOptions;

constructor(data?: PartialMessage<CrossChainTx>);

static readonly runtime: typeof proto3;
Expand Down
9 changes: 8 additions & 1 deletion typescript/zetachain/zetacore/crosschain/tx_pb.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Message, proto3 } from "@bufbuild/protobuf";
import type { CoinType } from "../pkg/coin/coin_pb.js";
import type { Proof } from "../pkg/proofs/proofs_pb.js";
import type { ReceiveStatus } from "../pkg/chains/chains_pb.js";
import type { ProtocolContractVersion } from "./cross_chain_tx_pb.js";
import type { ProtocolContractVersion, RevertOptions } from "./cross_chain_tx_pb.js";
import type { RateLimiterFlags } from "./rate_limiter_flags_pb.js";

/**
Expand Down Expand Up @@ -649,6 +649,13 @@ export declare class MsgVoteInbound extends Message<MsgVoteInbound> {
*/
protocolContractVersion: ProtocolContractVersion;

/**
* revert options provided by the sender
*
* @generated from field: zetachain.zetacore.crosschain.RevertOptions revert_options = 17;
*/
revertOptions?: RevertOptions;

constructor(data?: PartialMessage<MsgVoteInbound>);

static readonly runtime: typeof proto3;
Expand Down
7 changes: 4 additions & 3 deletions x/crosschain/keeper/cctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,15 @@ func (k Keeper) SetCctxAndNonceToCctxAndInboundHashToCctx(ctx sdk.Context, cctx
}
}

// SetCrossChainTx set a specific send in the store from its index
// SetCrossChainTx set a specific cctx in the store from its index
func (k Keeper) SetCrossChainTx(ctx sdk.Context, cctx types.CrossChainTx) {
p := types.KeyPrefix(fmt.Sprintf("%s", types.CCTXKey))
store := prefix.NewStore(ctx.KVStore(k.storeKey), p)
b := k.cdc.MustMarshal(&cctx)
store.Set(types.KeyPrefix(cctx.Index), b)
}

// GetCrossChainTx returns a send from its index
// GetCrossChainTx returns a cctx from its index
func (k Keeper) GetCrossChainTx(ctx sdk.Context, index string) (val types.CrossChainTx, found bool) {
p := types.KeyPrefix(fmt.Sprintf("%s", types.CCTXKey))
store := prefix.NewStore(ctx.KVStore(k.storeKey), p)
Expand All @@ -76,6 +76,7 @@ func (k Keeper) GetCrossChainTx(ctx sdk.Context, index string) (val types.CrossC
return val, true
}

// GetAllCrossChainTx returns all cctxs
func (k Keeper) GetAllCrossChainTx(ctx sdk.Context) (list []types.CrossChainTx) {
p := types.KeyPrefix(fmt.Sprintf("%s", types.CCTXKey))
store := prefix.NewStore(ctx.KVStore(k.storeKey), p)
Expand All @@ -93,7 +94,7 @@ func (k Keeper) GetAllCrossChainTx(ctx sdk.Context) (list []types.CrossChainTx)
return list
}

// RemoveCrossChainTx removes a send from the store
// RemoveCrossChainTx removes a cctx from the store
func (k Keeper) RemoveCrossChainTx(ctx sdk.Context, index string) {
p := types.KeyPrefix(fmt.Sprintf("%s", types.CCTXKey))
store := prefix.NewStore(ctx.KVStore(k.storeKey), p)
Expand Down
81 changes: 64 additions & 17 deletions x/crosschain/keeper/cctx_orchestrator_validate_outbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func (k Keeper) ValidateOutboundZEVM(
if depositErr != nil && isContractReverted {
tmpCtxRevert, commitRevert := ctx.CacheContext()
// contract call reverted; should refund via a revert tx
err := k.validateFailedOutbound(
err := k.processFailedOutboundonExternalChain(
tmpCtxRevert,
cctx,
types.CctxStatus_PendingOutbound,
Expand All @@ -59,7 +59,7 @@ func (k Keeper) ValidateOutboundZEVM(
commitRevert()
return types.CctxStatus_PendingRevert
}
k.validateSuccessfulOutbound(ctx, cctx, "", false)
k.processSuccessfulOutbound(ctx, cctx, "", false)
return types.CctxStatus_OutboundMined
}

Expand All @@ -75,9 +75,9 @@ func (k Keeper) ValidateOutboundObservers(
err := func() error {
switch ballotStatus {
case observertypes.BallotStatus_BallotFinalized_SuccessObservation:
k.validateSuccessfulOutbound(tmpCtx, cctx, valueReceived, true)
k.processSuccessfulOutbound(tmpCtx, cctx, valueReceived, true)
case observertypes.BallotStatus_BallotFinalized_FailureObservation:
err := k.validateFailedOutboundObservers(tmpCtx, cctx, valueReceived)
err := k.processFailedOutboundObservers(tmpCtx, cctx, valueReceived)
if err != nil {
return err
}
Expand All @@ -95,7 +95,7 @@ func (k Keeper) ValidateOutboundObservers(
return nil
}

// validateFailedOutboundObservers processes a failed outbound transaction for observers. It does the following things in one function:
// processFailedOutboundObservers processes a failed outbound transaction for observers. It does the following things in one function:
//
// 1. For Admin Tx or a withdrawal from Zeta chain, it aborts the CCTX
//
Expand All @@ -109,14 +109,18 @@ func (k Keeper) ValidateOutboundObservers(
//
// This function sets CCTX status , in cases where the outbound tx is successful, but tx itself fails
// This is done because SaveSuccessfulOutbound does not set the cctx status
// For cases where the outbound tx is unsuccessful, the cctx status is automatically set to Aborted in the validateFailedOutboundObservers function, so we can just return and error to trigger that
func (k Keeper) validateFailedOutboundObservers(ctx sdk.Context, cctx *types.CrossChainTx, valueReceived string) error {
// For cases where the outbound tx is unsuccessful, the cctx status is automatically set to Aborted in the processFailedOutboundObservers function, so we can just return and error to trigger that
func (k Keeper) processFailedOutboundObservers(ctx sdk.Context, cctx *types.CrossChainTx, valueReceived string) error {
oldStatus := cctx.CctxStatus.Status
// The following logic is used to handler the mentioned conditions separately. The reason being
// All admin tx is created using a policy message, there is no associated inbound tx, therefore we do not need any revert logic
// For transactions which originated from ZEVM, we can process the outbound in the same block as there is no TSS signing required for the revert
// For all other transactions we need to create a revert tx and set the status to pending revert

if cctx.ProtocolContractVersion == types.ProtocolContractVersion_V2 {
return processFailedOutboundV2(ctx, cctx)
}

if cctx.InboundParams.CoinType == coin.CoinType_Cmd {
// if the cctx is of coin type cmd or the sender chain is zeta chain, then we do not revert, the cctx is aborted
cctx.GetCurrentOutboundParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed
Expand All @@ -126,7 +130,7 @@ func (k Keeper) validateFailedOutboundObservers(ctx sdk.Context, cctx *types.Cro
// Try revert if the coin-type is ZETA
case coin.CoinType_Zeta:
{
err := k.validateFailedOutboundObserversForZEVM(ctx, cctx)
err := k.processFailedZETAOutboundOnZEVM(ctx, cctx)
if err != nil {
return cosmoserrors.Wrap(err, "validateFailedOutboundObserversForZEVMTx")
}
Expand All @@ -139,18 +143,18 @@ func (k Keeper) validateFailedOutboundObservers(ctx sdk.Context, cctx *types.Cro
}
}
} else {
err := k.validateFailedOutbound(ctx, cctx, oldStatus, "Outbound failed, start revert", cctx.GetCurrentOutboundParam().Amount)
err := k.processFailedOutboundonExternalChain(ctx, cctx, oldStatus, "Outbound failed, start revert", cctx.GetCurrentOutboundParam().Amount)
if err != nil {
return cosmoserrors.Wrap(err, "validateFailedOutbound")
return cosmoserrors.Wrap(err, "processFailedOutboundonExternalChain")
}
}
newStatus := cctx.CctxStatus.Status.String()
EmitOutboundFailure(ctx, valueReceived, oldStatus.String(), newStatus, cctx.Index)
return nil
}

// validateFailedOutbound processes the failed outbound transaction
func (k Keeper) validateFailedOutbound(
// processFailedOutboundonExternalChain processes the failed outbound transaction where the receiver is an external chain.
func (k Keeper) processFailedOutboundonExternalChain(
ctx sdk.Context,
cctx *types.CrossChainTx,
oldStatus types.CctxStatus,
Expand Down Expand Up @@ -201,7 +205,7 @@ func (k Keeper) validateFailedOutbound(
return nil
}

// validateSuccessfulOutbound processes a successful outbound transaction. It does the following things in one function:
// processSuccessfulOutbound processes a successful outbound transaction. It does the following things in one function:
//
// 1. Change the status of the CCTX from
// - PendingRevert to Reverted
Expand All @@ -213,8 +217,8 @@ func (k Keeper) validateFailedOutbound(
//
// This function sets CCTX status, in cases where the outbound tx is successful, but tx itself fails
// This is done because SaveSuccessfulOutbound does not set the cctx status
// For cases where the outbound tx is unsuccessful, the cctx status is automatically set to Aborted in the validateFailedOutboundObservers function, so we can just return and error to trigger that
func (k Keeper) validateSuccessfulOutbound(
// For cases where the outbound tx is unsuccessful, the cctx status is automatically set to Aborted in the processFailedOutboundObservers function, so we can just return and error to trigger that
func (k Keeper) processSuccessfulOutbound(
ctx sdk.Context,
cctx *types.CrossChainTx,
valueReceived string,
Expand All @@ -236,8 +240,8 @@ func (k Keeper) validateSuccessfulOutbound(
}
}

// validateFailedOutboundObserversForZEVM processes the failed outbound transaction for ZEVM
func (k Keeper) validateFailedOutboundObserversForZEVM(ctx sdk.Context, cctx *types.CrossChainTx) error {
// processFailedZETAOutboundOnZEVM processes a failed ZETA outbound on ZEVM
func (k Keeper) processFailedZETAOutboundOnZEVM(ctx sdk.Context, cctx *types.CrossChainTx) error {
indexBytes, err := cctx.GetCCTXIndexBytes()
if err != nil {
// Return err to save the failed outbound and set to aborted
Expand Down Expand Up @@ -300,3 +304,46 @@ func (k Keeper) validateFailedOutboundObserversForZEVM(ctx sdk.Context, cctx *ty
cctx.GetCurrentOutboundParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed
return nil
}

// processFailedOutboundV2 processes a failed outbound transaction for protocol version 2
// for revert, in V2 we have some assumption simplifying the logic
// - sender chain is always ZetaChain
// - all coin type use the same workflow
// TODO: consolidate logic with above function
// https://github.com/zeta-chain/node/issues/2627
func processFailedOutboundV2(ctx sdk.Context, cctx *types.CrossChainTx) error {
switch cctx.CctxStatus.Status {
case types.CctxStatus_PendingOutbound:

// add revert outbound
err := cctx.AddRevertOutbound(fungiblekeeper.ZEVMGasLimitDepositAndCall.Uint64())
if err != nil {
// Return err to save the failed outbound ad set to aborted
return fmt.Errorf("failed AddRevertOutbound: %s", err.Error())
}

// update status
cctx.SetPendingRevert("Outbound failed, trying revert")

// process the revert on ZEVM
// TODO: add ProcessV2RevertDeposit call
// https://github.com/zeta-chain/node/issues/2660

// tx is reverted
cctx.SetReverted("Outbound failed, revert executed")

// add event for tendermint transaction hash format
if len(ctx.TxBytes()) > 0 {
hash := tmbytes.HexBytes(tmtypes.Tx(ctx.TxBytes()).Hash())
ethTxHash := ethcommon.BytesToHash(hash)
cctx.GetCurrentOutboundParam().Hash = ethTxHash.String()
// #nosec G115 always positive
cctx.GetCurrentOutboundParam().ObservedExternalHeight = uint64(ctx.BlockHeight())
}
cctx.GetCurrentOutboundParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed
case types.CctxStatus_PendingRevert:
cctx.GetCurrentOutboundParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed
cctx.SetAbort("Outbound failed: revert failed; abort TX")
}
return nil
}
4 changes: 4 additions & 0 deletions x/crosschain/keeper/v2_zevm_inbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ func (k Keeper) parseGatewayCallEvent(
// currently inbound data is represented with a MsgVoteInbound message
// TODO: replace with a more appropriate object
// https://github.com/zeta-chain/node/issues/2658
// TODO: include revert options
// https://github.com/zeta-chain/node/issues/2660
func (k Keeper) newWithdrawalInbound(
ctx sdk.Context,
from ethcommon.Address,
Expand Down Expand Up @@ -205,6 +207,8 @@ func (k Keeper) newWithdrawalInbound(
// currently inbound data is represented with a MsgVoteInbound message
// TODO: replace with a more appropriate object
// https://github.com/zeta-chain/node/issues/2658
// TODO: include revert options
// https://github.com/zeta-chain/node/issues/2660
func (k Keeper) newCallInbound(
ctx sdk.Context,
from ethcommon.Address,
Expand Down
Loading

0 comments on commit 4a977fb

Please sign in to comment.