Skip to content

Commit

Permalink
refactored errors returning from votes
Browse files Browse the repository at this point in the history
Signed-off-by: Francisco de Borja Aranda Castillejo <[email protected]>
  • Loading branch information
Francisco de Borja Aranda Castillejo committed Jul 15, 2024
1 parent 6e9e2cf commit 9ff66ae
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 78 deletions.
3 changes: 1 addition & 2 deletions x/crosschain/keeper/msg_server_vote_gas_price.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package keeper

import (
"context"
"fmt"
"math/big"
"sort"
"strconv"
Expand All @@ -28,7 +27,7 @@ func (k msgServer) VoteGasPrice(

chain, found := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, msg.ChainId)
if !found {
return nil, cosmoserrors.Wrap(types.ErrUnsupportedChain, fmt.Sprintf("ChainID : %d ", msg.ChainId))
return nil, cosmoserrors.Wrapf(types.ErrUnsupportedChain, "ChainID: %d ", msg.ChainId)
}
if ok := k.zetaObserverKeeper.IsNonTombstonedObserver(ctx, msg.Creator); !ok {
return nil, observertypes.ErrNotObserver
Expand Down
22 changes: 11 additions & 11 deletions x/crosschain/keeper/msg_server_vote_inbound_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ package keeper

import (
"context"
"fmt"

cosmoserrors "cosmossdk.io/errors"
sdkerrors "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"

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

const voteInboundID = "Vote Inbound"

// FIXME: use more specific error types & codes

// VoteInbound casts a vote on an inbound transaction observed on a connected chain. If this
Expand Down Expand Up @@ -73,22 +74,21 @@ func (k msgServer) VoteInbound(
msg.InboundHash,
)
if err != nil {
return nil, err
return nil, sdkerrors.Wrap(err, voteInboundID)
}

// If it is a new ballot, check if an inbound with the same hash, sender chain and event index has already been finalized
// This may happen if the same inbound is observed twice where msg.Digest gives a different index
// This check prevents double spending
if isNew {
if k.IsFinalizedInbound(tmpCtx, msg.InboundHash, msg.SenderChainId, msg.EventIndex) {
return nil, cosmoserrors.Wrap(
return nil, sdkerrors.Wrapf(
types.ErrObservedTxAlreadyFinalized,
fmt.Sprintf(
"inboundHash:%s, SenderChainID:%d, EventIndex:%d",
msg.InboundHash,
msg.SenderChainId,
msg.EventIndex,
),
"%s, InboundHash:%s, SenderChainID:%d, EventIndex:%d",
voteInboundID,
msg.InboundHash,
msg.SenderChainId,
msg.EventIndex,
)
}
}
Expand All @@ -100,7 +100,7 @@ func (k msgServer) VoteInbound(

cctx, err := k.ValidateInbound(ctx, msg, true)
if err != nil {
return nil, err
return nil, sdkerrors.Wrap(err, voteInboundID)
}

// Save the inbound CCTX to the store. This is called irrespective of the status of the CCTX or the outcome of the process function.
Expand Down
77 changes: 43 additions & 34 deletions x/crosschain/keeper/msg_server_vote_outbound_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
observerkeeper "github.com/zeta-chain/zetacore/x/observer/keeper"
)

const voteOutboundID = "Vote Outbound"

// VoteOutbound casts a vote on an outbound transaction observed on a connected chain (after
// it has been broadcasted to and finalized on a connected chain). If this is
// the first vote, a new ballot is created. When a threshold of votes is
Expand Down Expand Up @@ -61,45 +63,48 @@ func (k msgServer) VoteOutbound(
) (*types.MsgVoteOutboundResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

// Validate the message params to verify it against an existing cctx
// Validate the message params to verify it against an existing CCTX.
cctx, err := k.ValidateOutboundMessage(ctx, *msg)
if err != nil {
return nil, err
return nil, cosmoserrors.Wrap(err, voteOutboundID)
}
// get ballot index

ballotIndex := msg.Digest()
// vote on outbound ballot
isFinalizingVote, isNew, ballot, observationChain, err := k.zetaObserverKeeper.VoteOnOutboundBallot(
ctx,
ballotIndex,
msg.OutboundChain,
msg.Status,
msg.Creator)
if err != nil {
return nil, err
return nil, cosmoserrors.Wrap(err, voteOutboundID)

Check warning on line 80 in x/crosschain/keeper/msg_server_vote_outbound_tx.go

View check run for this annotation

Codecov / codecov/patch

x/crosschain/keeper/msg_server_vote_outbound_tx.go#L80

Added line #L80 was not covered by tests
}
// if the ballot is new, set the index to the CCTX

// If the ballot is new, set the index to the CCTX.
if isNew {
observerkeeper.EmitEventBallotCreated(ctx, ballot, msg.ObservedOutboundHash, observationChain)
}
// if not finalized commit state here

// If not finalized commit state here.
if !isFinalizingVote {
return &types.MsgVoteOutboundResponse{}, nil
}

// if ballot successful, the value received should be the out tx amount
// If ballot is successful, the value received should be the out tx amount.
err = cctx.AddOutbound(ctx, *msg, ballot.BallotStatus)
if err != nil {
return nil, err
return nil, cosmoserrors.Wrap(err, voteOutboundID)

Check warning on line 96 in x/crosschain/keeper/msg_server_vote_outbound_tx.go

View check run for this annotation

Codecov / codecov/patch

x/crosschain/keeper/msg_server_vote_outbound_tx.go#L96

Added line #L96 was not covered by tests
}
// Fund the gas stability pool with the remaining funds

// Fund the gas stability pool with the remaining funds.
k.FundStabilityPool(ctx, &cctx)

err = k.ValidateOutboundObservers(ctx, &cctx, ballot.BallotStatus, msg.ValueReceived.String())
if err != nil {
k.SaveFailedOutbound(ctx, &cctx, err.Error(), ballotIndex)
return &types.MsgVoteOutboundResponse{}, nil
}

k.SaveSuccessfulOutbound(ctx, &cctx, ballotIndex)
return &types.MsgVoteOutboundResponse{}, nil
}
Expand All @@ -112,7 +117,7 @@ func (k Keeper) FundStabilityPool(ctx sdk.Context, cctx *types.CrossChainTx) {
// Fund the gas stability pool with the remaining funds
if err := k.FundGasStabilityPoolFromRemainingFees(ctx, *cctx.GetCurrentOutboundParam(), cctx.GetCurrentOutboundParam().ReceiverChainId); err != nil {
ctx.Logger().
Error(fmt.Sprintf("VoteOutbound: CCTX: %s Can't fund the gas stability pool with remaining fees %s", cctx.Index, err.Error()))
Error("%s: CCTX: %s Can't fund the gas stability pool with remaining fees %s", voteOutboundID, cctx.Index, err.Error())

Check warning on line 120 in x/crosschain/keeper/msg_server_vote_outbound_tx.go

View check run for this annotation

Codecov / codecov/patch

x/crosschain/keeper/msg_server_vote_outbound_tx.go#L120

Added line #L120 was not covered by tests
}
}

Expand All @@ -136,16 +141,18 @@ func (k Keeper) FundGasStabilityPoolFromRemainingFees(
remainingGas := gasLimit - gasUsed
remainingFees := math.NewUint(remainingGas).Mul(gasPrice).BigInt()

// We fund the stability pool with a portion of the remaining fees
// We fund the stability pool with a portion of the remaining fees.
remainingFees = percentOf(remainingFees, RemainingFeesToStabilityPoolPercent)
// Fund the gas stability pool

// Fund the gas stability pool.
if err := k.fungibleKeeper.FundGasStabilityPool(ctx, chainID, remainingFees); err != nil {
return err
}
} else {
return fmt.Errorf("VoteOutbound: The gas limit %d is less than the gas used %d", gasLimit, gasUsed)
return fmt.Errorf("%s: The gas limit %d is less than the gas used %d", voteOutboundID, gasLimit, gasUsed)
}
}

return nil
}

Expand All @@ -167,7 +174,6 @@ SaveFailedOutbound saves a failed outbound transaction.It does the following thi
func (k Keeper) SaveFailedOutbound(ctx sdk.Context, cctx *types.CrossChainTx, errMessage string, ballotIndex string) {
cctx.SetAbort(errMessage)
ctx.Logger().Error(errMessage)

k.SaveOutbound(ctx, cctx, ballotIndex)
}

Expand Down Expand Up @@ -195,48 +201,51 @@ func (k Keeper) SaveOutbound(ctx sdk.Context, cctx *types.CrossChainTx, ballotIn
outTxTssNonce := cctx.GetCurrentOutboundParam().TssNonce

cctx.GetCurrentOutboundParam().BallotIndex = ballotIndex

// #nosec G115 always in range
k.GetObserverKeeper().RemoveFromPendingNonces(ctx, tssPubkey, receiverChain, int64(outTxTssNonce))
k.RemoveOutboundTrackerFromStore(ctx, receiverChain, outTxTssNonce)
ctx.Logger().
Info(fmt.Sprintf("Remove tracker %s: , Block Height : %d ", getOutboundTrackerIndex(receiverChain, outTxTssNonce), ctx.BlockHeight()))
Info("%s: Remove tracker %s: , Block Height : %d ", voteOutboundID, getOutboundTrackerIndex(receiverChain, outTxTssNonce), ctx.BlockHeight())

// This should set nonce to cctx only if a new revert is created.
k.SetCctxAndNonceToCctxAndInboundHashToCctx(ctx, *cctx)
}

func (k Keeper) ValidateOutboundMessage(ctx sdk.Context, msg types.MsgVoteOutbound) (types.CrossChainTx, error) {
// check if CCTX exists and if the nonce matches
// Check if CCTX exists and if the nonce matches.
cctx, found := k.GetCrossChainTx(ctx, msg.CctxHash)
if !found {
return types.CrossChainTx{}, cosmoserrors.Wrap(
return types.CrossChainTx{}, cosmoserrors.Wrapf(
sdkerrors.ErrInvalidRequest,
fmt.Sprintf("CCTX %s does not exist", msg.CctxHash),
)
"%s, CCTX %s does not exist", voteOutboundID, msg.CctxHash)
}

if cctx.GetCurrentOutboundParam().TssNonce != msg.OutboundTssNonce {
return types.CrossChainTx{}, cosmoserrors.Wrap(
return types.CrossChainTx{}, cosmoserrors.Wrapf(
sdkerrors.ErrInvalidRequest,
fmt.Sprintf(
"OutboundTssNonce %d does not match CCTX OutboundTssNonce %d",
msg.OutboundTssNonce,
cctx.GetCurrentOutboundParam().TssNonce,
),
"%s, OutboundTssNonce %d does not match CCTX OutboundTssNonce %d",
voteOutboundID,
msg.OutboundTssNonce,
cctx.GetCurrentOutboundParam().TssNonce,
)
}
// do not process an outbound vote if TSS is not found

// Do not process an outbound vote if TSS is not found.
_, found = k.zetaObserverKeeper.GetTSS(ctx)
if !found {
return types.CrossChainTx{}, types.ErrCannotFindTSSKeys
return types.CrossChainTx{}, cosmoserrors.Wrap(types.ErrCannotFindTSSKeys, voteOutboundID)
}

if cctx.GetCurrentOutboundParam().ReceiverChainId != msg.OutboundChain {
return types.CrossChainTx{}, cosmoserrors.Wrap(
return types.CrossChainTx{}, cosmoserrors.Wrapf(
sdkerrors.ErrInvalidRequest,
fmt.Sprintf(
"OutboundChain %d does not match CCTX OutboundChain %d",
msg.OutboundChain,
cctx.GetCurrentOutboundParam().ReceiverChainId,
),
"%s, OutboundChain %d does not match CCTX OutboundChain %d",
voteOutboundID,
msg.OutboundChain,
cctx.GetCurrentOutboundParam().ReceiverChainId,
)
}

return cctx, nil
}
11 changes: 8 additions & 3 deletions x/observer/keeper/msg_server_vote_blame.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"github.com/zeta-chain/zetacore/x/observer/types"
)

const voteBlameID = "Vote Blame"

func (k msgServer) VoteBlame(
goCtx context.Context,
msg *types.MsgVoteBlame,
Expand All @@ -21,11 +23,12 @@ func (k msgServer) VoteBlame(
if !found {
return nil, sdkerrors.Wrapf(
crosschainTypes.ErrUnsupportedChain,
"ChainID %d, Blame vote", msg.ChainId)
"%s, ChainID %d", voteBlameID, msg.ChainId)
}

if ok := k.IsNonTombstonedObserver(ctx, msg.Creator); !ok {
return nil, types.ErrNotObserver
return nil, sdkerrors.Wrap(
types.ErrNotObserver, voteBlameID)
}

ballot, isFinalized, isNew, err := k.VoteOnBallot(
Expand All @@ -37,7 +40,9 @@ func (k msgServer) VoteBlame(
types.VoteType_SuccessObservation,
)
if err != nil {
return nil, sdkerrors.Wrap(err, errVoteOnBallot)
return nil, sdkerrors.Wrapf(
err,
"%s, BallotIdentifier %v", voteBlameID, ballot.BallotIdentifier)
}

if isNew {
Expand Down
14 changes: 10 additions & 4 deletions x/observer/keeper/msg_server_vote_block_header.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"github.com/zeta-chain/zetacore/x/observer/types"
)

const voteBlockHeaderID = "Vote BlockHeader"

// VoteBlockHeader vote for a new block header to the storers
func (k msgServer) VoteBlockHeader(
goCtx context.Context,
Expand All @@ -20,18 +22,22 @@ func (k msgServer) VoteBlockHeader(
// check if the chain is enabled
chain, found := k.GetSupportedChainFromChainID(ctx, msg.ChainId)
if !found {
return nil, sdkerrors.Wrapf(types.ErrSupportedChains, "chain id: %d", msg.ChainId)
return nil, sdkerrors.Wrapf(
types.ErrSupportedChains,
"%s, ChainID %d", voteBlockHeaderID, msg.ChainId)
}

// check if observer
if ok := k.IsNonTombstonedObserver(ctx, msg.Creator); !ok {
return nil, types.ErrNotObserver
return nil, sdkerrors.Wrap(types.ErrNotObserver, voteBlockHeaderID)
}

// check the new block header is valid
parentHash, err := k.lightclientKeeper.CheckNewBlockHeader(ctx, msg.ChainId, msg.BlockHash, msg.Height, msg.Header)
if err != nil {
return nil, sdkerrors.Wrap(lightclienttypes.ErrInvalidBlockHeader, err.Error())
return nil, sdkerrors.Wrapf(
lightclienttypes.ErrInvalidBlockHeader,
"%s, parent hash %s", voteBlockHeaderID, parentHash)
}

_, isFinalized, isNew, err := k.VoteOnBallot(
Expand All @@ -43,7 +49,7 @@ func (k msgServer) VoteBlockHeader(
types.VoteType_SuccessObservation,
)
if err != nil {
return nil, sdkerrors.Wrap(err, errVoteOnBallot)
return nil, sdkerrors.Wrap(err, voteBlockHeaderID)
}

if !isFinalized {
Expand Down
Loading

0 comments on commit 9ff66ae

Please sign in to comment.