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

fix: update pending nonces when aborting a cctx through MsgAbortStuckCCTX #3230

Merged
merged 14 commits into from
Dec 9, 2024
Merged
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

* [3206](https://github.com/zeta-chain/node/pull/3206) - skip Solana unsupported transaction version to not block inbound observation
* [3184](https://github.com/zeta-chain/node/pull/3184) - zetaclient should not retry if inbound vote message validation fails
* [3230](https://github.com/zeta-chain/node/pull/3230) - update pending nonces when aborting a cctx through MsgAbortStuckCCTX
* [3225](https://github.com/zeta-chain/node/pull/3225) - use separate database file names for btc signet and testnet4
* [3253](https://github.com/zeta-chain/node/pull/3253) - fix solana inbound version 0 queries and move tss keysign prior to relayer key checking

Expand Down
10 changes: 2 additions & 8 deletions e2e/utils/zetacore.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func WaitCctxsMinedByInboundHash(
allFound := true
for j, cctx := range res.CrossChainTxs {
cctx := cctx
if !IsTerminalStatus(cctx.CctxStatus.Status) {
if !cctx.CctxStatus.Status.IsTerminal() {
// prevent spamming logs
if i%20 == 0 {
logger.Info(
Expand Down Expand Up @@ -170,7 +170,7 @@ func WaitCCTXMinedByIndex(
}

cctx := res.CrossChainTx
if !IsTerminalStatus(cctx.CctxStatus.Status) {
if !cctx.CctxStatus.Status.IsTerminal() {
// prevent spamming logs
if i%20 == 0 {
logger.Info(
Expand Down Expand Up @@ -299,12 +299,6 @@ func WaitCctxByInboundHash(
}
}

func IsTerminalStatus(status crosschaintypes.CctxStatus) bool {
return status == crosschaintypes.CctxStatus_OutboundMined ||
status == crosschaintypes.CctxStatus_Aborted ||
status == crosschaintypes.CctxStatus_Reverted
}

// WaitForBlockHeight waits until the block height reaches the given height
func WaitForBlockHeight(
ctx context.Context,
Expand Down
7 changes: 5 additions & 2 deletions x/crosschain/genesis.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package crosschain

import (
sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/zeta-chain/node/x/crosschain/keeper"
Expand All @@ -10,7 +11,9 @@
// InitGenesis initializes the crosschain module's state from a provided genesis
// state.
func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) {
k.SetZetaAccounting(ctx, genState.ZetaAccounting)
// Always set the zeta accounting to zero at genesis.
// ZetaAccounting value is build by iterating through all the cctxs and adding the amount to the zeta accounting.
k.SetZetaAccounting(ctx, types.ZetaAccounting{AbortedZetaAmount: sdkmath.ZeroUint()})
ws4charlie marked this conversation as resolved.
Show resolved Hide resolved
// Set all the outbound tracker
for _, elem := range genState.OutboundTrackerList {
k.SetOutboundTracker(ctx, elem)
Expand Down Expand Up @@ -47,7 +50,7 @@
if found {
for _, elem := range genState.CrossChainTxs {
if elem != nil {
k.SetCctxAndNonceToCctxAndInboundHashToCctx(ctx, *elem, tss.TssPubkey)
k.SaveCCTXUpdate(ctx, *elem, tss.TssPubkey)

Check warning on line 53 in x/crosschain/genesis.go

View check run for this annotation

Codecov / codecov/patch

x/crosschain/genesis.go#L53

Added line #L53 was not covered by tests
}
}
}
Expand Down
78 changes: 58 additions & 20 deletions x/crosschain/keeper/cctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,41 @@ import (
observerTypes "github.com/zeta-chain/node/x/observer/types"
)

// SetCctxAndNonceToCctxAndInboundHashToCctx does the following things in one function:
// 1. set the cctx in the store
// 2. set the mapping inboundHash -> cctxIndex , one inboundHash can be connected to multiple cctxindex
// 3. set the mapping nonce => cctx
// SaveCCTXUpdate does the following things in one function:

// 1. Set the Nonce to Cctx mapping
// A new mapping between a nonce and a cctx index should be created only when we add a new outbound to an existing cctx.
// When adding a new outbound , the only two conditions are
// - The cctx is in CctxStatus_PendingOutbound , which means the first outbound has been added, and we need to set the nonce for that
// - The cctx is in CctxStatus_PendingRevert , which means the second outbound has been added, and we need to set the nonce for that

// 2. Set the cctx in the store

// 3. Update the mapping inboundHash -> cctxIndex
// A new value is added to the mapping when a single inbound hash is connected to multiple cctx indexes
// If the inbound hash to cctx mapping does not exist, a new mapping is created and the cctx index is added to the list of cctx indexes

// 4. update the zeta accounting
func (k Keeper) SetCctxAndNonceToCctxAndInboundHashToCctx(
// Zeta-accounting is updated aborted cctxs of cointtype zeta.When a cctx is aborted it means that `GetAbortedAmount`
//of zeta is locked and cannot be used.

func (k Keeper) SaveCCTXUpdate(
ctx sdk.Context,
cctx types.CrossChainTx,
tssPubkey string,
) {
// set mapping nonce => cctxIndex
if cctx.CctxStatus.Status == types.CctxStatus_PendingOutbound ||
cctx.CctxStatus.Status == types.CctxStatus_PendingRevert {
k.GetObserverKeeper().SetNonceToCctx(ctx, observerTypes.NonceToCctx{
ChainId: cctx.GetCurrentOutboundParam().ReceiverChainId,
// #nosec G115 always in range
Nonce: int64(cctx.GetCurrentOutboundParam().TssNonce),
CctxIndex: cctx.Index,
Tss: tssPubkey,
})
}

k.setNonceToCCTX(ctx, cctx, tssPubkey)
k.SetCrossChainTx(ctx, cctx)
// set mapping inboundHash -> cctxIndex
k.updateInboundHashToCCTX(ctx, cctx)
k.updateZetaAccounting(ctx, cctx)
}

// updateInboundHashToCCTX updates the mapping between an inbound hash and a cctx index.
// A new index is added to the list of cctx indexes if it is not already present
func (k Keeper) updateInboundHashToCCTX(
ctx sdk.Context,
cctx types.CrossChainTx,
) {
in, _ := k.GetInboundHashToCctx(ctx, cctx.InboundParams.ObservedHash)
in.InboundHash = cctx.InboundParams.ObservedHash
found := false
Expand All @@ -48,15 +59,42 @@ func (k Keeper) SetCctxAndNonceToCctxAndInboundHashToCctx(
in.CctxIndex = append(in.CctxIndex, cctx.Index)
}
k.SetInboundHashToCctx(ctx, in)
}

if cctx.CctxStatus.Status == types.CctxStatus_Aborted && cctx.InboundParams.CoinType == coin.CoinType_Zeta {
// updateZetaAccounting updates the zeta accounting with the amount of zeta that was locked in an aborted cctx
func (k Keeper) updateZetaAccounting(
lumtis marked this conversation as resolved.
Show resolved Hide resolved
ctx sdk.Context,
cctx types.CrossChainTx,
) {
if cctx.CctxStatus.Status == types.CctxStatus_Aborted &&
cctx.InboundParams.CoinType == coin.CoinType_Zeta &&
cctx.CctxStatus.IsAbortRefunded == false {
k.AddZetaAbortedAmount(ctx, GetAbortedAmount(cctx))
}
}

// setNonceToCCTX updates the mapping between a nonce and a cctx index if the cctx is in a PendingOutbound or PendingRevert state
func (k Keeper) setNonceToCCTX(
ctx sdk.Context,
cctx types.CrossChainTx,
tssPubkey string,
) {
// set mapping nonce => cctxIndex
if cctx.CctxStatus.Status == types.CctxStatus_PendingOutbound ||
cctx.CctxStatus.Status == types.CctxStatus_PendingRevert {
k.GetObserverKeeper().SetNonceToCctx(ctx, observerTypes.NonceToCctx{
ChainId: cctx.GetCurrentOutboundParam().ReceiverChainId,
// #nosec G115 always in range
Nonce: int64(cctx.GetCurrentOutboundParam().TssNonce),
CctxIndex: cctx.Index,
Tss: tssPubkey,
})
}
}

// SetCrossChainTx set a specific cctx in the store from its index
func (k Keeper) SetCrossChainTx(ctx sdk.Context, cctx types.CrossChainTx) {
// only set the update timestamp if the block height is >0 to allow
// only set the updated timestamp if the block height is >0 to allow
// for a genesis import
if cctx.CctxStatus != nil && ctx.BlockHeight() > 0 {
cctx.CctxStatus.LastUpdateTimestamp = ctx.BlockHeader().Time.Unix()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (k Keeper) ValidateInbound(
if ok {
cctx.InboundParams.ObservedHash = inCctxIndex
}
k.SetCctxAndNonceToCctxAndInboundHashToCctx(ctx, cctx, tss.TssPubkey)
k.SaveCCTXUpdate(ctx, cctx, tss.TssPubkey)

return &cctx, nil
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func TestKeeper_ValidateInbound(t *testing.T) {
Return(observerTypes.PendingNonces{NonceHigh: 1}, true)
observerMock.On("SetChainNonces", mock.Anything, mock.Anything).Return(nil)
observerMock.On("SetPendingNonces", mock.Anything, mock.Anything).Return(nil)
// setup Mocks for SetCctxAndNonceToCctxAndInboundHashToCctx
// setup Mocks for SaveCCTXUpdate
observerMock.On("SetNonceToCctx", mock.Anything, mock.Anything).Return(nil)

k.SetGasPrice(ctx, types.GasPrice{
Expand Down
Loading
Loading