From a616eefec196d756f59ab25bc31e226d45c12350 Mon Sep 17 00:00:00 2001 From: lumtis Date: Tue, 2 Jan 2024 11:05:38 +0100 Subject: [PATCH 01/24] move logic for ballot voting for inbound --- common/chain.go | 11 ++- x/crosschain/keeper/cctx.go | 14 ++- x/crosschain/keeper/evm_deposit.go | 6 +- x/crosschain/keeper/evm_hooks.go | 20 +++- .../keeper/msg_server_vote_inbound_tx.go | 93 +++++++------------ x/crosschain/types/expected_keepers.go | 12 ++- x/fungible/keeper/deposits.go | 8 +- x/observer/keeper/vote_inbound.go | 85 +++++++++++++++++ 8 files changed, 172 insertions(+), 77 deletions(-) create mode 100644 x/observer/keeper/vote_inbound.go diff --git a/common/chain.go b/common/chain.go index fe19b302bf..b33f8e692b 100644 --- a/common/chain.go +++ b/common/chain.go @@ -78,12 +78,17 @@ func (chain Chain) BTCAddressFromWitnessProgram(witnessProgram []byte) (string, // DecodeAddress decode the address string to bytes func (chain Chain) DecodeAddress(addr string) ([]byte, error) { - if IsEVMChain(chain.ChainId) { + return DecodeAddressFromChainID(chain.ChainId, addr) +} + +// DecodeAddressFromChainID decode the address string to bytes +func DecodeAddressFromChainID(chainID int64, addr string) ([]byte, error) { + if IsEVMChain(chainID) { return ethcommon.HexToAddress(addr).Bytes(), nil - } else if IsBitcoinChain(chain.ChainId) { + } else if IsBitcoinChain(chainID) { return []byte(addr), nil } - return nil, fmt.Errorf("chain (%d) not supported", chain.ChainId) + return nil, fmt.Errorf("chain (%d) not supported", chainID) } func IsZetaChain(chainID int64) bool { diff --git a/x/crosschain/keeper/cctx.go b/x/crosschain/keeper/cctx.go index e3a2a06f71..06e44f6b48 100644 --- a/x/crosschain/keeper/cctx.go +++ b/x/crosschain/keeper/cctx.go @@ -99,13 +99,21 @@ func (k Keeper) RemoveCrossChainTx(ctx sdk.Context, index string) { store.Delete(types.KeyPrefix(index)) } -func (k Keeper) CreateNewCCTX(ctx sdk.Context, msg *types.MsgVoteOnObservedInboundTx, index string, tssPubkey string, s types.CctxStatus, senderChain, receiverChain *common.Chain) types.CrossChainTx { +func (k Keeper) CreateNewCCTX( + ctx sdk.Context, + msg *types.MsgVoteOnObservedInboundTx, + index string, + tssPubkey string, + s types.CctxStatus, + senderChainID, + receiverChainID int64, +) types.CrossChainTx { if msg.TxOrigin == "" { msg.TxOrigin = msg.Sender } inboundParams := &types.InboundTxParams{ Sender: msg.Sender, - SenderChainId: senderChain.ChainId, + SenderChainId: senderChainID, TxOrigin: msg.TxOrigin, Asset: msg.Asset, Amount: msg.Amount, @@ -118,7 +126,7 @@ func (k Keeper) CreateNewCCTX(ctx sdk.Context, msg *types.MsgVoteOnObservedInbou outBoundParams := &types.OutboundTxParams{ Receiver: msg.Receiver, - ReceiverChainId: receiverChain.ChainId, + ReceiverChainId: receiverChainID, OutboundTxHash: "", OutboundTxTssNonce: 0, OutboundTxGasLimit: msg.GasLimit, diff --git a/x/crosschain/keeper/evm_deposit.go b/x/crosschain/keeper/evm_deposit.go index c33adc8420..2dfa933e63 100644 --- a/x/crosschain/keeper/evm_deposit.go +++ b/x/crosschain/keeper/evm_deposit.go @@ -22,7 +22,7 @@ func (k Keeper) HandleEVMDeposit( ctx sdk.Context, cctx *types.CrossChainTx, msg types.MsgVoteOnObservedInboundTx, - senderChain *common.Chain, + senderChainID int64, ) (bool, error) { to := ethcommon.HexToAddress(msg.Receiver) var ethTxHash ethcommon.Hash @@ -51,7 +51,7 @@ func (k Keeper) HandleEVMDeposit( to = parsedAddress } - from, err := senderChain.DecodeAddress(msg.Sender) + from, err := common.DecodeAddressFromChainID(senderChainID, msg.Sender) if err != nil { return false, fmt.Errorf("HandleEVMDeposit: unable to decode address: %s", err.Error()) } @@ -61,7 +61,7 @@ func (k Keeper) HandleEVMDeposit( from, to, msg.Amount.BigInt(), - senderChain, + msg.SenderChainId, data, msg.CoinType, msg.Asset, diff --git a/x/crosschain/keeper/evm_hooks.go b/x/crosschain/keeper/evm_hooks.go index 92fa5ffad5..d85d52accb 100644 --- a/x/crosschain/keeper/evm_hooks.go +++ b/x/crosschain/keeper/evm_hooks.go @@ -157,7 +157,15 @@ func (k Keeper) ProcessZRC20WithdrawalEvent(ctx sdk.Context, event *zrc20.ZRC20W ) sendHash := msg.Digest() - cctx := k.CreateNewCCTX(ctx, msg, sendHash, tss.TssPubkey, types.CctxStatus_PendingOutbound, &senderChain, receiverChain) + cctx := k.CreateNewCCTX( + ctx, + msg, + sendHash, + tss.TssPubkey, + types.CctxStatus_PendingOutbound, + senderChain.ChainId, + receiverChain.ChainId, + ) // Get gas price and amount gasprice, found := k.GetGasPrice(ctx, receiverChain.ChainId) @@ -235,7 +243,15 @@ func (k Keeper) ProcessZetaSentEvent(ctx sdk.Context, event *connectorzevm.ZetaC sendHash := msg.Digest() // Create the CCTX - cctx := k.CreateNewCCTX(ctx, msg, sendHash, tss.TssPubkey, types.CctxStatus_PendingOutbound, &senderChain, receiverChain) + cctx := k.CreateNewCCTX( + ctx, + msg, + sendHash, + tss.TssPubkey, + types.CctxStatus_PendingOutbound, + senderChain.ChainId, + receiverChain.ChainId, + ) if err := k.PayGasAndUpdateCctx( ctx, diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index dd5af15b4b..f9ccf97cdf 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -2,14 +2,9 @@ package keeper import ( "context" - "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" - observerKeeper "github.com/zeta-chain/zetacore/x/observer/keeper" - observerTypes "github.com/zeta-chain/zetacore/x/observer/types" ) // FIXME: use more specific error types & codes @@ -57,69 +52,44 @@ import ( // Only observer validators are authorized to broadcast this message. func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.MsgVoteOnObservedInboundTx) (*types.MsgVoteOnObservedInboundTxResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - - observationType := observerTypes.ObservationType_InBoundTx - if !k.zetaObserverKeeper.IsInboundEnabled(ctx) { - return nil, types.ErrNotEnoughPermissions - } - // GetChainFromChainID makes sure we are getting only supported chains , if a chain support has been turned on using gov proposal, this function returns nil - observationChain := k.zetaObserverKeeper.GetParams(ctx).GetChainFromChainID(msg.SenderChainId) - if observationChain == nil { - return nil, sdkerrors.Wrap(types.ErrUnsupportedChain, fmt.Sprintf("ChainID %d, Observation %s", msg.SenderChainId, observationType.String())) - } - receiverChain := k.zetaObserverKeeper.GetParams(ctx).GetChainFromChainID(msg.ReceiverChain) - if receiverChain == nil { - return nil, sdkerrors.Wrap(types.ErrUnsupportedChain, fmt.Sprintf("ChainID %d, Observation %s", msg.ReceiverChain, observationType.String())) - } - tssPub := "" - tss, tssFound := k.zetaObserverKeeper.GetTSS(ctx) - if tssFound { - tssPub = tss.TssPubkey - } - // IsAuthorized does various checks against the list of observer mappers - if ok := k.zetaObserverKeeper.IsAuthorized(ctx, msg.Creator, observationChain); !ok { - return nil, observerTypes.ErrNotAuthorizedPolicy - } - index := msg.Digest() - // Add votes and Set Ballot - // GetBallot checks against the supported chains list before querying for Ballot - ballot, isNew, err := k.zetaObserverKeeper.FindBallot(ctx, index, observationChain, observationType) - if err != nil { - return nil, err - } - if isNew { - observerKeeper.EmitEventBallotCreated(ctx, ballot, msg.InTxHash, observationChain.String()) - } - // AddVoteToBallot adds a vote and sets the ballot - ballot, err = k.zetaObserverKeeper.AddVoteToBallot(ctx, ballot, msg.Creator, observerTypes.VoteType_SuccessObservation) + + // vote on inbound ballot + finalized, err := k.zetaObserverKeeper.VoteOnInboundBallot( + ctx, + msg.SenderChainId, + msg.ReceiverChain, + msg.CoinType, + msg.Creator, + index, + msg.InTxHash, + ) if err != nil { return nil, err } - - _, isFinalized := k.zetaObserverKeeper.CheckIfFinalizingVote(ctx, ballot) - if !isFinalized { + if !finalized { // Return nil here to add vote to ballot and commit state return &types.MsgVoteOnObservedInboundTxResponse{}, nil } - // Validation if we want to send ZETA to external chain, but there is no ZETA token. - if receiverChain.IsExternalChain() { - coreParams, found := k.zetaObserverKeeper.GetCoreParamsByChainID(ctx, receiverChain.ChainId) - if !found { - return nil, types.ErrNotFoundCoreParams - } - if coreParams.ZetaTokenContractAddress == "" && msg.CoinType == common.CoinType_Zeta { - return nil, types.ErrUnableToSendCoinType - } + // get the latest TSS to set the TSS public key in the CCTX + tssPub := "" + tss, tssFound := k.zetaObserverKeeper.GetTSS(ctx) + if tssFound { + tssPub = tss.TssPubkey } - // ****************************************************************************** - // below only happens when ballot is finalized: exactly when threshold vote is in - // ****************************************************************************** + // create the CCTX + cctx := k.CreateNewCCTX( + ctx, + msg, + index, + tssPub, + types.CctxStatus_PendingInbound, + msg.SenderChainId, + msg.ReceiverChain, + ) - // Inbound Ballot has been finalized , Create CCTX - cctx := k.CreateNewCCTX(ctx, msg, index, tssPub, types.CctxStatus_PendingInbound, observationChain, receiverChain) defer func() { EmitEventInboundFinalized(ctx, &cctx) // #nosec G701 always positive @@ -127,11 +97,12 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg k.RemoveInTxTrackerIfExists(ctx, cctx.InboundTxParams.SenderChainId, cctx.InboundTxParams.InboundTxObservedHash) k.SetCctxAndNonceToCctxAndInTxHashToCctx(ctx, cctx) }() + // FinalizeInbound updates CCTX Prices and Nonce // Aborts is any of the updates fail - if receiverChain.IsZetaChain() { + if common.IsZetaChain(msg.ReceiverChain) { tmpCtx, commit := ctx.CacheContext() - isContractReverted, err := k.HandleEVMDeposit(tmpCtx, &cctx, *msg, observationChain) + isContractReverted, err := k.HandleEVMDeposit(tmpCtx, &cctx, *msg, msg.SenderChainId) if err != nil && !isContractReverted { // exceptional case; internal error; should abort CCTX cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()) @@ -215,7 +186,7 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg err = func() error { err := k.PayGasAndUpdateCctx( tmpCtx, - receiverChain.ChainId, + msg.ReceiverChain, &cctx, cctx.InboundTxParams.Amount, false, @@ -223,7 +194,7 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg if err != nil { return err } - return k.UpdateNonce(tmpCtx, receiverChain.ChainId, &cctx) + return k.UpdateNonce(tmpCtx, msg.ReceiverChain, &cctx) }() if err != nil { // do not commit anything here as the CCTX should be aborted diff --git a/x/crosschain/types/expected_keepers.go b/x/crosschain/types/expected_keepers.go index d4747e68c2..47db90184e 100644 --- a/x/crosschain/types/expected_keepers.go +++ b/x/crosschain/types/expected_keepers.go @@ -93,6 +93,16 @@ type ZetaObserverKeeper interface { SetTssAndUpdateNonce(ctx sdk.Context, tss observertypes.TSS) RemoveFromPendingNonces(ctx sdk.Context, tss string, chainID int64, nonce int64) GetAllNonceToCctx(ctx sdk.Context) (list []observertypes.NonceToCctx) + + VoteOnInboundBallot( + ctx sdk.Context, + senderChainID int64, + receiverChainID int64, + coinType common.CoinType, + voter string, + ballotIndex string, + inTxHash string, + ) (bool, error) } type FungibleKeeper interface { @@ -123,7 +133,7 @@ type FungibleKeeper interface { from []byte, to eth.Address, amount *big.Int, - senderChain *common.Chain, + senderChainID int64, data []byte, coinType common.CoinType, asset string, diff --git a/x/fungible/keeper/deposits.go b/x/fungible/keeper/deposits.go index 832613aa2c..3d8ebfb28b 100644 --- a/x/fungible/keeper/deposits.go +++ b/x/fungible/keeper/deposits.go @@ -26,7 +26,7 @@ func (k Keeper) ZRC20DepositAndCallContract( from []byte, to eth.Address, amount *big.Int, - senderChain *common.Chain, + senderChainID int64, data []byte, coinType common.CoinType, asset string, @@ -37,12 +37,12 @@ func (k Keeper) ZRC20DepositAndCallContract( // get foreign coin if coinType == common.CoinType_Gas { - coin, found = k.GetGasCoinForForeignCoin(ctx, senderChain.ChainId) + coin, found = k.GetGasCoinForForeignCoin(ctx, senderChainID) if !found { return nil, false, crosschaintypes.ErrGasCoinNotFound } } else { - coin, found = k.GetForeignCoinFromAsset(ctx, asset, senderChain.ChainId) + coin, found = k.GetForeignCoinFromAsset(ctx, asset, senderChainID) if !found { return nil, false, crosschaintypes.ErrForeignCoinNotFound } @@ -75,7 +75,7 @@ func (k Keeper) ZRC20DepositAndCallContract( context := systemcontract.ZContext{ Origin: from, Sender: eth.Address{}, - ChainID: big.NewInt(senderChain.ChainId), + ChainID: big.NewInt(senderChainID), } res, err := k.DepositZRC20AndCallContract(ctx, context, ZRC20Contract, to, amount, data) return res, true, err diff --git a/x/observer/keeper/vote_inbound.go b/x/observer/keeper/vote_inbound.go new file mode 100644 index 0000000000..d9a643326e --- /dev/null +++ b/x/observer/keeper/vote_inbound.go @@ -0,0 +1,85 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/x/crosschain/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" +) + +// VoteOnInboundBallot casts a vote on an inbound transaction observed on a connected chain. If this +// is the first vote, a new ballot is created. When a threshold of votes is +// reached, the ballot is finalized. +func (k Keeper) VoteOnInboundBallot( + ctx sdk.Context, + senderChainID int64, + receiverChainID int64, + coinType common.CoinType, + voter string, + ballotIndex string, + inTxHash string, +) (bool, error) { + if !k.IsInboundEnabled(ctx) { + return false, types.ErrNotEnoughPermissions + } + + // makes sure we are getting only supported chains + // if a chain support has been turned on using gov proposal + // this function returns nil + senderChain := k.GetParams(ctx).GetChainFromChainID(senderChainID) + if senderChain == nil { + return false, sdkerrors.Wrap(types.ErrUnsupportedChain, fmt.Sprintf( + "ChainID %d, Observation %s", + senderChainID, + observertypes.ObservationType_InBoundTx.String()), + ) + } + + // checks the voter is authorized to vote on the observation chain + if ok := k.IsAuthorized(ctx, voter, senderChain); !ok { + return false, observertypes.ErrNotAuthorizedPolicy + } + + // makes sure we are getting only supported chains + receiverChain := k.GetParams(ctx).GetChainFromChainID(receiverChainID) + if receiverChain == nil { + return false, sdkerrors.Wrap(types.ErrUnsupportedChain, fmt.Sprintf( + "ChainID %d, Observation %s", + receiverChain.ChainId, + observertypes.ObservationType_InBoundTx.String()), + ) + } + + // check if we want to send ZETA to external chain, but there is no ZETA token. + if receiverChain.IsExternalChain() { + coreParams, found := k.GetCoreParamsByChainID(ctx, receiverChain.ChainId) + if !found { + return false, types.ErrNotFoundCoreParams + } + if coreParams.ZetaTokenContractAddress == "" && coinType == common.CoinType_Zeta { + return false, types.ErrUnableToSendCoinType + } + } + + // checks against the supported chains list before querying for Ballot + ballot, isNew, err := k.FindBallot(ctx, ballotIndex, senderChain, observertypes.ObservationType_InBoundTx) + if err != nil { + return false, err + } + if isNew { + EmitEventBallotCreated(ctx, ballot, inTxHash, senderChain.String()) + } + + // adds a vote and sets the ballot + ballot, err = k.AddVoteToBallot(ctx, ballot, voter, observertypes.VoteType_SuccessObservation) + if err != nil { + return false, err + } + + // checks if the ballot is finalized + _, isFinalized := k.CheckIfFinalizingVote(ctx, ballot) + return isFinalized, nil +} From ce55d9ced0874c8b402b4830ca0008e478fcef80 Mon Sep 17 00:00:00 2001 From: lumtis Date: Tue, 2 Jan 2024 11:06:01 +0100 Subject: [PATCH 02/24] fix mocks --- testutil/keeper/mocks/crosschain/fungible.go | 22 +++++++-------- testutil/keeper/mocks/crosschain/observer.go | 28 ++++++++++++++++++++ 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/testutil/keeper/mocks/crosschain/fungible.go b/testutil/keeper/mocks/crosschain/fungible.go index 69f51cc939..67cd5c70b6 100644 --- a/testutil/keeper/mocks/crosschain/fungible.go +++ b/testutil/keeper/mocks/crosschain/fungible.go @@ -627,9 +627,9 @@ func (_m *CrosschainFungibleKeeper) WithdrawFromGasStabilityPool(ctx types.Conte return r0 } -// ZRC20DepositAndCallContract provides a mock function with given fields: ctx, from, to, amount, senderChain, data, coinType, asset -func (_m *CrosschainFungibleKeeper) ZRC20DepositAndCallContract(ctx types.Context, from []byte, to common.Address, amount *big.Int, senderChain *zetacorecommon.Chain, data []byte, coinType zetacorecommon.CoinType, asset string) (*evmtypes.MsgEthereumTxResponse, bool, error) { - ret := _m.Called(ctx, from, to, amount, senderChain, data, coinType, asset) +// ZRC20DepositAndCallContract provides a mock function with given fields: ctx, from, to, amount, senderChainID, data, coinType, asset +func (_m *CrosschainFungibleKeeper) ZRC20DepositAndCallContract(ctx types.Context, from []byte, to common.Address, amount *big.Int, senderChainID int64, data []byte, coinType zetacorecommon.CoinType, asset string) (*evmtypes.MsgEthereumTxResponse, bool, error) { + ret := _m.Called(ctx, from, to, amount, senderChainID, data, coinType, asset) if len(ret) == 0 { panic("no return value specified for ZRC20DepositAndCallContract") @@ -638,25 +638,25 @@ func (_m *CrosschainFungibleKeeper) ZRC20DepositAndCallContract(ctx types.Contex var r0 *evmtypes.MsgEthereumTxResponse var r1 bool var r2 error - if rf, ok := ret.Get(0).(func(types.Context, []byte, common.Address, *big.Int, *zetacorecommon.Chain, []byte, zetacorecommon.CoinType, string) (*evmtypes.MsgEthereumTxResponse, bool, error)); ok { - return rf(ctx, from, to, amount, senderChain, data, coinType, asset) + if rf, ok := ret.Get(0).(func(types.Context, []byte, common.Address, *big.Int, int64, []byte, zetacorecommon.CoinType, string) (*evmtypes.MsgEthereumTxResponse, bool, error)); ok { + return rf(ctx, from, to, amount, senderChainID, data, coinType, asset) } - if rf, ok := ret.Get(0).(func(types.Context, []byte, common.Address, *big.Int, *zetacorecommon.Chain, []byte, zetacorecommon.CoinType, string) *evmtypes.MsgEthereumTxResponse); ok { - r0 = rf(ctx, from, to, amount, senderChain, data, coinType, asset) + if rf, ok := ret.Get(0).(func(types.Context, []byte, common.Address, *big.Int, int64, []byte, zetacorecommon.CoinType, string) *evmtypes.MsgEthereumTxResponse); ok { + r0 = rf(ctx, from, to, amount, senderChainID, data, coinType, asset) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*evmtypes.MsgEthereumTxResponse) } } - if rf, ok := ret.Get(1).(func(types.Context, []byte, common.Address, *big.Int, *zetacorecommon.Chain, []byte, zetacorecommon.CoinType, string) bool); ok { - r1 = rf(ctx, from, to, amount, senderChain, data, coinType, asset) + if rf, ok := ret.Get(1).(func(types.Context, []byte, common.Address, *big.Int, int64, []byte, zetacorecommon.CoinType, string) bool); ok { + r1 = rf(ctx, from, to, amount, senderChainID, data, coinType, asset) } else { r1 = ret.Get(1).(bool) } - if rf, ok := ret.Get(2).(func(types.Context, []byte, common.Address, *big.Int, *zetacorecommon.Chain, []byte, zetacorecommon.CoinType, string) error); ok { - r2 = rf(ctx, from, to, amount, senderChain, data, coinType, asset) + if rf, ok := ret.Get(2).(func(types.Context, []byte, common.Address, *big.Int, int64, []byte, zetacorecommon.CoinType, string) error); ok { + r2 = rf(ctx, from, to, amount, senderChainID, data, coinType, asset) } else { r2 = ret.Error(2) } diff --git a/testutil/keeper/mocks/crosschain/observer.go b/testutil/keeper/mocks/crosschain/observer.go index 2f3bfb7669..5e2f2c3ac6 100644 --- a/testutil/keeper/mocks/crosschain/observer.go +++ b/testutil/keeper/mocks/crosschain/observer.go @@ -848,6 +848,34 @@ func (_m *CrosschainObserverKeeper) SetTssAndUpdateNonce(ctx types.Context, tss _m.Called(ctx, tss) } +// VoteOnInboundBallot provides a mock function with given fields: ctx, senderChainID, receiverChainID, coinType, voter, ballotIndex, inTxHash +func (_m *CrosschainObserverKeeper) VoteOnInboundBallot(ctx types.Context, senderChainID int64, receiverChainID int64, coinType common.CoinType, voter string, ballotIndex string, inTxHash string) (bool, error) { + ret := _m.Called(ctx, senderChainID, receiverChainID, coinType, voter, ballotIndex, inTxHash) + + if len(ret) == 0 { + panic("no return value specified for VoteOnInboundBallot") + } + + var r0 bool + var r1 error + if rf, ok := ret.Get(0).(func(types.Context, int64, int64, common.CoinType, string, string, string) (bool, error)); ok { + return rf(ctx, senderChainID, receiverChainID, coinType, voter, ballotIndex, inTxHash) + } + if rf, ok := ret.Get(0).(func(types.Context, int64, int64, common.CoinType, string, string, string) bool); ok { + r0 = rf(ctx, senderChainID, receiverChainID, coinType, voter, ballotIndex, inTxHash) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(types.Context, int64, int64, common.CoinType, string, string, string) error); ok { + r1 = rf(ctx, senderChainID, receiverChainID, coinType, voter, ballotIndex, inTxHash) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // NewCrosschainObserverKeeper creates a new instance of CrosschainObserverKeeper. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewCrosschainObserverKeeper(t interface { From 678027d7ba71baddec5e40af9b7a18674eee4922 Mon Sep 17 00:00:00 2001 From: lumtis Date: Tue, 2 Jan 2024 11:07:50 +0100 Subject: [PATCH 03/24] goimports --- x/crosschain/keeper/msg_server_vote_inbound_tx.go | 1 + 1 file changed, 1 insertion(+) diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index f9ccf97cdf..f7c5601221 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -2,6 +2,7 @@ package keeper import ( "context" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" From 18e4880c45d1f905a4679b1d6ae0f8537a1a2c72 Mon Sep 17 00:00:00 2001 From: lumtis Date: Tue, 2 Jan 2024 11:11:58 +0100 Subject: [PATCH 04/24] changelog --- changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.md b/changelog.md index 9b93cde356..6b73c8a4a8 100644 --- a/changelog.md +++ b/changelog.md @@ -28,6 +28,7 @@ ### Refactoring +* [1511](https://github.com/zeta-chain/node/pull/1511) - move ballot voting logic from `crosschain` to `observer` * [1211](https://github.com/zeta-chain/node/issues/1211) - use `grpc` and `msg` for query and message files * refactor cctx scheduler - decouple evm cctx scheduler from btc cctx scheduler * move tss state from crosschain to observer From 935043e274c92a29bbb24b308dfecb7b7c0b2f96 Mon Sep 17 00:00:00 2001 From: lumtis Date: Tue, 2 Jan 2024 13:52:10 +0100 Subject: [PATCH 05/24] fix unit tests --- x/crosschain/keeper/evm_deposit.go | 2 +- x/crosschain/keeper/evm_deposit_test.go | 22 +++++++-------- x/fungible/keeper/deposits_test.go | 36 ++++++++++++------------- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/x/crosschain/keeper/evm_deposit.go b/x/crosschain/keeper/evm_deposit.go index 2dfa933e63..e30e6069aa 100644 --- a/x/crosschain/keeper/evm_deposit.go +++ b/x/crosschain/keeper/evm_deposit.go @@ -61,7 +61,7 @@ func (k Keeper) HandleEVMDeposit( from, to, msg.Amount.BigInt(), - msg.SenderChainId, + senderChainID, data, msg.CoinType, msg.Asset, diff --git a/x/crosschain/keeper/evm_deposit_test.go b/x/crosschain/keeper/evm_deposit_test.go index 65483d89c1..dd6528e639 100644 --- a/x/crosschain/keeper/evm_deposit_test.go +++ b/x/crosschain/keeper/evm_deposit_test.go @@ -39,7 +39,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { Amount: math.NewUintFromBigInt(amount), CoinType: common.CoinType_Zeta, }, - nil, + 0, ) require.NoError(t, err) require.False(t, reverted) @@ -68,7 +68,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { Amount: math.NewUintFromBigInt(amount), CoinType: common.CoinType_Zeta, }, - nil, + 0, ) require.ErrorIs(t, err, errDeposit) require.False(t, reverted) @@ -80,7 +80,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { UseFungibleMock: true, }) - senderChain := getValidEthChain(t) + senderChain := getValidEthChainID(t) fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() @@ -124,7 +124,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { UseFungibleMock: true, }) - senderChain := getValidEthChain(t) + senderChain := getValidEthChainID(t) fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() @@ -169,7 +169,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { UseFungibleMock: true, }) - senderChain := getValidEthChain(t) + senderChain := getValidEthChainID(t) fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() @@ -214,7 +214,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { UseFungibleMock: true, }) - senderChain := getValidEthChain(t) + senderChain := getValidEthChainID(t) fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() @@ -258,7 +258,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { UseFungibleMock: true, }) - senderChain := getValidEthChain(t) + senderChain := getValidEthChainID(t) fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() @@ -302,7 +302,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { UseFungibleMock: true, }) - senderChain := getValidEthChain(t) + senderChain := getValidEthChainID(t) fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() @@ -343,7 +343,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ UseFungibleMock: true, }) - senderChain := getValidEthChain(t) + senderChain := getValidEthChainID(t) _, err := k.HandleEVMDeposit( ctx, @@ -366,7 +366,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { UseFungibleMock: true, }) - senderChain := getValidEthChain(t) + senderChain := getValidEthChainID(t) fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() @@ -409,7 +409,7 @@ func TestMsgServer_HandleEVMDeposit(t *testing.T) { UseFungibleMock: true, }) - senderChain := getValidEthChain(t) + senderChain := getValidEthChainID(t) fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) receiver := sample.EthAddress() diff --git a/x/fungible/keeper/deposits_test.go b/x/fungible/keeper/deposits_test.go index 4131a1e00d..bfd3f7eecd 100644 --- a/x/fungible/keeper/deposits_test.go +++ b/x/fungible/keeper/deposits_test.go @@ -22,11 +22,11 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { _ = k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) chainList := common.DefaultChainsList() - chain := chainList[0] + chain := chainList[0].ChainId // deploy the system contracts deploySystemContracts(t, ctx, k, sdkk.EvmKeeper) - zrc20 := setupGasCoin(t, ctx, k, sdkk.EvmKeeper, chain.ChainId, "foobar", "foobar") + zrc20 := setupGasCoin(t, ctx, k, sdkk.EvmKeeper, chain, "foobar", "foobar") // deposit to := sample.EthAddress() @@ -53,12 +53,12 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { _ = k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) chainList := common.DefaultChainsList() - chain := chainList[0] + chain := chainList[0].ChainId assetAddress := sample.EthAddress().String() // deploy the system contracts deploySystemContracts(t, ctx, k, sdkk.EvmKeeper) - zrc20 := deployZRC20(t, ctx, k, sdkk.EvmKeeper, chain.ChainId, "foobar", assetAddress, "foobar") + zrc20 := deployZRC20(t, ctx, k, sdkk.EvmKeeper, chain, "foobar", assetAddress, "foobar") // deposit to := sample.EthAddress() @@ -85,12 +85,12 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { _ = k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) chainList := common.DefaultChainsList() - chain := chainList[0] + chain := chainList[0].ChainId assetAddress := sample.EthAddress().String() // deploy the system contracts deploySystemContracts(t, ctx, k, sdkk.EvmKeeper) - deployZRC20(t, ctx, k, sdkk.EvmKeeper, chain.ChainId, "foobar", assetAddress, "foobar") + deployZRC20(t, ctx, k, sdkk.EvmKeeper, chain, "foobar", assetAddress, "foobar") // deposit to := sample.EthAddress() @@ -113,11 +113,11 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { _ = k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) chainList := common.DefaultChainsList() - chain := chainList[0] + chain := chainList[0].ChainId // deploy the system contracts deploySystemContracts(t, ctx, k, sdkk.EvmKeeper) - zrc20 := setupGasCoin(t, ctx, k, sdkk.EvmKeeper, chain.ChainId, "foobar", "foobar") + zrc20 := setupGasCoin(t, ctx, k, sdkk.EvmKeeper, chain, "foobar", "foobar") // there is an initial total supply minted during gas pool setup initialTotalSupply, err := k.TotalSupplyZRC4(ctx, zrc20) @@ -159,11 +159,11 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { _ = k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) chainList := common.DefaultChainsList() - chain := chainList[0] + chain := chainList[0].ChainId // deploy the system contracts deploySystemContracts(t, ctx, k, sdkk.EvmKeeper) - zrc20 := setupGasCoin(t, ctx, k, sdkk.EvmKeeper, chain.ChainId, "foobar", "foobar") + zrc20 := setupGasCoin(t, ctx, k, sdkk.EvmKeeper, chain, "foobar", "foobar") // pause the coin coin, found := k.GetForeignCoins(ctx, zrc20.String()) @@ -191,11 +191,11 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { _ = k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) chainList := common.DefaultChainsList() - chain := chainList[0] + chain := chainList[0].ChainId // deploy the system contracts deploySystemContracts(t, ctx, k, sdkk.EvmKeeper) - zrc20 := setupGasCoin(t, ctx, k, sdkk.EvmKeeper, chain.ChainId, "foobar", "foobar") + zrc20 := setupGasCoin(t, ctx, k, sdkk.EvmKeeper, chain, "foobar", "foobar") // there is an initial total supply minted during gas pool setup initialTotalSupply, err := k.TotalSupplyZRC4(ctx, zrc20) @@ -232,7 +232,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { _ = k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) chainList := common.DefaultChainsList() - chain := chainList[0] + chain := chainList[0].ChainId // deploy the system contracts deploySystemContracts(t, ctx, k, sdkk.EvmKeeper) @@ -257,7 +257,7 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { _ = k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) chainList := common.DefaultChainsList() - chain := chainList[0] + chain := chainList[0].ChainId assetAddress := sample.EthAddress().String() // deploy the system contracts @@ -284,11 +284,11 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { _ = k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) chainList := common.DefaultChainsList() - chain := chainList[0] + chain := chainList[0].ChainId // deploy the system contracts deploySystemContracts(t, ctx, k, sdkk.EvmKeeper) - zrc20 := setupGasCoin(t, ctx, k, sdkk.EvmKeeper, chain.ChainId, "foobar", "foobar") + zrc20 := setupGasCoin(t, ctx, k, sdkk.EvmKeeper, chain, "foobar", "foobar") example, err := k.DeployContract(ctx, contracts.ExampleMetaData) require.NoError(t, err) @@ -322,11 +322,11 @@ func TestKeeper_ZRC20DepositAndCallContract(t *testing.T) { _ = k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName) chainList := common.DefaultChainsList() - chain := chainList[0] + chain := chainList[0].ChainId // deploy the system contracts deploySystemContracts(t, ctx, k, sdkk.EvmKeeper) - zrc20 := setupGasCoin(t, ctx, k, sdkk.EvmKeeper, chain.ChainId, "foobar", "foobar") + zrc20 := setupGasCoin(t, ctx, k, sdkk.EvmKeeper, chain, "foobar", "foobar") reverter, err := k.DeployContract(ctx, contracts.ReverterMetaData) require.NoError(t, err) From af8daded49019a4b8bb4edbe230f6771e3ea27cf Mon Sep 17 00:00:00 2001 From: lumtis Date: Tue, 2 Jan 2024 13:54:45 +0100 Subject: [PATCH 06/24] fix CI = --- Dockerfile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index 071b367296..31446c3e6b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,14 +10,14 @@ RUN ssh-keygen -b 2048 -t rsa -f /root/.ssh/localtest.pem -q -N "" WORKDIR /go/delivery/zeta-node COPY go.mod . COPY go.sum . -RUN --mount=type=cache,target=/root/.cache/go-build \ - go mod download +RUN go mod download + COPY . . -RUN --mount=type=cache,target=/root/.cache/go-build \ - make install -RUN --mount=type=cache,target=/root/.cache/go-build \ - make install-smoketest +RUN make install + +RUN make install-smoketest + # #FROM golang:1.20-alpine From 0d19c85b7ad78aa2b2bc0b68a7b21c64d5501033 Mon Sep 17 00:00:00 2001 From: lumtis Date: Tue, 2 Jan 2024 14:52:32 +0100 Subject: [PATCH 07/24] x/observer/keeper/vote_outbound.go x/crosschain/types/expected_keepers.go x/crosschain/keeper/msg_server_vote_outbound_tx.go --- .../keeper/msg_server_vote_outbound_tx.go | 61 +++++++------------ x/crosschain/types/expected_keepers.go | 7 +++ x/observer/keeper/vote_outbound.go | 52 ++++++++++++++++ 3 files changed, 81 insertions(+), 39 deletions(-) create mode 100644 x/observer/keeper/vote_outbound.go diff --git a/x/crosschain/keeper/msg_server_vote_outbound_tx.go b/x/crosschain/keeper/msg_server_vote_outbound_tx.go index e954c25967..09ccc684e6 100644 --- a/x/crosschain/keeper/msg_server_vote_outbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_outbound_tx.go @@ -13,8 +13,8 @@ import ( "github.com/rs/zerolog/log" "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" - observerKeeper "github.com/zeta-chain/zetacore/x/observer/keeper" - observerTypes "github.com/zeta-chain/zetacore/x/observer/types" + observerkeeper "github.com/zeta-chain/zetacore/x/observer/keeper" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) // VoteOnObservedOutboundTx casts a vote on an outbound transaction observed on a connected chain (after @@ -60,59 +60,45 @@ import ( // Only observer validators are authorized to broadcast this message. func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.MsgVoteOnObservedOutboundTx) (*types.MsgVoteOnObservedOutboundTxResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - observationType := observerTypes.ObservationType_OutBoundTx - // Observer Chain already checked then inbound is created - /* EDGE CASE : Params updated in during the finalization process - i.e Inbound has been finalized but outbound is still pending - */ - observationChain := k.zetaObserverKeeper.GetParams(ctx).GetChainFromChainID(msg.OutTxChain) - if observationChain == nil { - return nil, observerTypes.ErrSupportedChains - } - err := observerTypes.CheckReceiveStatus(msg.Status) - if err != nil { - return nil, err - } - //Check is msg.Creator is authorized to vote - if ok := k.zetaObserverKeeper.IsAuthorized(ctx, msg.Creator, observationChain); !ok { - return nil, observerTypes.ErrNotAuthorizedPolicy - } - // Check if CCTX exists + // check if CCTX exists and if the nonce matches cctx, found := k.GetCrossChainTx(ctx, msg.CctxHash) if !found { return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, fmt.Sprintf("CCTX %s does not exist", msg.CctxHash)) } - if cctx.GetCurrentOutTxParam().OutboundTxTssNonce != msg.OutTxTssNonce { return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, fmt.Sprintf("OutTxTssNonce %d does not match CCTX OutTxTssNonce %d", msg.OutTxTssNonce, cctx.GetCurrentOutTxParam().OutboundTxTssNonce)) } + // get ballot index ballotIndex := msg.Digest() - // Add votes and Set Ballot - ballot, isNew, err := k.zetaObserverKeeper.FindBallot(ctx, ballotIndex, observationChain, observationType) + + // vote on outbound ballot + isFinalized, isNew, ballot, observationChain, err := k.zetaObserverKeeper.VoteOnOutboundBallot( + ctx, + ballotIndex, + msg.OutTxChain, + msg.Status, + msg.Creator) if err != nil { return nil, err } + + // if the ballot is new, set the index to the CCTX if isNew { - observerKeeper.EmitEventBallotCreated(ctx, ballot, msg.ObservedOutTxHash, observationChain.String()) + observerkeeper.EmitEventBallotCreated(ctx, ballot, msg.ObservedOutTxHash, observationChain) // Set this the first time when the ballot is created // The ballot might change if there are more votes in a different outbound ballot for this cctx hash cctx.GetCurrentOutTxParam().OutboundTxBallotIndex = ballotIndex - //k.SetCctxAndNonceToCctxAndInTxHashToCctx(ctx, cctx) - } - // AddVoteToBallot adds a vote and sets the ballot - ballot, err = k.zetaObserverKeeper.AddVoteToBallot(ctx, ballot, msg.Creator, observerTypes.ConvertReceiveStatusToVoteType(msg.Status)) - if err != nil { - return nil, err } - ballot, isFinalizedInThisBlock := k.zetaObserverKeeper.CheckIfFinalizingVote(ctx, ballot) - if !isFinalizedInThisBlock { - // Return nil here to add vote to ballot and commit state + // if not finalized commit state here + if !isFinalized { return &types.MsgVoteOnObservedOutboundTxResponse{}, nil } - if ballot.BallotStatus != observerTypes.BallotStatus_BallotFinalized_FailureObservation { + + // if ballot successful, the value received should be the out tx amount + if ballot.BallotStatus != observertypes.BallotStatus_BallotFinalized_FailureObservation { if !msg.ValueReceived.Equal(cctx.GetCurrentOutTxParam().Amount) { log.Error().Msgf("VoteOnObservedOutboundTx: Mint mismatch: %s value received vs %s cctx amount", msg.ValueReceived, @@ -140,15 +126,12 @@ func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.Ms return nil, types.ErrCannotFindTSSKeys } - // FinalizeOutbound sets final status for a successful vote - // FinalizeOutbound updates CCTX Prices and Nonce for a revert - tmpCtx, commit := ctx.CacheContext() err = func() error { //err = FinalizeOutbound(k, ctx, &cctx, msg, ballot.BallotStatus) cctx.GetCurrentOutTxParam().OutboundTxObservedExternalHeight = msg.ObservedOutTxBlockHeight oldStatus := cctx.CctxStatus.Status switch ballot.BallotStatus { - case observerTypes.BallotStatus_BallotFinalized_SuccessObservation: + case observertypes.BallotStatus_BallotFinalized_SuccessObservation: switch oldStatus { case types.CctxStatus_PendingRevert: cctx.CctxStatus.ChangeStatus(types.CctxStatus_Reverted, "") @@ -157,7 +140,7 @@ func (k msgServer) VoteOnObservedOutboundTx(goCtx context.Context, msg *types.Ms } newStatus := cctx.CctxStatus.Status.String() EmitOutboundSuccess(tmpCtx, msg, oldStatus.String(), newStatus, cctx) - case observerTypes.BallotStatus_BallotFinalized_FailureObservation: + case observertypes.BallotStatus_BallotFinalized_FailureObservation: if msg.CoinType == common.CoinType_Cmd || common.IsZetaChain(cctx.InboundTxParams.SenderChainId) { // 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.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, "") diff --git a/x/crosschain/types/expected_keepers.go b/x/crosschain/types/expected_keepers.go index 47db90184e..b759358549 100644 --- a/x/crosschain/types/expected_keepers.go +++ b/x/crosschain/types/expected_keepers.go @@ -103,6 +103,13 @@ type ZetaObserverKeeper interface { ballotIndex string, inTxHash string, ) (bool, error) + VoteOnOutboundBallot( + ctx sdk.Context, + ballotIndex string, + outTxChainID int64, + receiveStatus common.ReceiveStatus, + voter string, + ) (bool, bool, observertypes.Ballot, string, error) } type FungibleKeeper interface { diff --git a/x/observer/keeper/vote_outbound.go b/x/observer/keeper/vote_outbound.go new file mode 100644 index 0000000000..efa082ab43 --- /dev/null +++ b/x/observer/keeper/vote_outbound.go @@ -0,0 +1,52 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/zeta-chain/zetacore/common" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" +) + +// VoteOnOutboundBallot 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 +// reached, the ballot is finalized. +// returns if the vote is finalized, if the ballot is new, the ballot status and the name of the observation chain +func (k Keeper) VoteOnOutboundBallot( + ctx sdk.Context, + ballotIndex string, + outTxChainID int64, + receiveStatus common.ReceiveStatus, + voter string, +) (isFinalized bool, isNew bool, ballotStatus observertypes.Ballot, observationChainName string, err error) { + // Observer Chain already checked then inbound is created + /* EDGE CASE : Params updated in during the finalization process + i.e Inbound has been finalized but outbound is still pending + */ + observationChain := k.GetParams(ctx).GetChainFromChainID(outTxChainID) + if observationChain == nil { + return false, false, ballotStatus, "", observertypes.ErrSupportedChains + } + if observertypes.CheckReceiveStatus(receiveStatus) != nil { + return false, false, ballotStatus, "", err + } + + // check if voter is authorized + if ok := k.IsAuthorized(ctx, voter, observationChain); !ok { + return false, false, ballotStatus, "", observertypes.ErrNotAuthorizedPolicy + } + + // fetch or create ballot + ballot, isNew, err := k.FindBallot(ctx, ballotIndex, observationChain, observertypes.ObservationType_OutBoundTx) + if err != nil { + return false, false, ballotStatus, "", err + } + + // add vote to ballot + ballot, err = k.AddVoteToBallot(ctx, ballot, voter, observertypes.ConvertReceiveStatusToVoteType(receiveStatus)) + if err != nil { + return false, false, ballotStatus, "", err + } + + ballot, isFinalizedInThisBlock := k.CheckIfFinalizingVote(ctx, ballot) + return isFinalizedInThisBlock, isNew, ballot, observationChain.String(), nil +} From c6abd294a5ffe6fc8585f58e2621867bfde316c8 Mon Sep 17 00:00:00 2001 From: lumtis Date: Tue, 2 Jan 2024 14:55:32 +0100 Subject: [PATCH 08/24] update mocks --- testutil/keeper/mocks/crosschain/account.go | 2 +- testutil/keeper/mocks/crosschain/bank.go | 2 +- testutil/keeper/mocks/crosschain/fungible.go | 2 +- testutil/keeper/mocks/crosschain/observer.go | 51 +++++++++++++++++++- testutil/keeper/mocks/crosschain/staking.go | 2 +- testutil/keeper/mocks/fungible/account.go | 2 +- testutil/keeper/mocks/fungible/bank.go | 2 +- testutil/keeper/mocks/fungible/evm.go | 2 +- testutil/keeper/mocks/fungible/observer.go | 2 +- 9 files changed, 58 insertions(+), 9 deletions(-) diff --git a/testutil/keeper/mocks/crosschain/account.go b/testutil/keeper/mocks/crosschain/account.go index c54fb001d8..274a79766d 100644 --- a/testutil/keeper/mocks/crosschain/account.go +++ b/testutil/keeper/mocks/crosschain/account.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.39.1. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/crosschain/bank.go b/testutil/keeper/mocks/crosschain/bank.go index 76bacb53a8..278cccb833 100644 --- a/testutil/keeper/mocks/crosschain/bank.go +++ b/testutil/keeper/mocks/crosschain/bank.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.39.1. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/crosschain/fungible.go b/testutil/keeper/mocks/crosschain/fungible.go index 67cd5c70b6..de813beb8e 100644 --- a/testutil/keeper/mocks/crosschain/fungible.go +++ b/testutil/keeper/mocks/crosschain/fungible.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.39.1. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/crosschain/observer.go b/testutil/keeper/mocks/crosschain/observer.go index 5e2f2c3ac6..e17042337f 100644 --- a/testutil/keeper/mocks/crosschain/observer.go +++ b/testutil/keeper/mocks/crosschain/observer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.39.1. DO NOT EDIT. package mocks @@ -876,6 +876,55 @@ func (_m *CrosschainObserverKeeper) VoteOnInboundBallot(ctx types.Context, sende return r0, r1 } +// VoteOnOutboundBallot provides a mock function with given fields: ctx, ballotIndex, outTxChainID, receiveStatus, voter +func (_m *CrosschainObserverKeeper) VoteOnOutboundBallot(ctx types.Context, ballotIndex string, outTxChainID int64, receiveStatus common.ReceiveStatus, voter string) (bool, bool, observertypes.Ballot, string, error) { + ret := _m.Called(ctx, ballotIndex, outTxChainID, receiveStatus, voter) + + if len(ret) == 0 { + panic("no return value specified for VoteOnOutboundBallot") + } + + var r0 bool + var r1 bool + var r2 observertypes.Ballot + var r3 string + var r4 error + if rf, ok := ret.Get(0).(func(types.Context, string, int64, common.ReceiveStatus, string) (bool, bool, observertypes.Ballot, string, error)); ok { + return rf(ctx, ballotIndex, outTxChainID, receiveStatus, voter) + } + if rf, ok := ret.Get(0).(func(types.Context, string, int64, common.ReceiveStatus, string) bool); ok { + r0 = rf(ctx, ballotIndex, outTxChainID, receiveStatus, voter) + } else { + r0 = ret.Get(0).(bool) + } + + if rf, ok := ret.Get(1).(func(types.Context, string, int64, common.ReceiveStatus, string) bool); ok { + r1 = rf(ctx, ballotIndex, outTxChainID, receiveStatus, voter) + } else { + r1 = ret.Get(1).(bool) + } + + if rf, ok := ret.Get(2).(func(types.Context, string, int64, common.ReceiveStatus, string) observertypes.Ballot); ok { + r2 = rf(ctx, ballotIndex, outTxChainID, receiveStatus, voter) + } else { + r2 = ret.Get(2).(observertypes.Ballot) + } + + if rf, ok := ret.Get(3).(func(types.Context, string, int64, common.ReceiveStatus, string) string); ok { + r3 = rf(ctx, ballotIndex, outTxChainID, receiveStatus, voter) + } else { + r3 = ret.Get(3).(string) + } + + if rf, ok := ret.Get(4).(func(types.Context, string, int64, common.ReceiveStatus, string) error); ok { + r4 = rf(ctx, ballotIndex, outTxChainID, receiveStatus, voter) + } else { + r4 = ret.Error(4) + } + + return r0, r1, r2, r3, r4 +} + // NewCrosschainObserverKeeper creates a new instance of CrosschainObserverKeeper. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewCrosschainObserverKeeper(t interface { diff --git a/testutil/keeper/mocks/crosschain/staking.go b/testutil/keeper/mocks/crosschain/staking.go index a72a747e5a..772bb09971 100644 --- a/testutil/keeper/mocks/crosschain/staking.go +++ b/testutil/keeper/mocks/crosschain/staking.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.39.1. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/fungible/account.go b/testutil/keeper/mocks/fungible/account.go index 0522e833b4..94b7a84d75 100644 --- a/testutil/keeper/mocks/fungible/account.go +++ b/testutil/keeper/mocks/fungible/account.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.39.1. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/fungible/bank.go b/testutil/keeper/mocks/fungible/bank.go index 5b9fb0dd04..d44da595c0 100644 --- a/testutil/keeper/mocks/fungible/bank.go +++ b/testutil/keeper/mocks/fungible/bank.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.39.1. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/fungible/evm.go b/testutil/keeper/mocks/fungible/evm.go index f42cc011a3..64c041b22d 100644 --- a/testutil/keeper/mocks/fungible/evm.go +++ b/testutil/keeper/mocks/fungible/evm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.39.1. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/fungible/observer.go b/testutil/keeper/mocks/fungible/observer.go index 28fcbba60a..2147bac9b5 100644 --- a/testutil/keeper/mocks/fungible/observer.go +++ b/testutil/keeper/mocks/fungible/observer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.38.0. DO NOT EDIT. +// Code generated by mockery v2.39.1. DO NOT EDIT. package mocks From a37bc8a8b1a3acca850bbaab56cace1e44e9010c Mon Sep 17 00:00:00 2001 From: lumtis Date: Sun, 4 Feb 2024 15:59:25 -0800 Subject: [PATCH 09/24] refactor finalized check --- x/crosschain/keeper/msg_server_vote_inbound_tx.go | 7 +++++++ x/observer/keeper/vote_inbound.go | 4 ---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index 366636fab5..34e71be9b0 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -2,6 +2,8 @@ package keeper import ( "context" + errorsmod "cosmossdk.io/errors" + "fmt" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/zeta-chain/zetacore/common" @@ -55,6 +57,11 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg ctx := sdk.UnwrapSDKContext(goCtx) index := msg.Digest() + // Check if the inbound has already been processed. + if k.IsFinalizedInbound(ctx, msg.InTxHash, msg.SenderChainId, msg.EventIndex) { + return nil, errorsmod.Wrap(types.ErrObservedTxAlreadyFinalized, fmt.Sprintf("InTxHash:%s, SenderChainID:%d, EventIndex:%d", msg.InTxHash, msg.SenderChainId, msg.EventIndex)) + } + // vote on inbound ballot finalized, err := k.zetaObserverKeeper.VoteOnInboundBallot( ctx, diff --git a/x/observer/keeper/vote_inbound.go b/x/observer/keeper/vote_inbound.go index da5744b5cd..f663a9b768 100644 --- a/x/observer/keeper/vote_inbound.go +++ b/x/observer/keeper/vote_inbound.go @@ -70,10 +70,6 @@ func (k Keeper) VoteOnInboundBallot( return false, err } if isNew { - // Check if the inbound has already been processed. - //if k.IsFinalizedInbound(ctx, msg.InTxHash, msg.SenderChainId, msg.EventIndex) { - // return false, errorsmod.Wrap(types.ErrObservedTxAlreadyFinalized, fmt.Sprintf("InTxHash:%s, SenderChainID:%d, EventIndex:%d", msg.InTxHash, msg.SenderChainId, msg.EventIndex)) - //} EmitEventBallotCreated(ctx, ballot, inTxHash, senderChain.String()) } From d1932a0cdbcd2b3cf1ce8476406925b967970abc Mon Sep 17 00:00:00 2001 From: lumtis Date: Sun, 4 Feb 2024 16:03:35 -0800 Subject: [PATCH 10/24] make generate --- x/crosschain/keeper/msg_server_vote_inbound_tx.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index 34e71be9b0..3d420d095c 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -2,9 +2,10 @@ package keeper import ( "context" - errorsmod "cosmossdk.io/errors" "fmt" + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/x/crosschain/types" From 4d15fccf4ac12c3b850260ae00457588b492d8be Mon Sep 17 00:00:00 2001 From: lumtis Date: Tue, 20 Feb 2024 15:40:31 +0100 Subject: [PATCH 11/24] initialize vote inbound tests --- x/crosschain/keeper/evm_hooks.go | 2 +- x/crosschain/types/errors.go | 5 - x/observer/keeper/vote_inbound.go | 23 ++- x/observer/keeper/vote_inbound_test.go | 208 +++++++++++++++++++++++++ x/observer/types/ballot.go | 2 +- x/observer/types/errors.go | 24 +-- 6 files changed, 233 insertions(+), 31 deletions(-) create mode 100644 x/observer/keeper/vote_inbound_test.go diff --git a/x/crosschain/keeper/evm_hooks.go b/x/crosschain/keeper/evm_hooks.go index ff5b127534..7eca564f3a 100644 --- a/x/crosschain/keeper/evm_hooks.go +++ b/x/crosschain/keeper/evm_hooks.go @@ -216,7 +216,7 @@ func (k Keeper) ProcessZetaSentEvent(ctx sdk.Context, event *connectorzevm.ZetaC // Validation if we want to send ZETA to an external chain, but there is no ZETA token. chainParams, found := k.zetaObserverKeeper.GetChainParamsByChainID(ctx, receiverChain.ChainId) if !found { - return types.ErrNotFoundChainParams + return observertypes.ErrChainParamsNotFound } if receiverChain.IsExternalChain() && chainParams.ZetaTokenContractAddress == "" { return types.ErrUnableToSendCoinType diff --git a/x/crosschain/types/errors.go b/x/crosschain/types/errors.go index 680e9b6096..2c5a595eb5 100644 --- a/x/crosschain/types/errors.go +++ b/x/crosschain/types/errors.go @@ -7,7 +7,6 @@ import ( var ( ErrUnsupportedChain = errorsmod.Register(ModuleName, 1102, "chain parse error") ErrInvalidChainID = errorsmod.Register(ModuleName, 1101, "chain id cannot be negative") - ErrInvalidPubKeySet = errorsmod.Register(ModuleName, 1106, "invalid pubkeyset") ErrUnableToGetGasPrice = errorsmod.Register(ModuleName, 1107, "unable to get gas price") ErrNotEnoughZetaBurnt = errorsmod.Register(ModuleName, 1109, "not enough zeta burnt") ErrCannotFindReceiverNonce = errorsmod.Register(ModuleName, 1110, "cannot find receiver chain nonce") @@ -15,11 +14,9 @@ var ( ErrUnableToParseAddress = errorsmod.Register(ModuleName, 1115, "cannot parse address and data") ErrCannotProcessWithdrawal = errorsmod.Register(ModuleName, 1116, "cannot process withdrawal event") ErrForeignCoinNotFound = errorsmod.Register(ModuleName, 1118, "foreign coin not found for sender chain") - ErrNotEnoughPermissions = errorsmod.Register(ModuleName, 1119, "not enough permissions for current actions") ErrCannotFindPendingNonces = errorsmod.Register(ModuleName, 1121, "cannot find pending nonces") ErrCannotFindTSSKeys = errorsmod.Register(ModuleName, 1122, "cannot find TSS keys") ErrNonceMismatch = errorsmod.Register(ModuleName, 1123, "nonce mismatch") - ErrNotFoundChainParams = errorsmod.Register(ModuleName, 1126, "not found chain chain params") ErrUnableToSendCoinType = errorsmod.Register(ModuleName, 1127, "unable to send this coin type to a receiver chain") ErrInvalidAddress = errorsmod.Register(ModuleName, 1128, "invalid address") ErrDeployContract = errorsmod.Register(ModuleName, 1129, "unable to deploy contract") @@ -44,6 +41,4 @@ var ( ErrUnableProcessRefund = errorsmod.Register(ModuleName, 1148, "unable to process refund") ErrUnableToFindZetaAccounting = errorsmod.Register(ModuleName, 1149, "unable to find zeta accounting") ErrInsufficientZetaAmount = errorsmod.Register(ModuleName, 1150, "insufficient zeta amount") - - ErrProcessingZRC20Withdrawal = errorsmod.Register(ModuleName, 1151, "error processing zrc20 withdrawal") ) diff --git a/x/observer/keeper/vote_inbound.go b/x/observer/keeper/vote_inbound.go index f663a9b768..85d8e7ff75 100644 --- a/x/observer/keeper/vote_inbound.go +++ b/x/observer/keeper/vote_inbound.go @@ -6,8 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/zeta-chain/zetacore/common" - "github.com/zeta-chain/zetacore/x/crosschain/types" - observertypes "github.com/zeta-chain/zetacore/x/observer/types" + "github.com/zeta-chain/zetacore/x/observer/types" ) // VoteOnInboundBallot casts a vote on an inbound transaction observed on a connected chain. If this @@ -23,7 +22,7 @@ func (k Keeper) VoteOnInboundBallot( inTxHash string, ) (bool, error) { if !k.IsInboundEnabled(ctx) { - return false, types.ErrNotEnoughPermissions + return false, types.ErrInboundDisabled } // makes sure we are getting only supported chains @@ -31,25 +30,25 @@ func (k Keeper) VoteOnInboundBallot( // this function returns nil senderChain := k.GetSupportedChainFromChainID(ctx, senderChainID) if senderChain == nil { - return false, sdkerrors.Wrap(types.ErrUnsupportedChain, fmt.Sprintf( + return false, sdkerrors.Wrap(types.ErrSupportedChains, fmt.Sprintf( "ChainID %d, Observation %s", senderChainID, - observertypes.ObservationType_InBoundTx.String()), + types.ObservationType_InBoundTx.String()), ) } // checks the voter is authorized to vote on the observation chain if ok := k.IsAuthorized(ctx, voter); !ok { - return false, observertypes.ErrNotAuthorizedPolicy + return false, types.ErrNotObserver } // makes sure we are getting only supported chains receiverChain := k.GetSupportedChainFromChainID(ctx, receiverChainID) if receiverChain == nil { - return false, sdkerrors.Wrap(types.ErrUnsupportedChain, fmt.Sprintf( + return false, sdkerrors.Wrap(types.ErrSupportedChains, fmt.Sprintf( "ChainID %d, Observation %s", receiverChain.ChainId, - observertypes.ObservationType_InBoundTx.String()), + types.ObservationType_InBoundTx.String()), ) } @@ -57,15 +56,15 @@ func (k Keeper) VoteOnInboundBallot( if receiverChain.IsExternalChain() { coreParams, found := k.GetChainParamsByChainID(ctx, receiverChain.ChainId) if !found { - return false, types.ErrNotFoundChainParams + return false, types.ErrChainParamsNotFound } if coreParams.ZetaTokenContractAddress == "" && coinType == common.CoinType_Zeta { - return false, types.ErrUnableToSendCoinType + return false, types.ErrInvalidZetaCoinTypes } } // checks against the supported chains list before querying for Ballot - ballot, isNew, err := k.FindBallot(ctx, ballotIndex, senderChain, observertypes.ObservationType_InBoundTx) + ballot, isNew, err := k.FindBallot(ctx, ballotIndex, senderChain, types.ObservationType_InBoundTx) if err != nil { return false, err } @@ -74,7 +73,7 @@ func (k Keeper) VoteOnInboundBallot( } // adds a vote and sets the ballot - ballot, err = k.AddVoteToBallot(ctx, ballot, voter, observertypes.VoteType_SuccessObservation) + ballot, err = k.AddVoteToBallot(ctx, ballot, voter, types.VoteType_SuccessObservation) if err != nil { return false, err } diff --git a/x/observer/keeper/vote_inbound_test.go b/x/observer/keeper/vote_inbound_test.go new file mode 100644 index 0000000000..354b86c2ff --- /dev/null +++ b/x/observer/keeper/vote_inbound_test.go @@ -0,0 +1,208 @@ +package keeper_test + +import ( + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/common" + "github.com/zeta-chain/zetacore/testutil/sample" + "testing" + + keepertest "github.com/zeta-chain/zetacore/testutil/keeper" + "github.com/zeta-chain/zetacore/x/observer/types" +) + +func TestKeeper_VoteOnInboundBallot(t *testing.T) { + + t.Run("fail if inbound not enabled", func(t *testing.T) { + k, ctx := keepertest.ObserverKeeper(t) + + k.SetCrosschainFlags(ctx, types.CrosschainFlags{ + IsInboundEnabled: false, + }) + + _, err := k.VoteOnInboundBallot( + ctx, + getValidEthChainIDWithIndex(t, 0), + common.ZetaPrivnetChain().ChainId, + common.CoinType_ERC20, + sample.AccAddress(), + "index", + "inTxHash", + ) + + require.Error(t, err) + require.ErrorIs(t, err, types.ErrInboundDisabled) + }) + + t.Run("fail if sender chain not supported", func(t *testing.T) { + k, ctx := keepertest.ObserverKeeper(t) + + k.SetCrosschainFlags(ctx, types.CrosschainFlags{ + IsInboundEnabled: true, + }) + k.SetChainParamsList(ctx, types.ChainParamsList{}) + + _, err := k.VoteOnInboundBallot( + ctx, + getValidEthChainIDWithIndex(t, 0), + common.ZetaPrivnetChain().ChainId, + common.CoinType_ERC20, + sample.AccAddress(), + "index", + "inTxHash", + ) + require.Error(t, err) + require.ErrorIs(t, err, types.ErrSupportedChains) + + // set the chain but not supported + k.SetChainParamsList(ctx, types.ChainParamsList{ + ChainParams: []*types.ChainParams{ + { + ChainId: getValidEthChainIDWithIndex(t, 0), + IsSupported: false, + }, + }, + }) + + _, err = k.VoteOnInboundBallot( + ctx, + getValidEthChainIDWithIndex(t, 0), + common.ZetaPrivnetChain().ChainId, + common.CoinType_ERC20, + sample.AccAddress(), + "index", + "inTxHash", + ) + require.Error(t, err) + require.ErrorIs(t, err, types.ErrSupportedChains) + }) + + t.Run("fail if not authorized", func(t *testing.T) { + k, ctx := keepertest.ObserverKeeper(t) + + k.SetCrosschainFlags(ctx, types.CrosschainFlags{ + IsInboundEnabled: true, + }) + k.SetChainParamsList(ctx, types.ChainParamsList{ + ChainParams: []*types.ChainParams{ + { + ChainId: getValidEthChainIDWithIndex(t, 0), + IsSupported: true, + }, + }, + }) + k.SetObserverSet(ctx, types.ObserverSet{}) + + _, err := k.VoteOnInboundBallot( + ctx, + getValidEthChainIDWithIndex(t, 0), + common.ZetaPrivnetChain().ChainId, + common.CoinType_ERC20, + sample.AccAddress(), + "index", + "inTxHash", + ) + require.Error(t, err) + require.ErrorIs(t, err, types.ErrNotObserver) + }) + + t.Run("fail if receiver chain not supported", func(t *testing.T) { + k, ctx := keepertest.ObserverKeeper(t) + + observer := sample.AccAddress() + + k.SetCrosschainFlags(ctx, types.CrosschainFlags{ + IsInboundEnabled: true, + }) + k.SetChainParamsList(ctx, types.ChainParamsList{ + ChainParams: []*types.ChainParams{ + { + ChainId: getValidEthChainIDWithIndex(t, 0), + IsSupported: true, + }, + }, + }) + k.SetObserverSet(ctx, types.ObserverSet{ + ObserverList: []string{observer}, + }) + + _, err := k.VoteOnInboundBallot( + ctx, + getValidEthChainIDWithIndex(t, 0), + common.ZetaPrivnetChain().ChainId, + common.CoinType_ERC20, + observer, + "index", + "inTxHash", + ) + require.Error(t, err) + require.ErrorIs(t, err, types.ErrSupportedChains) + + // set the chain but not supported + k.SetChainParamsList(ctx, types.ChainParamsList{ + ChainParams: []*types.ChainParams{ + { + ChainId: getValidEthChainIDWithIndex(t, 0), + IsSupported: true, + }, + { + ChainId: common.ZetaPrivnetChain().ChainId, + IsSupported: false, + }, + }, + }) + + _, err = k.VoteOnInboundBallot( + ctx, + getValidEthChainIDWithIndex(t, 0), + common.ZetaPrivnetChain().ChainId, + common.CoinType_ERC20, + observer, + "index", + "inTxHash", + ) + require.Error(t, err) + require.ErrorIs(t, err, types.ErrSupportedChains) + }) + + t.Run("fail if inbound contain ZETA but receiver chain doesn't support ZETA", func(t *testing.T) { + k, ctx := keepertest.ObserverKeeper(t) + + observer := sample.AccAddress() + + k.SetCrosschainFlags(ctx, types.CrosschainFlags{ + IsInboundEnabled: true, + }) + k.SetChainParamsList(ctx, types.ChainParamsList{ + ChainParams: []*types.ChainParams{ + { + ChainId: getValidEthChainIDWithIndex(t, 0), + IsSupported: true, + }, + { + ChainId: common.ZetaPrivnetChain().ChainId, + IsSupported: true, + ZetaTokenContractAddress: "", + }, + }, + }) + k.SetObserverSet(ctx, types.ObserverSet{ + ObserverList: []string{observer}, + }) + + _, err := k.VoteOnInboundBallot( + ctx, + getValidEthChainIDWithIndex(t, 0), + common.ZetaPrivnetChain().ChainId, + common.CoinType_Zeta, + sample.AccAddress(), + "index", + "inTxHash", + ) + require.Error(t, err) + require.ErrorIs(t, err, types.ErrInvalidZetaCoinTypes) + }) + + t.Run("can add vote to inbound ballot", func(t *testing.T) { + + }) +} diff --git a/x/observer/types/ballot.go b/x/observer/types/ballot.go index bc6bfd66ee..10f21119d1 100644 --- a/x/observer/types/ballot.go +++ b/x/observer/types/ballot.go @@ -34,7 +34,7 @@ func (m Ballot) GetVoterIndex(address string) int { return index } -// Is finalzing vote checks sets the ballot to a final status if enough votes have been added +// IsFinalizingVote checks sets the ballot to a final status if enough votes have been added // If it has already been finalized it returns false // It enough votes have not been added it returns false func (m Ballot) IsFinalizingVote() (Ballot, bool) { diff --git a/x/observer/types/errors.go b/x/observer/types/errors.go index 0add35d4ce..4d5fd240a5 100644 --- a/x/observer/types/errors.go +++ b/x/observer/types/errors.go @@ -12,17 +12,15 @@ var ( ErrSupportedChains = errorsmod.Register(ModuleName, 1102, "chain not supported") ErrInvalidStatus = errorsmod.Register(ModuleName, 1103, "invalid Voting Status") - ErrObserverNotPresent = errorsmod.Register(ModuleName, 1105, "observer for type and observation does not exist") - ErrNotValidator = errorsmod.Register(ModuleName, 1106, "user needs to be a validator before applying to become an observer") - ErrValidatorStatus = errorsmod.Register(ModuleName, 1107, "corresponding validator needs to be bonded and not jailed") - ErrInvalidAddress = errorsmod.Register(ModuleName, 1108, "invalid Address") - ErrSelfDelegation = errorsmod.Register(ModuleName, 1109, "self Delegation for operator not found") - ErrCheckObserverDelegation = errorsmod.Register(ModuleName, 1110, "observer delegation not sufficient") - ErrNotAuthorizedPolicy = errorsmod.Register(ModuleName, 1111, "msg Sender is not the authorized policy") - ErrKeygenNotFound = errorsmod.Register(ModuleName, 1113, "Keygen not found, Keygen block can only be updated,New keygen cannot be set") - ErrKeygenBlockTooLow = errorsmod.Register(ModuleName, 1114, "please set a block number at-least 10 blocks higher than the current block number") - ErrKeygenCompleted = errorsmod.Register(ModuleName, 1115, "keygen already completed") - ErrNotAuthorized = errorsmod.Register(ModuleName, 1116, "not authorized") + ErrNotValidator = errorsmod.Register(ModuleName, 1106, "user needs to be a validator before applying to become an observer") + ErrValidatorStatus = errorsmod.Register(ModuleName, 1107, "corresponding validator needs to be bonded and not jailed") + ErrInvalidAddress = errorsmod.Register(ModuleName, 1108, "invalid Address") + ErrSelfDelegation = errorsmod.Register(ModuleName, 1109, "self Delegation for operator not found") + ErrNotAuthorizedPolicy = errorsmod.Register(ModuleName, 1111, "msg Sender is not the authorized policy") + ErrKeygenNotFound = errorsmod.Register(ModuleName, 1113, "Keygen not found, Keygen block can only be updated,New keygen cannot be set") + ErrKeygenBlockTooLow = errorsmod.Register(ModuleName, 1114, "please set a block number at-least 10 blocks higher than the current block number") + ErrKeygenCompleted = errorsmod.Register(ModuleName, 1115, "keygen already completed") + ErrNotAuthorized = errorsmod.Register(ModuleName, 1116, "not authorized") ErrBlockAlreadyExist = errorsmod.Register(ModuleName, 1119, "block already exists") ErrNoParentHash = errorsmod.Register(ModuleName, 1120, "no parent hash") @@ -38,5 +36,7 @@ var ( ErrObserverSetNotFound = errorsmod.Register(ModuleName, 1130, "observer set not found") ErrTssNotFound = errorsmod.Register(ModuleName, 1131, "tss not found") - ErrInboundDisabled = errorsmod.Register(ModuleName, 1132, "inbound tx processing is disabled") + ErrInboundDisabled = errorsmod.Register(ModuleName, 1132, "inbound tx processing is disabled") + ErrInvalidZetaCoinTypes = errorsmod.Register(ModuleName, 1133, "invalid zeta coin types") + ErrNotObserver = errorsmod.Register(ModuleName, 1134, "sender is not an observer") ) From e5930be276b7193c74dd33a25d2c3e67dac10b65 Mon Sep 17 00:00:00 2001 From: lumtis Date: Tue, 20 Feb 2024 15:49:50 +0100 Subject: [PATCH 12/24] add sdk keepers in observer testutil --- testutil/keeper/observer.go | 4 ++-- x/observer/keeper/chain_nonces_test.go | 6 +++--- x/observer/keeper/chain_params_test.go | 8 ++++---- x/observer/keeper/grpc_query_blame_test.go | 12 ++++++------ x/observer/keeper/grpc_query_nonces_test.go | 4 ++-- .../keeper/msg_server_add_block_header_test.go | 2 +- .../msg_server_remove_chain_params_test.go | 6 +++--- x/observer/keeper/msg_server_test.go | 14 -------------- .../msg_server_update_chain_params_test.go | 4 ++-- .../msg_server_update_crosschain_flags_test.go | 4 ++-- .../keeper/msg_server_update_observer_test.go | 16 ++++++++-------- x/observer/keeper/nonce_to_cctx_test.go | 6 +++--- x/observer/keeper/nonces_test.go | 6 +++--- x/observer/keeper/observer_set_test.go | 14 +++++++------- x/observer/keeper/pending_nonces_test.go | 6 +++--- x/observer/keeper/tss_funds_migrator_test.go | 4 ++-- x/observer/keeper/utils_test.go | 6 +++--- x/observer/keeper/vote_inbound_test.go | 10 +++++----- 18 files changed, 59 insertions(+), 73 deletions(-) delete mode 100644 x/observer/keeper/msg_server_test.go diff --git a/testutil/keeper/observer.go b/testutil/keeper/observer.go index 946dac84c6..40f46bee8d 100644 --- a/testutil/keeper/observer.go +++ b/testutil/keeper/observer.go @@ -41,7 +41,7 @@ func initObserverKeeper( } // ObserverKeeper instantiates an observer keeper for testing purposes -func ObserverKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { +func ObserverKeeper(t testing.TB) (*keeper.Keeper, sdk.Context, SDKKeepers) { storeKey := sdk.NewKVStoreKey(types.StoreKey) memStoreKey := storetypes.NewMemoryStoreKey(types.MemStoreKey) @@ -77,5 +77,5 @@ func ObserverKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { k.SetParams(ctx, types.DefaultParams()) - return k, ctx + return k, ctx, sdkKeepers } diff --git a/x/observer/keeper/chain_nonces_test.go b/x/observer/keeper/chain_nonces_test.go index 0c511d3f79..d133c7fc53 100644 --- a/x/observer/keeper/chain_nonces_test.go +++ b/x/observer/keeper/chain_nonces_test.go @@ -10,7 +10,7 @@ import ( func TestKeeper_GetChainNonces(t *testing.T) { t.Run("Get chain nonces", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) chainNoncesList := sample.ChainNoncesList(t, 10) for _, n := range chainNoncesList { k.SetChainNonces(ctx, n) @@ -22,7 +22,7 @@ func TestKeeper_GetChainNonces(t *testing.T) { } }) t.Run("Get chain nonces not found", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) chainNoncesList := sample.ChainNoncesList(t, 10) for _, n := range chainNoncesList { k.SetChainNonces(ctx, n) @@ -31,7 +31,7 @@ func TestKeeper_GetChainNonces(t *testing.T) { require.False(t, found) }) t.Run("Get all chain nonces", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) chainNoncesList := sample.ChainNoncesList(t, 10) for _, n := range chainNoncesList { k.SetChainNonces(ctx, n) diff --git a/x/observer/keeper/chain_params_test.go b/x/observer/keeper/chain_params_test.go index c9142b7526..9bf63cd65b 100644 --- a/x/observer/keeper/chain_params_test.go +++ b/x/observer/keeper/chain_params_test.go @@ -12,7 +12,7 @@ import ( func TestKeeper_GetSupportedChainFromChainID(t *testing.T) { t.Run("return nil if chain not found", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) // no core params list require.Nil(t, k.GetSupportedChainFromChainID(ctx, getValidEthChainIDWithIndex(t, 0))) @@ -31,7 +31,7 @@ func TestKeeper_GetSupportedChainFromChainID(t *testing.T) { }) t.Run("return chain if chain found", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) chainID := getValidEthChainIDWithIndex(t, 0) setSupportedChain(ctx, *k, getValidEthChainIDWithIndex(t, 1), chainID) chain := k.GetSupportedChainFromChainID(ctx, chainID) @@ -42,12 +42,12 @@ func TestKeeper_GetSupportedChainFromChainID(t *testing.T) { func TestKeeper_GetSupportedChains(t *testing.T) { t.Run("return empty list if no core params list", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) require.Empty(t, k.GetSupportedChains(ctx)) }) t.Run("return list containing supported chains", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) require.Greater(t, len(common.ExternalChainList()), 5) supported1 := common.ExternalChainList()[0] diff --git a/x/observer/keeper/grpc_query_blame_test.go b/x/observer/keeper/grpc_query_blame_test.go index 8e66e3a2da..141246af47 100644 --- a/x/observer/keeper/grpc_query_blame_test.go +++ b/x/observer/keeper/grpc_query_blame_test.go @@ -12,7 +12,7 @@ import ( ) func TestKeeper_BlameByIdentifier(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) var chainId int64 = 97 var nonce uint64 = 101 digest := "85f5e10431f69bc2a14046a13aabaefc660103b6de7a84f75c4b96181d03f0b5" @@ -31,7 +31,7 @@ func TestKeeper_BlameByIdentifier(t *testing.T) { } func TestKeeper_BlameByChainAndNonce(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) var chainId int64 = 97 var nonce uint64 = 101 digest := "85f5e10431f69bc2a14046a13aabaefc660103b6de7a84f75c4b96181d03f0b5" @@ -52,7 +52,7 @@ func TestKeeper_BlameByChainAndNonce(t *testing.T) { func TestKeeper_BlameAll(t *testing.T) { t.Run("GetBlameRecord by limit ", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) blameList := sample.BlameRecordsList(t, 10) for _, record := range blameList { k.SetBlame(ctx, record) @@ -69,7 +69,7 @@ func TestKeeper_BlameAll(t *testing.T) { require.Equal(t, len(blameList), int(pageRes.Total)) }) t.Run("GetBlameRecord by offset ", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) blameList := sample.BlameRecordsList(t, 20) offset := 10 for _, record := range blameList { @@ -88,7 +88,7 @@ func TestKeeper_BlameAll(t *testing.T) { require.Equal(t, len(blameList), int(pageRes.Total)) }) t.Run("GetAllBlameRecord", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) blameList := sample.BlameRecordsList(t, 100) for _, record := range blameList { k.SetBlame(ctx, record) @@ -103,7 +103,7 @@ func TestKeeper_BlameAll(t *testing.T) { require.Equal(t, blameList, rst) }) t.Run("Get no records if nothing is set", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) rst := k.GetAllBlame(ctx) require.Len(t, rst, 0) }) diff --git a/x/observer/keeper/grpc_query_nonces_test.go b/x/observer/keeper/grpc_query_nonces_test.go index 6ec06efd28..74f4777b5d 100644 --- a/x/observer/keeper/grpc_query_nonces_test.go +++ b/x/observer/keeper/grpc_query_nonces_test.go @@ -14,7 +14,7 @@ import ( ) func TestChainNoncesQuerySingle(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) wctx := sdk.WrapSDKContext(ctx) chainNonces := sample.ChainNoncesList(t, 2) for _, nonce := range chainNonces { @@ -59,7 +59,7 @@ func TestChainNoncesQuerySingle(t *testing.T) { } func TestChainNoncesQueryPaginated(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) wctx := sdk.WrapSDKContext(ctx) chainNonces := sample.ChainNoncesList(t, 5) for _, nonce := range chainNonces { diff --git a/x/observer/keeper/msg_server_add_block_header_test.go b/x/observer/keeper/msg_server_add_block_header_test.go index 34bde9c115..85a7ec505b 100644 --- a/x/observer/keeper/msg_server_add_block_header_test.go +++ b/x/observer/keeper/msg_server_add_block_header_test.go @@ -149,7 +149,7 @@ func TestMsgServer_AddBlockHeader(t *testing.T) { } for _, tc := range tt { t.Run(tc.name, func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) srv := keeper.NewMsgServerImpl(*k) k.SetObserverSet(ctx, types.ObserverSet{ ObserverList: []string{observerAddress.String()}, diff --git a/x/observer/keeper/msg_server_remove_chain_params_test.go b/x/observer/keeper/msg_server_remove_chain_params_test.go index d99b301403..238f86e256 100644 --- a/x/observer/keeper/msg_server_remove_chain_params_test.go +++ b/x/observer/keeper/msg_server_remove_chain_params_test.go @@ -14,7 +14,7 @@ import ( func TestMsgServer_RemoveChainParams(t *testing.T) { t.Run("can update chain params", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) srv := keeper.NewMsgServerImpl(*k) chain1 := common.ExternalChainList()[0].ChainId @@ -75,7 +75,7 @@ func TestMsgServer_RemoveChainParams(t *testing.T) { }) t.Run("cannot remove chain params if not authorized", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) srv := keeper.NewMsgServerImpl(*k) _, err := srv.UpdateChainParams(sdk.WrapSDKContext(ctx), &types.MsgUpdateChainParams{ @@ -97,7 +97,7 @@ func TestMsgServer_RemoveChainParams(t *testing.T) { }) t.Run("cannot remove if chain ID not found", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) srv := keeper.NewMsgServerImpl(*k) // set admin diff --git a/x/observer/keeper/msg_server_test.go b/x/observer/keeper/msg_server_test.go deleted file mode 100644 index 98911a5a70..0000000000 --- a/x/observer/keeper/msg_server_test.go +++ /dev/null @@ -1,14 +0,0 @@ -package keeper - -import ( - "context" - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/zeta-chain/zetacore/x/observer/types" -) - -func setupMsgServer(t testing.TB) (types.MsgServer, context.Context) { - k, ctx := SetupKeeper(t) - return NewMsgServerImpl(*k), sdk.WrapSDKContext(ctx) -} diff --git a/x/observer/keeper/msg_server_update_chain_params_test.go b/x/observer/keeper/msg_server_update_chain_params_test.go index 7b2f8a5cb3..1e4a707aeb 100644 --- a/x/observer/keeper/msg_server_update_chain_params_test.go +++ b/x/observer/keeper/msg_server_update_chain_params_test.go @@ -14,7 +14,7 @@ import ( func TestMsgServer_UpdateChainParams(t *testing.T) { t.Run("can update chain params", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) srv := keeper.NewMsgServerImpl(*k) chain1 := common.ExternalChainList()[0].ChainId @@ -92,7 +92,7 @@ func TestMsgServer_UpdateChainParams(t *testing.T) { }) t.Run("cannot update chain params if not authorized", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) srv := keeper.NewMsgServerImpl(*k) _, err := srv.UpdateChainParams(sdk.WrapSDKContext(ctx), &types.MsgUpdateChainParams{ diff --git a/x/observer/keeper/msg_server_update_crosschain_flags_test.go b/x/observer/keeper/msg_server_update_crosschain_flags_test.go index 555988694c..aaa33f4e23 100644 --- a/x/observer/keeper/msg_server_update_crosschain_flags_test.go +++ b/x/observer/keeper/msg_server_update_crosschain_flags_test.go @@ -26,7 +26,7 @@ func setAdminCrossChainFlags(ctx sdk.Context, k *keeper.Keeper, admin string, gr func TestMsgServer_UpdateCrosschainFlags(t *testing.T) { t.Run("can update crosschain flags", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) srv := keeper.NewMsgServerImpl(*k) admin := sample.AccAddress() @@ -157,7 +157,7 @@ func TestMsgServer_UpdateCrosschainFlags(t *testing.T) { }) t.Run("cannot update crosschain flags if not authorized", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) srv := keeper.NewMsgServerImpl(*k) _, err := srv.UpdateCrosschainFlags(sdk.WrapSDKContext(ctx), &types.MsgUpdateCrosschainFlags{ diff --git a/x/observer/keeper/msg_server_update_observer_test.go b/x/observer/keeper/msg_server_update_observer_test.go index 7fe73734d8..679e9851c5 100644 --- a/x/observer/keeper/msg_server_update_observer_test.go +++ b/x/observer/keeper/msg_server_update_observer_test.go @@ -17,7 +17,7 @@ import ( func TestMsgServer_UpdateObserver(t *testing.T) { t.Run("successfully update tombstoned observer", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) srv := keeper.NewMsgServerImpl(*k) // #nosec G404 test purpose - weak randomness is not an issue here r := rand.New(rand.NewSource(9)) @@ -73,7 +73,7 @@ func TestMsgServer_UpdateObserver(t *testing.T) { }) t.Run("unable to update to a non validator address", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) srv := keeper.NewMsgServerImpl(*k) // #nosec G404 test purpose - weak randomness is not an issue here r := rand.New(rand.NewSource(9)) @@ -122,7 +122,7 @@ func TestMsgServer_UpdateObserver(t *testing.T) { }) t.Run("unable to update tombstoned validator with with non operator account", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) srv := keeper.NewMsgServerImpl(*k) // #nosec G404 test purpose - weak randomness is not an issue here r := rand.New(rand.NewSource(9)) @@ -173,7 +173,7 @@ func TestMsgServer_UpdateObserver(t *testing.T) { require.ErrorIs(t, err, types.ErrUpdateObserver) }) t.Run("unable to update non-tombstoned observer with update reason tombstoned", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) srv := keeper.NewMsgServerImpl(*k) // #nosec G404 test purpose - weak randomness is not an issue here r := rand.New(rand.NewSource(9)) @@ -223,7 +223,7 @@ func TestMsgServer_UpdateObserver(t *testing.T) { require.ErrorIs(t, err, types.ErrUpdateObserver) }) t.Run("unable to update observer with no node account", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) srv := keeper.NewMsgServerImpl(*k) // #nosec G404 test purpose - weak randomness is not an issue here r := rand.New(rand.NewSource(9)) @@ -269,7 +269,7 @@ func TestMsgServer_UpdateObserver(t *testing.T) { require.ErrorIs(t, err, types.ErrNodeAccountNotFound) }) t.Run("unable to update observer when last observer count is missing", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) srv := keeper.NewMsgServerImpl(*k) // #nosec G404 test purpose - weak randomness is not an issue here r := rand.New(rand.NewSource(9)) @@ -314,7 +314,7 @@ func TestMsgServer_UpdateObserver(t *testing.T) { require.ErrorIs(t, err, types.ErrLastObserverCountNotFound) }) t.Run("update observer using admin policy", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) srv := keeper.NewMsgServerImpl(*k) admin := sample.AccAddress() @@ -369,7 +369,7 @@ func TestMsgServer_UpdateObserver(t *testing.T) { require.Equal(t, newOperatorAddress.String(), acc.Operator) }) t.Run("fail to update observer using regular account and update type admin", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) srv := keeper.NewMsgServerImpl(*k) // #nosec G404 test purpose - weak randomness is not an issue here diff --git a/x/observer/keeper/nonce_to_cctx_test.go b/x/observer/keeper/nonce_to_cctx_test.go index 1cbd023fbd..75df5eb311 100644 --- a/x/observer/keeper/nonce_to_cctx_test.go +++ b/x/observer/keeper/nonce_to_cctx_test.go @@ -10,7 +10,7 @@ import ( func TestKeeper_GetNonceToCctx(t *testing.T) { t.Run("Get nonce to cctx", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) nonceToCctxList := sample.NonceToCctxList(t, "sample", 1) for _, n := range nonceToCctxList { k.SetNonceToCctx(ctx, n) @@ -22,7 +22,7 @@ func TestKeeper_GetNonceToCctx(t *testing.T) { } }) t.Run("Get nonce to cctx not found", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) nonceToCctxList := sample.NonceToCctxList(t, "sample", 1) for _, n := range nonceToCctxList { k.SetNonceToCctx(ctx, n) @@ -31,7 +31,7 @@ func TestKeeper_GetNonceToCctx(t *testing.T) { require.False(t, found) }) t.Run("Get all nonce to cctx", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) nonceToCctxList := sample.NonceToCctxList(t, "sample", 10) for _, n := range nonceToCctxList { k.SetNonceToCctx(ctx, n) diff --git a/x/observer/keeper/nonces_test.go b/x/observer/keeper/nonces_test.go index aaf7369df1..aa972eab3e 100644 --- a/x/observer/keeper/nonces_test.go +++ b/x/observer/keeper/nonces_test.go @@ -9,7 +9,7 @@ import ( ) func TestChainNoncesGet(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) items := sample.ChainNoncesList(t, 10) for _, item := range items { k.SetChainNonces(ctx, item) @@ -21,7 +21,7 @@ func TestChainNoncesGet(t *testing.T) { } } func TestChainNoncesRemove(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) items := sample.ChainNoncesList(t, 10) for _, item := range items { k.SetChainNonces(ctx, item) @@ -34,7 +34,7 @@ func TestChainNoncesRemove(t *testing.T) { } func TestChainNoncesGetAll(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) items := sample.ChainNoncesList(t, 10) for _, item := range items { k.SetChainNonces(ctx, item) diff --git a/x/observer/keeper/observer_set_test.go b/x/observer/keeper/observer_set_test.go index ca7212704a..6561405acf 100644 --- a/x/observer/keeper/observer_set_test.go +++ b/x/observer/keeper/observer_set_test.go @@ -10,7 +10,7 @@ import ( func TestKeeper_GetObserverSet(t *testing.T) { t.Run("get observer set", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) os := sample.ObserverSet(10) k.SetObserverSet(ctx, os) tfm, found := k.GetObserverSet(ctx) @@ -21,7 +21,7 @@ func TestKeeper_GetObserverSet(t *testing.T) { func TestKeeper_IsAddressPartOfObserverSet(t *testing.T) { t.Run("address is part of observer set", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) os := sample.ObserverSet(10) k.SetObserverSet(ctx, os) require.True(t, k.IsAddressPartOfObserverSet(ctx, os.ObserverList[0])) @@ -31,7 +31,7 @@ func TestKeeper_IsAddressPartOfObserverSet(t *testing.T) { func TestKeeper_AddObserverToSet(t *testing.T) { t.Run("add observer to set", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) os := sample.ObserverSet(10) k.SetObserverSet(ctx, os) newObserver := sample.AccAddress() @@ -46,7 +46,7 @@ func TestKeeper_AddObserverToSet(t *testing.T) { func TestKeeper_RemoveObserverFromSet(t *testing.T) { t.Run("remove observer from set", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) os := sample.ObserverSet(10) k.SetObserverSet(ctx, os) k.RemoveObserverFromSet(ctx, os.ObserverList[0]) @@ -59,7 +59,7 @@ func TestKeeper_RemoveObserverFromSet(t *testing.T) { func TestKeeper_UpdateObserverAddress(t *testing.T) { t.Run("update observer address", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) oldObserverAddress := sample.AccAddress() newObserverAddress := sample.AccAddress() observerSet := sample.ObserverSet(10) @@ -72,7 +72,7 @@ func TestKeeper_UpdateObserverAddress(t *testing.T) { require.Equal(t, newObserverAddress, observerSet.ObserverList[len(observerSet.ObserverList)-1]) }) t.Run("update observer address long observerList", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) oldObserverAddress := sample.AccAddress() newObserverAddress := sample.AccAddress() observerSet := sample.ObserverSet(10000) @@ -85,7 +85,7 @@ func TestKeeper_UpdateObserverAddress(t *testing.T) { require.Equal(t, newObserverAddress, observerMappers.ObserverList[len(observerMappers.ObserverList)-1]) }) t.Run("update observer address short observerList", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) oldObserverAddress := sample.AccAddress() newObserverAddress := sample.AccAddress() observerSet := sample.ObserverSet(1) diff --git a/x/observer/keeper/pending_nonces_test.go b/x/observer/keeper/pending_nonces_test.go index 0cb61f090d..8ada35c5ba 100644 --- a/x/observer/keeper/pending_nonces_test.go +++ b/x/observer/keeper/pending_nonces_test.go @@ -12,7 +12,7 @@ import ( func TestKeeper_PendingNoncesAll(t *testing.T) { t.Run("Get all pending nonces paginated by limit", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) nonces := sample.PendingNoncesList(t, "sample", 10) sort.SliceStable(nonces, func(i, j int) bool { return nonces[i].ChainId < nonces[j].ChainId @@ -29,7 +29,7 @@ func TestKeeper_PendingNoncesAll(t *testing.T) { require.Equal(t, len(nonces), int(pageRes.Total)) }) t.Run("Get all pending nonces paginated by offset", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) nonces := sample.PendingNoncesList(t, "sample", 42) sort.SliceStable(nonces, func(i, j int) bool { return nonces[i].ChainId < nonces[j].ChainId @@ -48,7 +48,7 @@ func TestKeeper_PendingNoncesAll(t *testing.T) { require.Equal(t, len(nonces), int(pageRes.Total)) }) t.Run("Get all pending nonces ", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) nonces := sample.PendingNoncesList(t, "sample", 10) sort.SliceStable(nonces, func(i, j int) bool { return nonces[i].ChainId < nonces[j].ChainId diff --git a/x/observer/keeper/tss_funds_migrator_test.go b/x/observer/keeper/tss_funds_migrator_test.go index 62d622e179..46c8891ef9 100644 --- a/x/observer/keeper/tss_funds_migrator_test.go +++ b/x/observer/keeper/tss_funds_migrator_test.go @@ -10,7 +10,7 @@ import ( func TestKeeper_GetTssFundMigrator(t *testing.T) { t.Run("Successfully set funds migrator for chain", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) chain := sample.TssFundsMigrator(1) k.SetFundMigrator(ctx, chain) tfm, found := k.GetFundMigrator(ctx, chain.ChainId) @@ -18,7 +18,7 @@ func TestKeeper_GetTssFundMigrator(t *testing.T) { require.Equal(t, chain, tfm) }) t.Run("Verify only one migrator can be created for a chain", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) tfm1 := sample.TssFundsMigrator(1) k.SetFundMigrator(ctx, tfm1) tfm2 := tfm1 diff --git a/x/observer/keeper/utils_test.go b/x/observer/keeper/utils_test.go index 6534fc6200..e68fb2edd7 100644 --- a/x/observer/keeper/utils_test.go +++ b/x/observer/keeper/utils_test.go @@ -43,7 +43,7 @@ func getValidEthChainIDWithIndex(t *testing.T, index int) int64 { func TestKeeper_IsAuthorized(t *testing.T) { t.Run("authorized observer", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) r := rand.New(rand.NewSource(9)) @@ -69,7 +69,7 @@ func TestKeeper_IsAuthorized(t *testing.T) { }) t.Run("not authorized for tombstoned observer", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) r := rand.New(rand.NewSource(9)) @@ -95,7 +95,7 @@ func TestKeeper_IsAuthorized(t *testing.T) { }) t.Run("not authorized for non-validator observer", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) r := rand.New(rand.NewSource(9)) diff --git a/x/observer/keeper/vote_inbound_test.go b/x/observer/keeper/vote_inbound_test.go index 354b86c2ff..7914f52638 100644 --- a/x/observer/keeper/vote_inbound_test.go +++ b/x/observer/keeper/vote_inbound_test.go @@ -13,7 +13,7 @@ import ( func TestKeeper_VoteOnInboundBallot(t *testing.T) { t.Run("fail if inbound not enabled", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) k.SetCrosschainFlags(ctx, types.CrosschainFlags{ IsInboundEnabled: false, @@ -34,7 +34,7 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { }) t.Run("fail if sender chain not supported", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) k.SetCrosschainFlags(ctx, types.CrosschainFlags{ IsInboundEnabled: true, @@ -77,7 +77,7 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { }) t.Run("fail if not authorized", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) k.SetCrosschainFlags(ctx, types.CrosschainFlags{ IsInboundEnabled: true, @@ -106,7 +106,7 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { }) t.Run("fail if receiver chain not supported", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) observer := sample.AccAddress() @@ -165,7 +165,7 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { }) t.Run("fail if inbound contain ZETA but receiver chain doesn't support ZETA", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) observer := sample.AccAddress() From 926e12e77c786be817ea81a71923b48a6c97c097 Mon Sep 17 00:00:00 2001 From: lumtis Date: Tue, 20 Feb 2024 16:52:13 +0100 Subject: [PATCH 13/24] implement mock option for observer --- testutil/keeper/crosschain.go | 2 +- testutil/keeper/mocks/crosschain/account.go | 2 +- testutil/keeper/mocks/crosschain/bank.go | 2 +- testutil/keeper/mocks/crosschain/fungible.go | 2 +- testutil/keeper/mocks/crosschain/observer.go | 2 +- testutil/keeper/mocks/crosschain/staking.go | 2 +- testutil/keeper/mocks/fungible/account.go | 2 +- testutil/keeper/mocks/fungible/bank.go | 2 +- testutil/keeper/mocks/fungible/evm.go | 2 +- testutil/keeper/mocks/fungible/observer.go | 2 +- testutil/keeper/mocks/mocks.go | 15 ++++ testutil/keeper/mocks/observer/slashing.go | 53 ++++++++++++ testutil/keeper/mocks/observer/staking.go | 91 ++++++++++++++++++++ testutil/keeper/observer.go | 79 +++++++++++++++-- 14 files changed, 242 insertions(+), 16 deletions(-) create mode 100644 testutil/keeper/mocks/observer/slashing.go create mode 100644 testutil/keeper/mocks/observer/staking.go diff --git a/testutil/keeper/crosschain.go b/testutil/keeper/crosschain.go index 69f2ae68f4..45a68a5627 100644 --- a/testutil/keeper/crosschain.go +++ b/testutil/keeper/crosschain.go @@ -32,7 +32,7 @@ var ( CrosschainNoMocks = CrosschainMockOptions{} ) -// CrosschainKeeper initializes a crosschain keeper for testing purposes with option to mock specific keepers +// CrosschainKeeperWithMocks initializes a crosschain keeper for testing purposes with option to mock specific keepers func CrosschainKeeperWithMocks( t testing.TB, mockOptions CrosschainMockOptions, diff --git a/testutil/keeper/mocks/crosschain/account.go b/testutil/keeper/mocks/crosschain/account.go index 0560f21be8..99b7f1cf5b 100644 --- a/testutil/keeper/mocks/crosschain/account.go +++ b/testutil/keeper/mocks/crosschain/account.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.41.0. DO NOT EDIT. +// Code generated by mockery v2.39.1. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/crosschain/bank.go b/testutil/keeper/mocks/crosschain/bank.go index 9ac2b1278b..267f2b45b4 100644 --- a/testutil/keeper/mocks/crosschain/bank.go +++ b/testutil/keeper/mocks/crosschain/bank.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.41.0. DO NOT EDIT. +// Code generated by mockery v2.39.1. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/crosschain/fungible.go b/testutil/keeper/mocks/crosschain/fungible.go index 3cd55097ed..a720711b79 100644 --- a/testutil/keeper/mocks/crosschain/fungible.go +++ b/testutil/keeper/mocks/crosschain/fungible.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.41.0. DO NOT EDIT. +// Code generated by mockery v2.39.1. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/crosschain/observer.go b/testutil/keeper/mocks/crosschain/observer.go index a299839f02..5953a5de34 100644 --- a/testutil/keeper/mocks/crosschain/observer.go +++ b/testutil/keeper/mocks/crosschain/observer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.41.0. DO NOT EDIT. +// Code generated by mockery v2.39.1. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/crosschain/staking.go b/testutil/keeper/mocks/crosschain/staking.go index 1fb8a14061..64bbe0fed6 100644 --- a/testutil/keeper/mocks/crosschain/staking.go +++ b/testutil/keeper/mocks/crosschain/staking.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.41.0. DO NOT EDIT. +// Code generated by mockery v2.39.1. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/fungible/account.go b/testutil/keeper/mocks/fungible/account.go index f7a2788969..94b7a84d75 100644 --- a/testutil/keeper/mocks/fungible/account.go +++ b/testutil/keeper/mocks/fungible/account.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.41.0. DO NOT EDIT. +// Code generated by mockery v2.39.1. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/fungible/bank.go b/testutil/keeper/mocks/fungible/bank.go index 599ba3453f..20a2590911 100644 --- a/testutil/keeper/mocks/fungible/bank.go +++ b/testutil/keeper/mocks/fungible/bank.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.41.0. DO NOT EDIT. +// Code generated by mockery v2.39.1. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/fungible/evm.go b/testutil/keeper/mocks/fungible/evm.go index b59f7d477e..f0dcd01094 100644 --- a/testutil/keeper/mocks/fungible/evm.go +++ b/testutil/keeper/mocks/fungible/evm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.41.0. DO NOT EDIT. +// Code generated by mockery v2.39.1. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/fungible/observer.go b/testutil/keeper/mocks/fungible/observer.go index b5736cd960..3a4685f3b2 100644 --- a/testutil/keeper/mocks/fungible/observer.go +++ b/testutil/keeper/mocks/fungible/observer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.41.0. DO NOT EDIT. +// Code generated by mockery v2.39.1. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/mocks.go b/testutil/keeper/mocks/mocks.go index dbbdeccd76..a0349f7d3d 100644 --- a/testutil/keeper/mocks/mocks.go +++ b/testutil/keeper/mocks/mocks.go @@ -3,6 +3,7 @@ package mocks import ( crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" + observertypes "github.com/zeta-chain/zetacore/x/observer/types" ) /** @@ -57,3 +58,17 @@ type FungibleObserverKeeper interface { type FungibleEVMKeeper interface { fungibletypes.EVMKeeper } + +/** + * Observer Mocks + */ + +//go:generate mockery --name ObserverStakingKeeper --filename staking.go --case underscore --output ./observer +type ObserverStakingKeeper interface { + observertypes.StakingKeeper +} + +//go:generate mockery --name ObserverSlashingKeeper --filename slashing.go --case underscore --output ./observer +type ObserverSlashingKeeper interface { + observertypes.SlashingKeeper +} diff --git a/testutil/keeper/mocks/observer/slashing.go b/testutil/keeper/mocks/observer/slashing.go new file mode 100644 index 0000000000..d3f64ff726 --- /dev/null +++ b/testutil/keeper/mocks/observer/slashing.go @@ -0,0 +1,53 @@ +// Code generated by mockery v2.39.1. DO NOT EDIT. + +package mocks + +import ( + mock "github.com/stretchr/testify/mock" + + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + + types "github.com/cosmos/cosmos-sdk/types" +) + +// ObserverSlashingKeeper is an autogenerated mock type for the ObserverSlashingKeeper type +type ObserverSlashingKeeper struct { + mock.Mock +} + +// IsTombstoned provides a mock function with given fields: ctx, addr +func (_m *ObserverSlashingKeeper) IsTombstoned(ctx types.Context, addr types.ConsAddress) bool { + ret := _m.Called(ctx, addr) + + if len(ret) == 0 { + panic("no return value specified for IsTombstoned") + } + + var r0 bool + if rf, ok := ret.Get(0).(func(types.Context, types.ConsAddress) bool); ok { + r0 = rf(ctx, addr) + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// SetValidatorSigningInfo provides a mock function with given fields: ctx, address, info +func (_m *ObserverSlashingKeeper) SetValidatorSigningInfo(ctx types.Context, address types.ConsAddress, info slashingtypes.ValidatorSigningInfo) { + _m.Called(ctx, address, info) +} + +// NewObserverSlashingKeeper creates a new instance of ObserverSlashingKeeper. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewObserverSlashingKeeper(t interface { + mock.TestingT + Cleanup(func()) +}) *ObserverSlashingKeeper { + mock := &ObserverSlashingKeeper{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/testutil/keeper/mocks/observer/staking.go b/testutil/keeper/mocks/observer/staking.go new file mode 100644 index 0000000000..72fe2be116 --- /dev/null +++ b/testutil/keeper/mocks/observer/staking.go @@ -0,0 +1,91 @@ +// Code generated by mockery v2.39.1. DO NOT EDIT. + +package mocks + +import ( + mock "github.com/stretchr/testify/mock" + + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + types "github.com/cosmos/cosmos-sdk/types" +) + +// ObserverStakingKeeper is an autogenerated mock type for the ObserverStakingKeeper type +type ObserverStakingKeeper struct { + mock.Mock +} + +// GetDelegation provides a mock function with given fields: ctx, delAddr, valAddr +func (_m *ObserverStakingKeeper) GetDelegation(ctx types.Context, delAddr types.AccAddress, valAddr types.ValAddress) (stakingtypes.Delegation, bool) { + ret := _m.Called(ctx, delAddr, valAddr) + + if len(ret) == 0 { + panic("no return value specified for GetDelegation") + } + + var r0 stakingtypes.Delegation + var r1 bool + if rf, ok := ret.Get(0).(func(types.Context, types.AccAddress, types.ValAddress) (stakingtypes.Delegation, bool)); ok { + return rf(ctx, delAddr, valAddr) + } + if rf, ok := ret.Get(0).(func(types.Context, types.AccAddress, types.ValAddress) stakingtypes.Delegation); ok { + r0 = rf(ctx, delAddr, valAddr) + } else { + r0 = ret.Get(0).(stakingtypes.Delegation) + } + + if rf, ok := ret.Get(1).(func(types.Context, types.AccAddress, types.ValAddress) bool); ok { + r1 = rf(ctx, delAddr, valAddr) + } else { + r1 = ret.Get(1).(bool) + } + + return r0, r1 +} + +// GetValidator provides a mock function with given fields: ctx, addr +func (_m *ObserverStakingKeeper) GetValidator(ctx types.Context, addr types.ValAddress) (stakingtypes.Validator, bool) { + ret := _m.Called(ctx, addr) + + if len(ret) == 0 { + panic("no return value specified for GetValidator") + } + + var r0 stakingtypes.Validator + var r1 bool + if rf, ok := ret.Get(0).(func(types.Context, types.ValAddress) (stakingtypes.Validator, bool)); ok { + return rf(ctx, addr) + } + if rf, ok := ret.Get(0).(func(types.Context, types.ValAddress) stakingtypes.Validator); ok { + r0 = rf(ctx, addr) + } else { + r0 = ret.Get(0).(stakingtypes.Validator) + } + + if rf, ok := ret.Get(1).(func(types.Context, types.ValAddress) bool); ok { + r1 = rf(ctx, addr) + } else { + r1 = ret.Get(1).(bool) + } + + return r0, r1 +} + +// SetValidator provides a mock function with given fields: ctx, validator +func (_m *ObserverStakingKeeper) SetValidator(ctx types.Context, validator stakingtypes.Validator) { + _m.Called(ctx, validator) +} + +// NewObserverStakingKeeper creates a new instance of ObserverStakingKeeper. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewObserverStakingKeeper(t interface { + mock.TestingT + Cleanup(func()) +}) *ObserverStakingKeeper { + mock := &ObserverStakingKeeper{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/testutil/keeper/observer.go b/testutil/keeper/observer.go index 40f46bee8d..1a6dd2e257 100644 --- a/testutil/keeper/observer.go +++ b/testutil/keeper/observer.go @@ -3,20 +3,36 @@ package keeper import ( "testing" - slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" + slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" tmdb "github.com/tendermint/tm-db" + observermocks "github.com/zeta-chain/zetacore/testutil/keeper/mocks/observer" "github.com/zeta-chain/zetacore/x/observer/keeper" "github.com/zeta-chain/zetacore/x/observer/types" ) +// ObserverMockOptions represents options for instantiating an observer keeper with mocks +type ObserverMockOptions struct { + UseStakingMock bool + UseSlashingMock bool +} + +var ( + ObserverMocksAll = ObserverMockOptions{ + UseStakingMock: true, + UseSlashingMock: true, + } + ObserverNoMocks = ObserverMockOptions{} +) + func initObserverKeeper( cdc codec.Codec, db *tmdb.MemDB, @@ -40,8 +56,8 @@ func initObserverKeeper( ) } -// ObserverKeeper instantiates an observer keeper for testing purposes -func ObserverKeeper(t testing.TB) (*keeper.Keeper, sdk.Context, SDKKeepers) { +// ObserverKeeperWithMocks instantiates an observer keeper for testing purposes with the option to mock specific keepers +func ObserverKeeperWithMocks(t testing.TB, mockOptions ObserverMockOptions) (*keeper.Keeper, sdk.Context, SDKKeepers) { storeKey := sdk.NewKVStoreKey(types.StoreKey) memStoreKey := storetypes.NewMemoryStoreKey(types.MemStoreKey) @@ -66,16 +82,67 @@ func ObserverKeeper(t testing.TB) (*keeper.Keeper, sdk.Context, SDKKeepers) { // Add a proposer to the context ctx = sdkKeepers.InitBlockProposer(t, ctx) + // Initialize mocks for mocked keepers + var stakingKeeper types.StakingKeeper = sdkKeepers.StakingKeeper + var slashingKeeper types.SlashingKeeper = sdkKeepers.SlashingKeeper + if mockOptions.UseStakingMock { + stakingKeeper = observermocks.NewObserverStakingKeeper(t) + } + if mockOptions.UseSlashingMock { + slashingKeeper = observermocks.NewObserverSlashingKeeper(t) + } + k := keeper.NewKeeper( cdc, storeKey, memStoreKey, sdkKeepers.ParamsKeeper.Subspace(types.ModuleName), - sdkKeepers.StakingKeeper, - sdkKeepers.SlashingKeeper, + stakingKeeper, + slashingKeeper, ) k.SetParams(ctx, types.DefaultParams()) return k, ctx, sdkKeepers } + +// ObserverKeeper instantiates an observer keeper for testing purposes +func ObserverKeeper(t testing.TB) (*keeper.Keeper, sdk.Context, SDKKeepers) { + return ObserverKeeperWithMocks(t, ObserverNoMocks) +} + +// GetObserverStakingMock returns a new observer staking keeper mock +func GetObserverStakingMock(t testing.TB, keeper *keeper.Keeper) *ObserverMockStakingKeeper { + k, ok := keeper.GetStakingKeeper().(*observermocks.ObserverStakingKeeper) + require.True(t, ok) + return &ObserverMockStakingKeeper{ + ObserverStakingKeeper: k, + } +} + +// GetObserverSlashingMock returns a new observer slashing keeper mock +func GetObserverSlashingMock(t testing.TB, keeper *keeper.Keeper) *ObserverMockSlashingKeeper { + k, ok := keeper.GetSlashingKeeper().(*observermocks.ObserverSlashingKeeper) + require.True(t, ok) + return &ObserverMockSlashingKeeper{ + ObserverSlashingKeeper: k, + } +} + +// ObserverMockStakingKeeper is a wrapper of the observer staking keeper mock that add methods to mock the GetValidator method +type ObserverMockStakingKeeper struct { + *observermocks.ObserverStakingKeeper +} + +func (m *ObserverMockStakingKeeper) MockGetValidator(validator stakingtypes.Validator) { + m.On("GetValidator", mock.Anything, mock.Anything).Return(validator, true) +} + +// ObserverMockSlashingKeeper is a wrapper of the observer slashing keeper mock that add methods to mock the IsTombstoned method +type ObserverMockSlashingKeeper struct { + *observermocks.ObserverSlashingKeeper +} + +func (m *ObserverMockSlashingKeeper) MockIsTombstoned(isTombstoned bool) { + m.On("IsTombstoned", mock.Anything, mock.Anything).Return(isTombstoned) +} From f474277e5bd285918bb479b92e73807dd73a7226 Mon Sep 17 00:00:00 2001 From: lumtis Date: Tue, 20 Feb 2024 17:32:07 +0100 Subject: [PATCH 14/24] inbound vote test --- testutil/sample/sample.go | 5 + x/observer/keeper/tss_test.go | 16 ++-- x/observer/keeper/vote_inbound.go | 2 +- x/observer/keeper/vote_inbound_test.go | 125 +++++++++++++++++++++++-- 4 files changed, 133 insertions(+), 15 deletions(-) diff --git a/testutil/sample/sample.go b/testutil/sample/sample.go index 4fcc9ac9e8..46f637ee2c 100644 --- a/testutil/sample/sample.go +++ b/testutil/sample/sample.go @@ -34,6 +34,11 @@ func newRandFromStringSeed(t *testing.T, s string) *rand.Rand { return newRandFromSeed(int64(h.Sum64())) } +// Rand returns a new random number generator +func Rand() *rand.Rand { + return newRandFromSeed(42) +} + // PubKey returns a sample account PubKey func PubKey(r *rand.Rand) cryptotypes.PubKey { seed := []byte(strconv.Itoa(r.Int())) diff --git a/x/observer/keeper/tss_test.go b/x/observer/keeper/tss_test.go index 0af8bae7f3..06f763e4d3 100644 --- a/x/observer/keeper/tss_test.go +++ b/x/observer/keeper/tss_test.go @@ -17,7 +17,7 @@ import ( ) func TestTSSGet(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) tss := sample.Tss() k.SetTSS(ctx, tss) tssQueried, found := k.GetTSS(ctx) @@ -26,7 +26,7 @@ func TestTSSGet(t *testing.T) { } func TestTSSRemove(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) tss := sample.Tss() k.SetTSS(ctx, tss) k.RemoveTSS(ctx) @@ -35,7 +35,7 @@ func TestTSSRemove(t *testing.T) { } func TestTSSQuerySingle(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) wctx := sdk.WrapSDKContext(ctx) //msgs := createTSS(keeper, ctx, 1) tss := sample.Tss() @@ -69,7 +69,7 @@ func TestTSSQuerySingle(t *testing.T) { } func TestTSSQueryHistory(t *testing.T) { - keeper, ctx := keepertest.ObserverKeeper(t) + keeper, ctx, _ := keepertest.ObserverKeeper(t) wctx := sdk.WrapSDKContext(ctx) for _, tc := range []struct { desc string @@ -115,7 +115,7 @@ func TestTSSQueryHistory(t *testing.T) { func TestKeeper_TssHistory(t *testing.T) { t.Run("Get tss history paginated by limit", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) tssList := sample.TssList(10) for _, tss := range tssList { k.SetTSSHistory(ctx, tss) @@ -132,7 +132,7 @@ func TestKeeper_TssHistory(t *testing.T) { require.Equal(t, len(tssList), int(pageRes.Total)) }) t.Run("Get tss history paginated by offset", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) tssList := sample.TssList(100) offset := 20 for _, tss := range tssList { @@ -151,7 +151,7 @@ func TestKeeper_TssHistory(t *testing.T) { require.Equal(t, len(tssList), int(pageRes.Total)) }) t.Run("Get all TSS without pagination", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) tssList := sample.TssList(100) for _, tss := range tssList { k.SetTSSHistory(ctx, tss) @@ -166,7 +166,7 @@ func TestKeeper_TssHistory(t *testing.T) { require.Equal(t, tssList, rst) }) t.Run("Get historical TSS", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) tssList := sample.TssList(100) for _, tss := range tssList { k.SetTSSHistory(ctx, tss) diff --git a/x/observer/keeper/vote_inbound.go b/x/observer/keeper/vote_inbound.go index 85d8e7ff75..ab707063e8 100644 --- a/x/observer/keeper/vote_inbound.go +++ b/x/observer/keeper/vote_inbound.go @@ -47,7 +47,7 @@ func (k Keeper) VoteOnInboundBallot( if receiverChain == nil { return false, sdkerrors.Wrap(types.ErrSupportedChains, fmt.Sprintf( "ChainID %d, Observation %s", - receiverChain.ChainId, + receiverChainID, types.ObservationType_InBoundTx.String()), ) } diff --git a/x/observer/keeper/vote_inbound_test.go b/x/observer/keeper/vote_inbound_test.go index 7914f52638..49c0fa9e19 100644 --- a/x/observer/keeper/vote_inbound_test.go +++ b/x/observer/keeper/vote_inbound_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/testutil/sample" @@ -106,9 +107,11 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { }) t.Run("fail if receiver chain not supported", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeperWithMocks(t, keepertest.ObserverMocksAll) observer := sample.AccAddress() + stakingMock := keepertest.GetObserverStakingMock(t, k) + slashingMock := keepertest.GetObserverSlashingMock(t, k) k.SetCrosschainFlags(ctx, types.CrosschainFlags{ IsInboundEnabled: true, @@ -124,6 +127,8 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { k.SetObserverSet(ctx, types.ObserverSet{ ObserverList: []string{observer}, }) + stakingMock.MockGetValidator(sample.Validator(t, sample.Rand())) + slashingMock.MockIsTombstoned(false) _, err := k.VoteOnInboundBallot( ctx, @@ -150,6 +155,8 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { }, }, }) + stakingMock.MockGetValidator(sample.Validator(t, sample.Rand())) + slashingMock.MockIsTombstoned(false) _, err = k.VoteOnInboundBallot( ctx, @@ -165,9 +172,11 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { }) t.Run("fail if inbound contain ZETA but receiver chain doesn't support ZETA", func(t *testing.T) { - k, ctx, _ := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeperWithMocks(t, keepertest.ObserverMocksAll) observer := sample.AccAddress() + stakingMock := keepertest.GetObserverStakingMock(t, k) + slashingMock := keepertest.GetObserverSlashingMock(t, k) k.SetCrosschainFlags(ctx, types.CrosschainFlags{ IsInboundEnabled: true, @@ -179,7 +188,7 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { IsSupported: true, }, { - ChainId: common.ZetaPrivnetChain().ChainId, + ChainId: getValidEthChainIDWithIndex(t, 1), IsSupported: true, ZetaTokenContractAddress: "", }, @@ -188,13 +197,15 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { k.SetObserverSet(ctx, types.ObserverSet{ ObserverList: []string{observer}, }) + stakingMock.MockGetValidator(sample.Validator(t, sample.Rand())) + slashingMock.MockIsTombstoned(false) _, err := k.VoteOnInboundBallot( ctx, getValidEthChainIDWithIndex(t, 0), - common.ZetaPrivnetChain().ChainId, + getValidEthChainIDWithIndex(t, 1), common.CoinType_Zeta, - sample.AccAddress(), + observer, "index", "inTxHash", ) @@ -202,7 +213,109 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { require.ErrorIs(t, err, types.ErrInvalidZetaCoinTypes) }) - t.Run("can add vote to inbound ballot", func(t *testing.T) { + t.Run("can add vote and create ballot", func(t *testing.T) { + k, ctx, _ := keepertest.ObserverKeeperWithMocks(t, keepertest.ObserverMocksAll) + + observer := sample.AccAddress() + stakingMock := keepertest.GetObserverStakingMock(t, k) + slashingMock := keepertest.GetObserverSlashingMock(t, k) + + k.SetCrosschainFlags(ctx, types.CrosschainFlags{ + IsInboundEnabled: true, + }) + k.SetChainParamsList(ctx, types.ChainParamsList{ + ChainParams: []*types.ChainParams{ + { + ChainId: getValidEthChainIDWithIndex(t, 0), + IsSupported: true, + }, + { + ChainId: getValidEthChainIDWithIndex(t, 1), + IsSupported: true, + }, + }, + }) + k.SetObserverSet(ctx, types.ObserverSet{ + ObserverList: []string{observer}, + }) + stakingMock.MockGetValidator(sample.Validator(t, sample.Rand())) + slashingMock.MockIsTombstoned(false) + + isFinalized, err := k.VoteOnInboundBallot( + ctx, + getValidEthChainIDWithIndex(t, 0), + getValidEthChainIDWithIndex(t, 1), + common.CoinType_ERC20, + observer, + "index", + "inTxHash", + ) + require.NoError(t, err) + + // ballot should be finalized since there is only one observer + require.True(t, isFinalized) + }) + + t.Run("can add vote to an existing ballot", func(t *testing.T) { + k, ctx, _ := keepertest.ObserverKeeperWithMocks(t, keepertest.ObserverMocksAll) + + observer := sample.AccAddress() + stakingMock := keepertest.GetObserverStakingMock(t, k) + slashingMock := keepertest.GetObserverSlashingMock(t, k) + + k.SetCrosschainFlags(ctx, types.CrosschainFlags{ + IsInboundEnabled: true, + }) + k.SetChainParamsList(ctx, types.ChainParamsList{ + ChainParams: []*types.ChainParams{ + { + ChainId: getValidEthChainIDWithIndex(t, 0), + IsSupported: true, + }, + { + ChainId: getValidEthChainIDWithIndex(t, 1), + IsSupported: true, + }, + }, + }) + k.SetObserverSet(ctx, types.ObserverSet{ + ObserverList: []string{observer}, + }) + stakingMock.MockGetValidator(sample.Validator(t, sample.Rand())) + slashingMock.MockIsTombstoned(false) + + // set a ballot + threshold, err := sdk.NewDecFromStr("0.7") + require.NoError(t, err) + ballot := types.Ballot{ + Index: "index", + BallotIdentifier: "index", + VoterList: []string{ + sample.AccAddress(), + sample.AccAddress(), + observer, + sample.AccAddress(), + sample.AccAddress(), + }, + Votes: types.CreateVotes(5), + ObservationType: types.ObservationType_InBoundTx, + BallotThreshold: threshold, + BallotStatus: types.BallotStatus_BallotInProgress, + } + k.SetBallot(ctx, &ballot) + + isFinalized, err := k.VoteOnInboundBallot( + ctx, + getValidEthChainIDWithIndex(t, 0), + getValidEthChainIDWithIndex(t, 1), + common.CoinType_ERC20, + observer, + "index", + "inTxHash", + ) + require.NoError(t, err) + // ballot should not be finalized as the threshold is not reached + require.False(t, isFinalized) }) } From f0c7843b16d5b7984154b8ad2a29303101aef070 Mon Sep 17 00:00:00 2001 From: lumtis Date: Tue, 20 Feb 2024 17:42:39 +0100 Subject: [PATCH 15/24] initialize outbound tests --- x/observer/keeper/vote_outbound_test.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 x/observer/keeper/vote_outbound_test.go diff --git a/x/observer/keeper/vote_outbound_test.go b/x/observer/keeper/vote_outbound_test.go new file mode 100644 index 0000000000..55f97b2b46 --- /dev/null +++ b/x/observer/keeper/vote_outbound_test.go @@ -0,0 +1,17 @@ +package keeper_test + +import "testing" + +func TestKeeper_VoteOnOutboundBallot(t *testing.T) { + t.Run("fail if chain is not supported", func(t *testing.T) { + + }) + + t.Run("fail if sender is not authorized", func(t *testing.T) { + + }) + + t.Run("fail if sender is not authorized", func(t *testing.T) { + + }) +} From ebcc4234408219eede92bac9cfcfb3c4c410a562 Mon Sep 17 00:00:00 2001 From: lumtis Date: Tue, 20 Feb 2024 17:44:00 +0100 Subject: [PATCH 16/24] goimports --- x/observer/keeper/vote_inbound_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x/observer/keeper/vote_inbound_test.go b/x/observer/keeper/vote_inbound_test.go index 49c0fa9e19..7c66fcc8a6 100644 --- a/x/observer/keeper/vote_inbound_test.go +++ b/x/observer/keeper/vote_inbound_test.go @@ -1,11 +1,12 @@ package keeper_test import ( + "testing" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/testutil/sample" - "testing" keepertest "github.com/zeta-chain/zetacore/testutil/keeper" "github.com/zeta-chain/zetacore/x/observer/types" From 6fdeb473cbfa310077d1e0aade629ca5559521fd Mon Sep 17 00:00:00 2001 From: lumtis Date: Tue, 20 Feb 2024 21:25:51 +0100 Subject: [PATCH 17/24] vote outbound tests --- x/observer/keeper/vote_inbound_test.go | 3 +- x/observer/keeper/vote_outbound.go | 14 +- x/observer/keeper/vote_outbound_test.go | 180 +++++++++++++++++++++++- x/observer/types/observer_mapper.go | 28 ---- x/observer/types/observer_set.go | 27 ++++ 5 files changed, 213 insertions(+), 39 deletions(-) delete mode 100644 x/observer/types/observer_mapper.go diff --git a/x/observer/keeper/vote_inbound_test.go b/x/observer/keeper/vote_inbound_test.go index 7c66fcc8a6..3420d48b45 100644 --- a/x/observer/keeper/vote_inbound_test.go +++ b/x/observer/keeper/vote_inbound_test.go @@ -6,9 +6,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/common" - "github.com/zeta-chain/zetacore/testutil/sample" - keepertest "github.com/zeta-chain/zetacore/testutil/keeper" + "github.com/zeta-chain/zetacore/testutil/sample" "github.com/zeta-chain/zetacore/x/observer/types" ) diff --git a/x/observer/keeper/vote_outbound.go b/x/observer/keeper/vote_outbound.go index db86486cdb..3ee0c6b585 100644 --- a/x/observer/keeper/vote_outbound.go +++ b/x/observer/keeper/vote_outbound.go @@ -17,34 +17,34 @@ func (k Keeper) VoteOnOutboundBallot( outTxChainID int64, receiveStatus common.ReceiveStatus, voter string, -) (isFinalized bool, isNew bool, ballotStatus observertypes.Ballot, observationChainName string, err error) { +) (isFinalized bool, isNew bool, ballot observertypes.Ballot, observationChainName string, err error) { // Observer Chain already checked then inbound is created /* EDGE CASE : Params updated in during the finalization process i.e Inbound has been finalized but outbound is still pending */ observationChain := k.GetSupportedChainFromChainID(ctx, outTxChainID) if observationChain == nil { - return false, false, ballotStatus, "", observertypes.ErrSupportedChains + return false, false, ballot, "", observertypes.ErrSupportedChains } if observertypes.CheckReceiveStatus(receiveStatus) != nil { - return false, false, ballotStatus, "", err + return false, false, ballot, "", observertypes.ErrInvalidStatus } // check if voter is authorized if ok := k.IsAuthorized(ctx, voter); !ok { - return false, false, ballotStatus, "", observertypes.ErrNotAuthorizedPolicy + return false, false, ballot, "", observertypes.ErrNotObserver } // fetch or create ballot - ballot, isNew, err := k.FindBallot(ctx, ballotIndex, observationChain, observertypes.ObservationType_OutBoundTx) + ballot, isNew, err = k.FindBallot(ctx, ballotIndex, observationChain, observertypes.ObservationType_OutBoundTx) if err != nil { - return false, false, ballotStatus, "", err + return false, false, ballot, "", err } // add vote to ballot ballot, err = k.AddVoteToBallot(ctx, ballot, voter, observertypes.ConvertReceiveStatusToVoteType(receiveStatus)) if err != nil { - return false, false, ballotStatus, "", err + return false, false, ballot, "", err } ballot, isFinalizedInThisBlock := k.CheckIfFinalizingVote(ctx, ballot) diff --git a/x/observer/keeper/vote_outbound_test.go b/x/observer/keeper/vote_outbound_test.go index 55f97b2b46..edb7db3fec 100644 --- a/x/observer/keeper/vote_outbound_test.go +++ b/x/observer/keeper/vote_outbound_test.go @@ -1,17 +1,193 @@ package keeper_test -import "testing" +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/common" + keepertest "github.com/zeta-chain/zetacore/testutil/keeper" + "github.com/zeta-chain/zetacore/testutil/sample" + "github.com/zeta-chain/zetacore/x/observer/types" +) func TestKeeper_VoteOnOutboundBallot(t *testing.T) { t.Run("fail if chain is not supported", func(t *testing.T) { + k, ctx, _ := keepertest.ObserverKeeper(t) + + k.SetChainParamsList(ctx, types.ChainParamsList{}) + + _, _, _, _, err := k.VoteOnOutboundBallot( + ctx, + "index", + getValidEthChainIDWithIndex(t, 0), + common.ReceiveStatus_Success, + sample.AccAddress(), + ) + require.Error(t, err) + require.ErrorIs(t, err, types.ErrSupportedChains) + // set the chain but not supported + k.SetChainParamsList(ctx, types.ChainParamsList{ + ChainParams: []*types.ChainParams{ + { + ChainId: getValidEthChainIDWithIndex(t, 0), + IsSupported: false, + }, + }, + }) + + _, _, _, _, err = k.VoteOnOutboundBallot( + ctx, + "index", + getValidEthChainIDWithIndex(t, 0), + common.ReceiveStatus_Success, + sample.AccAddress(), + ) + require.Error(t, err) + require.ErrorIs(t, err, types.ErrSupportedChains) }) - t.Run("fail if sender is not authorized", func(t *testing.T) { + t.Run("fail if receive status is invalid", func(t *testing.T) { + k, ctx, _ := keepertest.ObserverKeeper(t) + k.SetChainParamsList(ctx, types.ChainParamsList{ + ChainParams: []*types.ChainParams{ + { + ChainId: getValidEthChainIDWithIndex(t, 0), + IsSupported: true, + }, + }, + }) + + _, _, _, _, err := k.VoteOnOutboundBallot( + ctx, + "index", + getValidEthChainIDWithIndex(t, 0), + common.ReceiveStatus(1000), + sample.AccAddress(), + ) + require.Error(t, err) + require.ErrorIs(t, err, types.ErrInvalidStatus) }) t.Run("fail if sender is not authorized", func(t *testing.T) { + k, ctx, _ := keepertest.ObserverKeeper(t) + + k.SetChainParamsList(ctx, types.ChainParamsList{ + ChainParams: []*types.ChainParams{ + { + ChainId: getValidEthChainIDWithIndex(t, 0), + IsSupported: true, + }, + }, + }) + k.SetObserverSet(ctx, types.ObserverSet{}) + + _, _, _, _, err := k.VoteOnOutboundBallot( + ctx, + "index", + getValidEthChainIDWithIndex(t, 0), + common.ReceiveStatus_Success, + sample.AccAddress(), + ) + require.Error(t, err) + require.ErrorIs(t, err, types.ErrNotObserver) + }) + + t.Run("can add vote and create ballot", func(t *testing.T) { + k, ctx, _ := keepertest.ObserverKeeperWithMocks(t, keepertest.ObserverMocksAll) + + observer := sample.AccAddress() + stakingMock := keepertest.GetObserverStakingMock(t, k) + slashingMock := keepertest.GetObserverSlashingMock(t, k) + + k.SetChainParamsList(ctx, types.ChainParamsList{ + ChainParams: []*types.ChainParams{ + { + ChainId: getValidEthChainIDWithIndex(t, 0), + IsSupported: true, + }, + }, + }) + k.SetObserverSet(ctx, types.ObserverSet{ + ObserverList: []string{observer}, + }) + stakingMock.MockGetValidator(sample.Validator(t, sample.Rand())) + slashingMock.MockIsTombstoned(false) + + isFinalized, isNew, ballot, _, err := k.VoteOnOutboundBallot( + ctx, + "index", + getValidEthChainIDWithIndex(t, 0), + common.ReceiveStatus_Success, + observer, + ) + require.NoError(t, err) + + // ballot should be finalized since there is only one observer + require.True(t, isFinalized) + require.True(t, isNew) + expectedBallot, found := k.GetBallot(ctx, "index") + require.True(t, found) + require.Equal(t, expectedBallot, ballot) + }) + + t.Run("can add vote to an existing ballot", func(t *testing.T) { + k, ctx, _ := keepertest.ObserverKeeperWithMocks(t, keepertest.ObserverMocksAll) + + observer := sample.AccAddress() + stakingMock := keepertest.GetObserverStakingMock(t, k) + slashingMock := keepertest.GetObserverSlashingMock(t, k) + + k.SetChainParamsList(ctx, types.ChainParamsList{ + ChainParams: []*types.ChainParams{ + { + ChainId: getValidEthChainIDWithIndex(t, 0), + IsSupported: true, + }, + }, + }) + k.SetObserverSet(ctx, types.ObserverSet{ + ObserverList: []string{observer}, + }) + stakingMock.MockGetValidator(sample.Validator(t, sample.Rand())) + slashingMock.MockIsTombstoned(false) + + // set a ballot + threshold, err := sdk.NewDecFromStr("0.7") + require.NoError(t, err) + ballot := types.Ballot{ + Index: "index", + BallotIdentifier: "index", + VoterList: []string{ + sample.AccAddress(), + sample.AccAddress(), + observer, + sample.AccAddress(), + sample.AccAddress(), + }, + Votes: types.CreateVotes(5), + ObservationType: types.ObservationType_OutBoundTx, + BallotThreshold: threshold, + BallotStatus: types.BallotStatus_BallotInProgress, + } + k.SetBallot(ctx, &ballot) + + isFinalized, isNew, ballot, _, err := k.VoteOnOutboundBallot( + ctx, + "index", + getValidEthChainIDWithIndex(t, 0), + common.ReceiveStatus_Success, + observer, + ) + require.NoError(t, err) + // ballot should be finalized since there is only one observer + require.False(t, isFinalized) + require.False(t, isNew) + expectedBallot, found := k.GetBallot(ctx, "index") + require.True(t, found) + require.Equal(t, expectedBallot, ballot) }) } diff --git a/x/observer/types/observer_mapper.go b/x/observer/types/observer_mapper.go deleted file mode 100644 index b78f5daa8c..0000000000 --- a/x/observer/types/observer_mapper.go +++ /dev/null @@ -1,28 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/zeta-chain/zetacore/common" -) - -// Validate observer mapper contains an existing chain -func (m *ObserverSet) Validate() error { - for _, observerAddress := range m.ObserverList { - _, err := sdk.AccAddressFromBech32(observerAddress) - if err != nil { - return err - } - } - return nil -} - -func CheckReceiveStatus(status common.ReceiveStatus) error { - switch status { - case common.ReceiveStatus_Success: - return nil - case common.ReceiveStatus_Failed: - return nil - default: - return ErrInvalidStatus - } -} diff --git a/x/observer/types/observer_set.go b/x/observer/types/observer_set.go index 71798f213f..e1b6c61c9b 100644 --- a/x/observer/types/observer_set.go +++ b/x/observer/types/observer_set.go @@ -1,5 +1,10 @@ package types +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/zeta-chain/zetacore/common" +) + func (m *ObserverSet) Len() int { return len(m.ObserverList) } @@ -7,3 +12,25 @@ func (m *ObserverSet) Len() int { func (m *ObserverSet) LenUint() uint64 { return uint64(len(m.ObserverList)) } + +// Validate observer mapper contains an existing chain +func (m *ObserverSet) Validate() error { + for _, observerAddress := range m.ObserverList { + _, err := sdk.AccAddressFromBech32(observerAddress) + if err != nil { + return err + } + } + return nil +} + +func CheckReceiveStatus(status common.ReceiveStatus) error { + switch status { + case common.ReceiveStatus_Success: + return nil + case common.ReceiveStatus_Failed: + return nil + default: + return ErrInvalidStatus + } +} From e5cecb553a6a895930484bbc77bffc703a1bc3a7 Mon Sep 17 00:00:00 2001 From: lumtis Date: Tue, 20 Feb 2024 21:37:13 +0100 Subject: [PATCH 18/24] update changelog --- changelog.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index f51f04d25c..ff71663b4e 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,11 @@ # CHANGELOG +## Unreleased + +### Refactor + +* [1511](https://github.com/zeta-chain/node/pull/1511) - move ballot voting logic from `crosschain` to `observer` + ## Version: v13.0.0 ### Breaking Changes @@ -24,7 +30,6 @@ * [1766](https://github.com/zeta-chain/node/pull/1766) - Refactors the `PostTxProcessing` EVM hook functionality to deal with invalid withdraw events * [1630](https://github.com/zeta-chain/node/pull/1630) - added password prompts for hotkey and tss keyshare in zetaclient * [1760](https://github.com/zeta-chain/node/pull/1760) - Make staking keeper private in crosschain module -* [1511](https://github.com/zeta-chain/node/pull/1511) - move ballot voting logic from `crosschain` to `observer` ### Fixes From cda061b72a37e02661cf8970b34b70806634dbfc Mon Sep 17 00:00:00 2001 From: lumtis Date: Wed, 21 Feb 2024 10:24:11 +0100 Subject: [PATCH 19/24] test with integration tests --- .../integrationtests/inbound_voter_test.go | 182 +++++++++--------- .../integrationtests/outbound_voter_test.go | 180 ++++++++--------- x/crosschain/client/integrationtests/suite.go | 2 +- 3 files changed, 181 insertions(+), 183 deletions(-) diff --git a/x/crosschain/client/integrationtests/inbound_voter_test.go b/x/crosschain/client/integrationtests/inbound_voter_test.go index b838250745..32da0d92db 100644 --- a/x/crosschain/client/integrationtests/inbound_voter_test.go +++ b/x/crosschain/client/integrationtests/inbound_voter_test.go @@ -136,92 +136,92 @@ func (s *IntegrationTestSuite) TestCCTXInboundVoter() { ballotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, }, - { - name: "5 votes only ballot does not get finalized", - votes: map[string]observerTypes.VoteType{ - "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, - "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, - "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, - "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_SuccessObservation, - "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_SuccessObservation, - "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_NotYetVoted, - "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_NotYetVoted, - "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_NotYetVoted, - "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_NotYetVoted, - "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_NotYetVoted, - }, - ballotResult: observerTypes.BallotStatus_BallotInProgress, - cctxStatus: crosschaintypes.CctxStatus_PendingRevert, - }, - { - name: "1 false vote but correct ballot is still finalized", - votes: map[string]observerTypes.VoteType{ - "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, - "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, - "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, - "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_SuccessObservation, - "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_SuccessObservation, - "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_SuccessObservation, - "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_SuccessObservation, - "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_FailureObservation, - "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_SuccessObservation, - "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_NotYetVoted, - }, - ballotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, - cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, - }, - { - name: "2 ballots with 5 votes each no ballot gets finalized", - votes: map[string]observerTypes.VoteType{ - "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, - "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, - "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, - "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_SuccessObservation, - "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_SuccessObservation, - "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_FailureObservation, - "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_FailureObservation, - "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_FailureObservation, - "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_FailureObservation, - "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_FailureObservation, - }, - ballotResult: observerTypes.BallotStatus_BallotInProgress, - cctxStatus: crosschaintypes.CctxStatus_PendingRevert, - }, - { - name: "majority wrong votes incorrect ballot finalized / correct ballot still in progress", - votes: map[string]observerTypes.VoteType{ - "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, - "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, - "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, - "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_FailureObservation, - "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_FailureObservation, - "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_FailureObservation, - "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_FailureObservation, - "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_FailureObservation, - "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_FailureObservation, - "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_FailureObservation, - }, - ballotResult: observerTypes.BallotStatus_BallotInProgress, - cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, - falseBallotIdentifier: "majority wrong votes incorrect ballot finalized / correct ballot still in progress" + "falseVote", - }, - { - name: "7 votes only just crossed threshold", - votes: map[string]observerTypes.VoteType{ - "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, - "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, - "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, - "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_SuccessObservation, - "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_SuccessObservation, - "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_NotYetVoted, - "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_SuccessObservation, - "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_NotYetVoted, - "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_NotYetVoted, - "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_SuccessObservation, - }, - ballotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, - cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, - }, + //{ + // name: "5 votes only ballot does not get finalized", + // votes: map[string]observerTypes.VoteType{ + // "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, + // "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, + // "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, + // "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_SuccessObservation, + // "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_SuccessObservation, + // "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_NotYetVoted, + // "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_NotYetVoted, + // "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_NotYetVoted, + // "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_NotYetVoted, + // "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_NotYetVoted, + // }, + // ballotResult: observerTypes.BallotStatus_BallotInProgress, + // cctxStatus: crosschaintypes.CctxStatus_PendingRevert, + //}, + //{ + // name: "1 false vote but correct ballot is still finalized", + // votes: map[string]observerTypes.VoteType{ + // "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, + // "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, + // "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, + // "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_SuccessObservation, + // "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_SuccessObservation, + // "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_SuccessObservation, + // "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_SuccessObservation, + // "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_FailureObservation, + // "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_SuccessObservation, + // "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_NotYetVoted, + // }, + // ballotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, + // cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, + //}, + //{ + // name: "2 ballots with 5 votes each no ballot gets finalized", + // votes: map[string]observerTypes.VoteType{ + // "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, + // "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, + // "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, + // "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_SuccessObservation, + // "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_SuccessObservation, + // "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_FailureObservation, + // "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_FailureObservation, + // "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_FailureObservation, + // "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_FailureObservation, + // "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_FailureObservation, + // }, + // ballotResult: observerTypes.BallotStatus_BallotInProgress, + // cctxStatus: crosschaintypes.CctxStatus_PendingRevert, + //}, + //{ + // name: "majority wrong votes incorrect ballot finalized / correct ballot still in progress", + // votes: map[string]observerTypes.VoteType{ + // "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, + // "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, + // "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, + // "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_FailureObservation, + // "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_FailureObservation, + // "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_FailureObservation, + // "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_FailureObservation, + // "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_FailureObservation, + // "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_FailureObservation, + // "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_FailureObservation, + // }, + // ballotResult: observerTypes.BallotStatus_BallotInProgress, + // cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, + // falseBallotIdentifier: "majority wrong votes incorrect ballot finalized / correct ballot still in progress" + "falseVote", + //}, + //{ + // name: "7 votes only just crossed threshold", + // votes: map[string]observerTypes.VoteType{ + // "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, + // "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, + // "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, + // "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_SuccessObservation, + // "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_SuccessObservation, + // "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_NotYetVoted, + // "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_SuccessObservation, + // "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_NotYetVoted, + // "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_NotYetVoted, + // "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_SuccessObservation, + // }, + // ballotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, + // cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, + //}, } for i, test := range tt { test := test @@ -241,13 +241,10 @@ func (s *IntegrationTestSuite) TestCCTXInboundVoter() { s.Require().NoError(s.network.WaitForNBlocks(2)) out, err := clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, observercli.CmdListPendingNonces(), []string{"--output", "json"}) s.Require().NoError(err) - //fmt.Println(out.String()) out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, observercli.CmdGetSupportedChains(), []string{"--output", "json"}) s.Require().NoError(err) - //fmt.Println(out.String()) out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, crosschaincli.CmdListGasPrice(), []string{"--output", "json"}) s.Require().NoError(err) - //fmt.Println(out.String()) // Vote the inbound tx for _, val := range s.network.Validators { @@ -266,6 +263,7 @@ func (s *IntegrationTestSuite) TestCCTXInboundVoter() { signedTx := BuildSignedInboundVote(s.T(), val, s.cfg.BondDenom, account, message, i) out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetBroadcastCommand(), []string{signedTx.Name(), "--broadcast-mode", "sync"}) s.Require().NoError(err) + fmt.Println(out.String()) } s.Require().NoError(s.network.WaitForNBlocks(2)) @@ -283,9 +281,9 @@ func (s *IntegrationTestSuite) TestCCTXInboundVoter() { s.Assert().Equal(observerTypes.VoteType_NotYetVoted.String(), vote.VoteType.String()) continue } - s.Assert().Equal(test.votes[vote.VoterAddress].String(), vote.VoteType.String()) + s.Assert().Equal(test.votes[vote.VoterAddress].String(), vote.VoteType.String(), "incorrect vote for voter: %s", vote.VoterAddress) } - s.Assert().Equal(test.ballotResult.String(), ballot.BallotStatus.String()) + s.Require().Equal(test.ballotResult.String(), ballot.BallotStatus.String()) // Get the cctx and check its status cctxIdentifier := ballotIdentifier @@ -298,7 +296,7 @@ func (s *IntegrationTestSuite) TestCCTXInboundVoter() { s.Require().Contains(out.String(), "not found") } else { s.NoError(broadcaster.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &cctx)) - s.Assert().Equal(test.cctxStatus.String(), cctx.CrossChainTx.CctxStatus.Status.String(), cctx.CrossChainTx.CctxStatus.StatusMessage) + s.Require().Equal(test.cctxStatus.String(), cctx.CrossChainTx.CctxStatus.Status.String(), cctx.CrossChainTx.CctxStatus.StatusMessage) } }) } diff --git a/x/crosschain/client/integrationtests/outbound_voter_test.go b/x/crosschain/client/integrationtests/outbound_voter_test.go index d388adc003..f35bba271b 100644 --- a/x/crosschain/client/integrationtests/outbound_voter_test.go +++ b/x/crosschain/client/integrationtests/outbound_voter_test.go @@ -24,96 +24,96 @@ func (s *IntegrationTestSuite) TestCCTXOutBoundVoter() { cctxStatus crosschaintypes.CctxStatus falseBallotIdentifier string }{ - { - name: "All observers voted success or not voted", - votes: []Vote{ - {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_NotYetVoted, isFakeVote: false}, - }, - correctBallotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, - cctxStatus: crosschaintypes.CctxStatus_OutboundMined, - valueReceived: "7991636132140714751", - }, - { - name: "1 fake vote but ballot still success", - votes: []Vote{ - {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - }, - correctBallotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, - cctxStatus: crosschaintypes.CctxStatus_OutboundMined, - valueReceived: "7990439496224753106", - }, - { - name: "Half success and half false", - votes: []Vote{ - {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - }, - correctBallotResult: observerTypes.BallotStatus_BallotInProgress, - cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, - valueReceived: "7990439496224753106", - }, - { - name: "Fake ballot has more votes outbound gets finalized", - votes: []Vote{ - {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - }, - correctBallotResult: observerTypes.BallotStatus_BallotInProgress, - cctxStatus: crosschaintypes.CctxStatus_OutboundMined, - valueReceived: "7987124742653889020", - }, - { - name: "5 success 5 Failed votes ", - votes: []Vote{ - {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, - {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, - {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, - {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, - {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, - }, - correctBallotResult: observerTypes.BallotStatus_BallotInProgress, - cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, - valueReceived: "7991636132140714751", - }, + //{ + // name: "All observers voted success or not voted", + // votes: []Vote{ + // {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_NotYetVoted, isFakeVote: false}, + // }, + // correctBallotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, + // cctxStatus: crosschaintypes.CctxStatus_OutboundMined, + // valueReceived: "7991636132140714751", + //}, + //{ + // name: "1 fake vote but ballot still success", + // votes: []Vote{ + // {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + // {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // }, + // correctBallotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, + // cctxStatus: crosschaintypes.CctxStatus_OutboundMined, + // valueReceived: "7990439496224753106", + //}, + //{ + // name: "Half success and half false", + // votes: []Vote{ + // {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + // {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + // {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + // {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + // {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + // }, + // correctBallotResult: observerTypes.BallotStatus_BallotInProgress, + // cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, + // valueReceived: "7990439496224753106", + //}, + //{ + // name: "Fake ballot has more votes outbound gets finalized", + // votes: []Vote{ + // {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + // {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + // {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + // {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + // {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + // {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + // {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + // {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + // }, + // correctBallotResult: observerTypes.BallotStatus_BallotInProgress, + // cctxStatus: crosschaintypes.CctxStatus_OutboundMined, + // valueReceived: "7987124742653889020", + //}, + //{ + // name: "5 success 5 Failed votes ", + // votes: []Vote{ + // {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + // {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, + // {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, + // {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, + // {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, + // {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, + // }, + // correctBallotResult: observerTypes.BallotStatus_BallotInProgress, + // cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, + // valueReceived: "7991636132140714751", + //}, } for i, test := range tt { // Buffer event index so that it does not clash with the inbound voter test diff --git a/x/crosschain/client/integrationtests/suite.go b/x/crosschain/client/integrationtests/suite.go index 65a45bc4b3..b5f16a683d 100644 --- a/x/crosschain/client/integrationtests/suite.go +++ b/x/crosschain/client/integrationtests/suite.go @@ -52,7 +52,7 @@ func (s *IntegrationTestSuite) SetupSuite() { network.AddCrosschainData(s.T(), 0, s.cfg.GenesisState, s.cfg.Codec) network.AddObserverData(s.T(), 0, s.cfg.GenesisState, s.cfg.Codec, nil) net, err := network.New(s.T(), app.NodeDir, s.cfg) - s.Assert().NoError(err) + s.Require().NoError(err) s.network = net time.Sleep(3 * time.Second) _, err = s.network.WaitForHeight(1) From 3e08a1dd9d033cba793accdb6c30fc21352a8fdd Mon Sep 17 00:00:00 2001 From: lumtis Date: Wed, 21 Feb 2024 12:21:13 +0100 Subject: [PATCH 20/24] add isNew in vote_inbound --- testutil/keeper/mocks/crosschain/account.go | 2 +- testutil/keeper/mocks/crosschain/bank.go | 2 +- testutil/keeper/mocks/crosschain/fungible.go | 2 +- testutil/keeper/mocks/crosschain/observer.go | 21 ++++++++++++------- testutil/keeper/mocks/crosschain/staking.go | 2 +- testutil/keeper/mocks/fungible/account.go | 2 +- testutil/keeper/mocks/fungible/bank.go | 2 +- testutil/keeper/mocks/fungible/evm.go | 2 +- testutil/keeper/mocks/fungible/observer.go | 2 +- testutil/keeper/mocks/observer/slashing.go | 2 +- testutil/keeper/mocks/observer/staking.go | 2 +- testutil/network/network_setup.go | 2 ++ .../integrationtests/inbound_voter_test.go | 4 ++-- .../keeper/msg_server_vote_inbound_tx.go | 19 ++++++++++------- x/crosschain/types/expected_keepers.go | 2 +- x/observer/genesis_test.go | 2 +- x/observer/keeper/vote_inbound.go | 20 +++++++++--------- x/observer/keeper/vote_inbound_test.go | 20 ++++++++++-------- x/observer/migrations/v3/migrate_test.go | 2 +- x/observer/migrations/v4/migrate_test.go | 2 +- x/observer/migrations/v5/migrate_test.go | 4 ++-- x/observer/migrations/v6/migrate_test.go | 4 ++-- 22 files changed, 69 insertions(+), 53 deletions(-) diff --git a/testutil/keeper/mocks/crosschain/account.go b/testutil/keeper/mocks/crosschain/account.go index 99b7f1cf5b..fbd7c0377b 100644 --- a/testutil/keeper/mocks/crosschain/account.go +++ b/testutil/keeper/mocks/crosschain/account.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.39.1. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/crosschain/bank.go b/testutil/keeper/mocks/crosschain/bank.go index 267f2b45b4..90f4e17e29 100644 --- a/testutil/keeper/mocks/crosschain/bank.go +++ b/testutil/keeper/mocks/crosschain/bank.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.39.1. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/crosschain/fungible.go b/testutil/keeper/mocks/crosschain/fungible.go index a720711b79..7a0a40a6de 100644 --- a/testutil/keeper/mocks/crosschain/fungible.go +++ b/testutil/keeper/mocks/crosschain/fungible.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.39.1. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/crosschain/observer.go b/testutil/keeper/mocks/crosschain/observer.go index 5953a5de34..8e2a40b9cb 100644 --- a/testutil/keeper/mocks/crosschain/observer.go +++ b/testutil/keeper/mocks/crosschain/observer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.39.1. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks @@ -801,7 +801,7 @@ func (_m *CrosschainObserverKeeper) SetTssAndUpdateNonce(ctx types.Context, tss } // VoteOnInboundBallot provides a mock function with given fields: ctx, senderChainID, receiverChainID, coinType, voter, ballotIndex, inTxHash -func (_m *CrosschainObserverKeeper) VoteOnInboundBallot(ctx types.Context, senderChainID int64, receiverChainID int64, coinType common.CoinType, voter string, ballotIndex string, inTxHash string) (bool, error) { +func (_m *CrosschainObserverKeeper) VoteOnInboundBallot(ctx types.Context, senderChainID int64, receiverChainID int64, coinType common.CoinType, voter string, ballotIndex string, inTxHash string) (bool, bool, error) { ret := _m.Called(ctx, senderChainID, receiverChainID, coinType, voter, ballotIndex, inTxHash) if len(ret) == 0 { @@ -809,8 +809,9 @@ func (_m *CrosschainObserverKeeper) VoteOnInboundBallot(ctx types.Context, sende } var r0 bool - var r1 error - if rf, ok := ret.Get(0).(func(types.Context, int64, int64, common.CoinType, string, string, string) (bool, error)); ok { + var r1 bool + var r2 error + if rf, ok := ret.Get(0).(func(types.Context, int64, int64, common.CoinType, string, string, string) (bool, bool, error)); ok { return rf(ctx, senderChainID, receiverChainID, coinType, voter, ballotIndex, inTxHash) } if rf, ok := ret.Get(0).(func(types.Context, int64, int64, common.CoinType, string, string, string) bool); ok { @@ -819,13 +820,19 @@ func (_m *CrosschainObserverKeeper) VoteOnInboundBallot(ctx types.Context, sende r0 = ret.Get(0).(bool) } - if rf, ok := ret.Get(1).(func(types.Context, int64, int64, common.CoinType, string, string, string) error); ok { + if rf, ok := ret.Get(1).(func(types.Context, int64, int64, common.CoinType, string, string, string) bool); ok { r1 = rf(ctx, senderChainID, receiverChainID, coinType, voter, ballotIndex, inTxHash) } else { - r1 = ret.Error(1) + r1 = ret.Get(1).(bool) } - return r0, r1 + if rf, ok := ret.Get(2).(func(types.Context, int64, int64, common.CoinType, string, string, string) error); ok { + r2 = rf(ctx, senderChainID, receiverChainID, coinType, voter, ballotIndex, inTxHash) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 } // VoteOnOutboundBallot provides a mock function with given fields: ctx, ballotIndex, outTxChainID, receiveStatus, voter diff --git a/testutil/keeper/mocks/crosschain/staking.go b/testutil/keeper/mocks/crosschain/staking.go index 64bbe0fed6..5b7d3c501f 100644 --- a/testutil/keeper/mocks/crosschain/staking.go +++ b/testutil/keeper/mocks/crosschain/staking.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.39.1. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/fungible/account.go b/testutil/keeper/mocks/fungible/account.go index 94b7a84d75..0522e833b4 100644 --- a/testutil/keeper/mocks/fungible/account.go +++ b/testutil/keeper/mocks/fungible/account.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.39.1. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/fungible/bank.go b/testutil/keeper/mocks/fungible/bank.go index 20a2590911..db14226310 100644 --- a/testutil/keeper/mocks/fungible/bank.go +++ b/testutil/keeper/mocks/fungible/bank.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.39.1. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/fungible/evm.go b/testutil/keeper/mocks/fungible/evm.go index f0dcd01094..28fd46e25c 100644 --- a/testutil/keeper/mocks/fungible/evm.go +++ b/testutil/keeper/mocks/fungible/evm.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.39.1. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/fungible/observer.go b/testutil/keeper/mocks/fungible/observer.go index 3a4685f3b2..3010f8faaf 100644 --- a/testutil/keeper/mocks/fungible/observer.go +++ b/testutil/keeper/mocks/fungible/observer.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.39.1. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/observer/slashing.go b/testutil/keeper/mocks/observer/slashing.go index d3f64ff726..a7793ef8dc 100644 --- a/testutil/keeper/mocks/observer/slashing.go +++ b/testutil/keeper/mocks/observer/slashing.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.39.1. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks diff --git a/testutil/keeper/mocks/observer/staking.go b/testutil/keeper/mocks/observer/staking.go index 72fe2be116..90007b6c35 100644 --- a/testutil/keeper/mocks/observer/staking.go +++ b/testutil/keeper/mocks/observer/staking.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.39.1. DO NOT EDIT. +// Code generated by mockery v2.38.0. DO NOT EDIT. package mocks diff --git a/testutil/network/network_setup.go b/testutil/network/network_setup.go index 08bc9277fd..987bb38fe5 100644 --- a/testutil/network/network_setup.go +++ b/testutil/network/network_setup.go @@ -528,6 +528,8 @@ func (n *Network) WaitForHeightWithTimeout(h int64, t time.Duration) (int64, err if latestHeight >= h { return latestHeight, nil } + } else if err != nil { + fmt.Printf("error trying to fetch block height: %v\n", err) } } } diff --git a/x/crosschain/client/integrationtests/inbound_voter_test.go b/x/crosschain/client/integrationtests/inbound_voter_test.go index 32da0d92db..126e0b421d 100644 --- a/x/crosschain/client/integrationtests/inbound_voter_test.go +++ b/x/crosschain/client/integrationtests/inbound_voter_test.go @@ -261,7 +261,7 @@ func (s *IntegrationTestSuite) TestCCTXInboundVoter() { message = message + "falseVote" } signedTx := BuildSignedInboundVote(s.T(), val, s.cfg.BondDenom, account, message, i) - out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetBroadcastCommand(), []string{signedTx.Name(), "--broadcast-mode", "sync"}) + out, err = clitestutil.ExecTestCLICmd(broadcaster.ClientCtx, authcli.GetBroadcastCommand(), []string{signedTx.Name(), "--broadcast-mode", "block"}) s.Require().NoError(err) fmt.Println(out.String()) } @@ -275,7 +275,7 @@ func (s *IntegrationTestSuite) TestCCTXInboundVoter() { s.NoError(broadcaster.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &ballot)) // Check the vote in the ballot - s.Assert().Equal(len(test.votes), len(ballot.Voters)) + s.Require().Equal(len(test.votes), len(ballot.Voters)) for _, vote := range ballot.Voters { if test.votes[vote.VoterAddress] == observerTypes.VoteType_FailureObservation { s.Assert().Equal(observerTypes.VoteType_NotYetVoted.String(), vote.VoteType.String()) diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index 9bd5f3daa4..7abb696ee8 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -58,13 +58,8 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg ctx := sdk.UnwrapSDKContext(goCtx) index := msg.Digest() - // Check if the inbound has already been processed. - if k.IsFinalizedInbound(ctx, msg.InTxHash, msg.SenderChainId, msg.EventIndex) { - return nil, errorsmod.Wrap(types.ErrObservedTxAlreadyFinalized, fmt.Sprintf("InTxHash:%s, SenderChainID:%d, EventIndex:%d", msg.InTxHash, msg.SenderChainId, msg.EventIndex)) - } - // vote on inbound ballot - finalized, err := k.zetaObserverKeeper.VoteOnInboundBallot( + finalized, isNew, err := k.zetaObserverKeeper.VoteOnInboundBallot( ctx, msg.SenderChainId, msg.ReceiverChain, @@ -76,8 +71,18 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg if err != nil { return nil, err } + + // 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(ctx, msg.InTxHash, msg.SenderChainId, msg.EventIndex) { + return nil, errorsmod.Wrap(types.ErrObservedTxAlreadyFinalized, fmt.Sprintf("InTxHash:%s, SenderChainID:%d, EventIndex:%d", msg.InTxHash, msg.SenderChainId, msg.EventIndex)) + } + } + + // If the ballot is not finalized return nil here to add vote to commit state if !finalized { - // Return nil here to add vote to ballot and commit state return &types.MsgVoteOnObservedInboundTxResponse{}, nil } diff --git a/x/crosschain/types/expected_keepers.go b/x/crosschain/types/expected_keepers.go index 036edc76e1..d8d73487fa 100644 --- a/x/crosschain/types/expected_keepers.go +++ b/x/crosschain/types/expected_keepers.go @@ -80,7 +80,7 @@ type ObserverKeeper interface { voter string, ballotIndex string, inTxHash string, - ) (bool, error) + ) (bool, bool, error) VoteOnOutboundBallot( ctx sdk.Context, ballotIndex string, diff --git a/x/observer/genesis_test.go b/x/observer/genesis_test.go index 56cc00352f..73193de928 100644 --- a/x/observer/genesis_test.go +++ b/x/observer/genesis_test.go @@ -44,7 +44,7 @@ func TestGenesis(t *testing.T) { } // Init and export - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) observer.InitGenesis(ctx, *k, genesisState) got := observer.ExportGenesis(ctx, *k) require.NotNil(t, got) diff --git a/x/observer/keeper/vote_inbound.go b/x/observer/keeper/vote_inbound.go index ab707063e8..2f5ae16a46 100644 --- a/x/observer/keeper/vote_inbound.go +++ b/x/observer/keeper/vote_inbound.go @@ -20,9 +20,9 @@ func (k Keeper) VoteOnInboundBallot( voter string, ballotIndex string, inTxHash string, -) (bool, error) { +) (bool, bool, error) { if !k.IsInboundEnabled(ctx) { - return false, types.ErrInboundDisabled + return false, false, types.ErrInboundDisabled } // makes sure we are getting only supported chains @@ -30,7 +30,7 @@ func (k Keeper) VoteOnInboundBallot( // this function returns nil senderChain := k.GetSupportedChainFromChainID(ctx, senderChainID) if senderChain == nil { - return false, sdkerrors.Wrap(types.ErrSupportedChains, fmt.Sprintf( + return false, false, sdkerrors.Wrap(types.ErrSupportedChains, fmt.Sprintf( "ChainID %d, Observation %s", senderChainID, types.ObservationType_InBoundTx.String()), @@ -39,13 +39,13 @@ func (k Keeper) VoteOnInboundBallot( // checks the voter is authorized to vote on the observation chain if ok := k.IsAuthorized(ctx, voter); !ok { - return false, types.ErrNotObserver + return false, false, types.ErrNotObserver } // makes sure we are getting only supported chains receiverChain := k.GetSupportedChainFromChainID(ctx, receiverChainID) if receiverChain == nil { - return false, sdkerrors.Wrap(types.ErrSupportedChains, fmt.Sprintf( + return false, false, sdkerrors.Wrap(types.ErrSupportedChains, fmt.Sprintf( "ChainID %d, Observation %s", receiverChainID, types.ObservationType_InBoundTx.String()), @@ -56,17 +56,17 @@ func (k Keeper) VoteOnInboundBallot( if receiverChain.IsExternalChain() { coreParams, found := k.GetChainParamsByChainID(ctx, receiverChain.ChainId) if !found { - return false, types.ErrChainParamsNotFound + return false, false, types.ErrChainParamsNotFound } if coreParams.ZetaTokenContractAddress == "" && coinType == common.CoinType_Zeta { - return false, types.ErrInvalidZetaCoinTypes + return false, false, types.ErrInvalidZetaCoinTypes } } // checks against the supported chains list before querying for Ballot ballot, isNew, err := k.FindBallot(ctx, ballotIndex, senderChain, types.ObservationType_InBoundTx) if err != nil { - return false, err + return false, false, err } if isNew { EmitEventBallotCreated(ctx, ballot, inTxHash, senderChain.String()) @@ -75,10 +75,10 @@ func (k Keeper) VoteOnInboundBallot( // adds a vote and sets the ballot ballot, err = k.AddVoteToBallot(ctx, ballot, voter, types.VoteType_SuccessObservation) if err != nil { - return false, err + return false, false, err } // checks if the ballot is finalized _, isFinalized := k.CheckIfFinalizingVote(ctx, ballot) - return isFinalized, nil + return isFinalized, false, nil } diff --git a/x/observer/keeper/vote_inbound_test.go b/x/observer/keeper/vote_inbound_test.go index 3420d48b45..7f6c9fb81d 100644 --- a/x/observer/keeper/vote_inbound_test.go +++ b/x/observer/keeper/vote_inbound_test.go @@ -20,7 +20,7 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { IsInboundEnabled: false, }) - _, err := k.VoteOnInboundBallot( + _, _, err := k.VoteOnInboundBallot( ctx, getValidEthChainIDWithIndex(t, 0), common.ZetaPrivnetChain().ChainId, @@ -42,7 +42,7 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { }) k.SetChainParamsList(ctx, types.ChainParamsList{}) - _, err := k.VoteOnInboundBallot( + _, _, err := k.VoteOnInboundBallot( ctx, getValidEthChainIDWithIndex(t, 0), common.ZetaPrivnetChain().ChainId, @@ -64,7 +64,7 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { }, }) - _, err = k.VoteOnInboundBallot( + _, _, err = k.VoteOnInboundBallot( ctx, getValidEthChainIDWithIndex(t, 0), common.ZetaPrivnetChain().ChainId, @@ -93,7 +93,7 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { }) k.SetObserverSet(ctx, types.ObserverSet{}) - _, err := k.VoteOnInboundBallot( + _, _, err := k.VoteOnInboundBallot( ctx, getValidEthChainIDWithIndex(t, 0), common.ZetaPrivnetChain().ChainId, @@ -130,7 +130,7 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { stakingMock.MockGetValidator(sample.Validator(t, sample.Rand())) slashingMock.MockIsTombstoned(false) - _, err := k.VoteOnInboundBallot( + _, _, err := k.VoteOnInboundBallot( ctx, getValidEthChainIDWithIndex(t, 0), common.ZetaPrivnetChain().ChainId, @@ -158,7 +158,7 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { stakingMock.MockGetValidator(sample.Validator(t, sample.Rand())) slashingMock.MockIsTombstoned(false) - _, err = k.VoteOnInboundBallot( + _, _, err = k.VoteOnInboundBallot( ctx, getValidEthChainIDWithIndex(t, 0), common.ZetaPrivnetChain().ChainId, @@ -200,7 +200,7 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { stakingMock.MockGetValidator(sample.Validator(t, sample.Rand())) slashingMock.MockIsTombstoned(false) - _, err := k.VoteOnInboundBallot( + _, _, err := k.VoteOnInboundBallot( ctx, getValidEthChainIDWithIndex(t, 0), getValidEthChainIDWithIndex(t, 1), @@ -241,7 +241,7 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { stakingMock.MockGetValidator(sample.Validator(t, sample.Rand())) slashingMock.MockIsTombstoned(false) - isFinalized, err := k.VoteOnInboundBallot( + isFinalized, isNew, err := k.VoteOnInboundBallot( ctx, getValidEthChainIDWithIndex(t, 0), getValidEthChainIDWithIndex(t, 1), @@ -254,6 +254,7 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { // ballot should be finalized since there is only one observer require.True(t, isFinalized) + require.True(t, isNew) }) t.Run("can add vote to an existing ballot", func(t *testing.T) { @@ -304,7 +305,7 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { } k.SetBallot(ctx, &ballot) - isFinalized, err := k.VoteOnInboundBallot( + isFinalized, isNew, err := k.VoteOnInboundBallot( ctx, getValidEthChainIDWithIndex(t, 0), getValidEthChainIDWithIndex(t, 1), @@ -317,5 +318,6 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { // ballot should not be finalized as the threshold is not reached require.False(t, isFinalized) + require.False(t, isNew) }) } diff --git a/x/observer/migrations/v3/migrate_test.go b/x/observer/migrations/v3/migrate_test.go index 604fd0a9c7..ce580cbf42 100644 --- a/x/observer/migrations/v3/migrate_test.go +++ b/x/observer/migrations/v3/migrate_test.go @@ -11,7 +11,7 @@ import ( ) func TestMigrateStore(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) // nothing if no admin policy params := types.DefaultParams() diff --git a/x/observer/migrations/v4/migrate_test.go b/x/observer/migrations/v4/migrate_test.go index a5bfd67f56..55c87d6541 100644 --- a/x/observer/migrations/v4/migrate_test.go +++ b/x/observer/migrations/v4/migrate_test.go @@ -11,7 +11,7 @@ import ( ) func TestMigrateCrosschainFlags(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) store := prefix.NewStore(ctx.KVStore(k.StoreKey()), types.KeyPrefix(types.CrosschainFlagsKey)) legacyFlags := types.LegacyCrosschainFlags{ IsInboundEnabled: false, diff --git a/x/observer/migrations/v5/migrate_test.go b/x/observer/migrations/v5/migrate_test.go index 8b83d5d0ed..f5aa035414 100644 --- a/x/observer/migrations/v5/migrate_test.go +++ b/x/observer/migrations/v5/migrate_test.go @@ -15,7 +15,7 @@ import ( func TestMigrateObserverMapper(t *testing.T) { t.Run("TestMigrateStore", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) legacyObserverMapperStore := prefix.NewStore(ctx.KVStore(k.StoreKey()), types.KeyPrefix(types.ObserverMapperKey)) legacyObserverMapperList := sample.LegacyObserverMapperList(t, 12, "sample") for _, legacyObserverMapper := range legacyObserverMapperList { @@ -43,7 +43,7 @@ func TestMigrateObserverMapper(t *testing.T) { } func TestMigrateObserverParams(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) // set chain params previousChainParamsList := types.ChainParamsList{ diff --git a/x/observer/migrations/v6/migrate_test.go b/x/observer/migrations/v6/migrate_test.go index 925c1b0b32..b99242aabc 100644 --- a/x/observer/migrations/v6/migrate_test.go +++ b/x/observer/migrations/v6/migrate_test.go @@ -12,7 +12,7 @@ import ( func TestMigrateObserverParams(t *testing.T) { t.Run("Migrate when keygen is Pending", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) k.SetKeygen(ctx, types.Keygen{ Status: types.KeygenStatus_PendingKeygen, BlockNumber: math.MaxInt64, @@ -57,7 +57,7 @@ func TestMigrateObserverParams(t *testing.T) { require.Equal(t, participantList, participantList) }) t.Run("Migrate when keygen is not Pending", func(t *testing.T) { - k, ctx := keepertest.ObserverKeeper(t) + k, ctx, _ := keepertest.ObserverKeeper(t) participantList := []string{ "zetapub1addwnpepqglunjrgl3qg08duxq9pf28jmvrer3crwnnfzp6m0u0yh9jk9mnn5p76utc", "zetapub1addwnpepqwwpjwwnes7cywfkr0afme7ymk8rf5jzhn8pfr6qqvfm9v342486qsrh4f5", From 78c3c0c93c94d730cc25f8727e51a597822b4e43 Mon Sep 17 00:00:00 2001 From: lumtis Date: Wed, 21 Feb 2024 12:22:21 +0100 Subject: [PATCH 21/24] add tests back --- .../integrationtests/inbound_voter_test.go | 172 ++++++++--------- .../integrationtests/outbound_voter_test.go | 180 +++++++++--------- 2 files changed, 176 insertions(+), 176 deletions(-) diff --git a/x/crosschain/client/integrationtests/inbound_voter_test.go b/x/crosschain/client/integrationtests/inbound_voter_test.go index 126e0b421d..50cf041a64 100644 --- a/x/crosschain/client/integrationtests/inbound_voter_test.go +++ b/x/crosschain/client/integrationtests/inbound_voter_test.go @@ -136,92 +136,92 @@ func (s *IntegrationTestSuite) TestCCTXInboundVoter() { ballotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, }, - //{ - // name: "5 votes only ballot does not get finalized", - // votes: map[string]observerTypes.VoteType{ - // "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, - // "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, - // "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, - // "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_SuccessObservation, - // "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_SuccessObservation, - // "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_NotYetVoted, - // "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_NotYetVoted, - // "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_NotYetVoted, - // "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_NotYetVoted, - // "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_NotYetVoted, - // }, - // ballotResult: observerTypes.BallotStatus_BallotInProgress, - // cctxStatus: crosschaintypes.CctxStatus_PendingRevert, - //}, - //{ - // name: "1 false vote but correct ballot is still finalized", - // votes: map[string]observerTypes.VoteType{ - // "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, - // "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, - // "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, - // "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_SuccessObservation, - // "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_SuccessObservation, - // "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_SuccessObservation, - // "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_SuccessObservation, - // "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_FailureObservation, - // "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_SuccessObservation, - // "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_NotYetVoted, - // }, - // ballotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, - // cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, - //}, - //{ - // name: "2 ballots with 5 votes each no ballot gets finalized", - // votes: map[string]observerTypes.VoteType{ - // "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, - // "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, - // "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, - // "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_SuccessObservation, - // "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_SuccessObservation, - // "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_FailureObservation, - // "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_FailureObservation, - // "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_FailureObservation, - // "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_FailureObservation, - // "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_FailureObservation, - // }, - // ballotResult: observerTypes.BallotStatus_BallotInProgress, - // cctxStatus: crosschaintypes.CctxStatus_PendingRevert, - //}, - //{ - // name: "majority wrong votes incorrect ballot finalized / correct ballot still in progress", - // votes: map[string]observerTypes.VoteType{ - // "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, - // "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, - // "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, - // "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_FailureObservation, - // "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_FailureObservation, - // "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_FailureObservation, - // "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_FailureObservation, - // "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_FailureObservation, - // "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_FailureObservation, - // "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_FailureObservation, - // }, - // ballotResult: observerTypes.BallotStatus_BallotInProgress, - // cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, - // falseBallotIdentifier: "majority wrong votes incorrect ballot finalized / correct ballot still in progress" + "falseVote", - //}, - //{ - // name: "7 votes only just crossed threshold", - // votes: map[string]observerTypes.VoteType{ - // "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, - // "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, - // "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, - // "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_SuccessObservation, - // "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_SuccessObservation, - // "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_NotYetVoted, - // "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_SuccessObservation, - // "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_NotYetVoted, - // "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_NotYetVoted, - // "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_SuccessObservation, - // }, - // ballotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, - // cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, - //}, + { + name: "5 votes only ballot does not get finalized", + votes: map[string]observerTypes.VoteType{ + "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, + "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, + "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, + "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_SuccessObservation, + "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_SuccessObservation, + "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_NotYetVoted, + "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_NotYetVoted, + "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_NotYetVoted, + "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_NotYetVoted, + "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_NotYetVoted, + }, + ballotResult: observerTypes.BallotStatus_BallotInProgress, + cctxStatus: crosschaintypes.CctxStatus_PendingRevert, + }, + { + name: "1 false vote but correct ballot is still finalized", + votes: map[string]observerTypes.VoteType{ + "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, + "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, + "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, + "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_SuccessObservation, + "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_SuccessObservation, + "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_SuccessObservation, + "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_SuccessObservation, + "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_FailureObservation, + "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_SuccessObservation, + "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_NotYetVoted, + }, + ballotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, + cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, + }, + { + name: "2 ballots with 5 votes each no ballot gets finalized", + votes: map[string]observerTypes.VoteType{ + "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, + "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, + "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, + "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_SuccessObservation, + "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_SuccessObservation, + "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_FailureObservation, + "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_FailureObservation, + "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_FailureObservation, + "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_FailureObservation, + "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_FailureObservation, + }, + ballotResult: observerTypes.BallotStatus_BallotInProgress, + cctxStatus: crosschaintypes.CctxStatus_PendingRevert, + }, + { + name: "majority wrong votes incorrect ballot finalized / correct ballot still in progress", + votes: map[string]observerTypes.VoteType{ + "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, + "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, + "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, + "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_FailureObservation, + "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_FailureObservation, + "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_FailureObservation, + "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_FailureObservation, + "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_FailureObservation, + "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_FailureObservation, + "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_FailureObservation, + }, + ballotResult: observerTypes.BallotStatus_BallotInProgress, + cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, + falseBallotIdentifier: "majority wrong votes incorrect ballot finalized / correct ballot still in progress" + "falseVote", + }, + { + name: "7 votes only just crossed threshold", + votes: map[string]observerTypes.VoteType{ + "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax": observerTypes.VoteType_SuccessObservation, + "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2": observerTypes.VoteType_SuccessObservation, + "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4": observerTypes.VoteType_SuccessObservation, + "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c": observerTypes.VoteType_SuccessObservation, + "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca": observerTypes.VoteType_SuccessObservation, + "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt": observerTypes.VoteType_NotYetVoted, + "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4": observerTypes.VoteType_SuccessObservation, + "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy": observerTypes.VoteType_NotYetVoted, + "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav": observerTypes.VoteType_NotYetVoted, + "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t": observerTypes.VoteType_SuccessObservation, + }, + ballotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, + cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, + }, } for i, test := range tt { test := test diff --git a/x/crosschain/client/integrationtests/outbound_voter_test.go b/x/crosschain/client/integrationtests/outbound_voter_test.go index f35bba271b..d388adc003 100644 --- a/x/crosschain/client/integrationtests/outbound_voter_test.go +++ b/x/crosschain/client/integrationtests/outbound_voter_test.go @@ -24,96 +24,96 @@ func (s *IntegrationTestSuite) TestCCTXOutBoundVoter() { cctxStatus crosschaintypes.CctxStatus falseBallotIdentifier string }{ - //{ - // name: "All observers voted success or not voted", - // votes: []Vote{ - // {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_NotYetVoted, isFakeVote: false}, - // }, - // correctBallotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, - // cctxStatus: crosschaintypes.CctxStatus_OutboundMined, - // valueReceived: "7991636132140714751", - //}, - //{ - // name: "1 fake vote but ballot still success", - // votes: []Vote{ - // {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - // {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // }, - // correctBallotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, - // cctxStatus: crosschaintypes.CctxStatus_OutboundMined, - // valueReceived: "7990439496224753106", - //}, - //{ - // name: "Half success and half false", - // votes: []Vote{ - // {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - // {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - // {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - // {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - // {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - // }, - // correctBallotResult: observerTypes.BallotStatus_BallotInProgress, - // cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, - // valueReceived: "7990439496224753106", - //}, - //{ - // name: "Fake ballot has more votes outbound gets finalized", - // votes: []Vote{ - // {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - // {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - // {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - // {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - // {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - // {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - // {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - // {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, - // }, - // correctBallotResult: observerTypes.BallotStatus_BallotInProgress, - // cctxStatus: crosschaintypes.CctxStatus_OutboundMined, - // valueReceived: "7987124742653889020", - //}, - //{ - // name: "5 success 5 Failed votes ", - // votes: []Vote{ - // {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, - // {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, - // {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, - // {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, - // {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, - // {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, - // }, - // correctBallotResult: observerTypes.BallotStatus_BallotInProgress, - // cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, - // valueReceived: "7991636132140714751", - //}, + { + name: "All observers voted success or not voted", + votes: []Vote{ + {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_NotYetVoted, isFakeVote: false}, + }, + correctBallotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, + cctxStatus: crosschaintypes.CctxStatus_OutboundMined, + valueReceived: "7991636132140714751", + }, + { + name: "1 fake vote but ballot still success", + votes: []Vote{ + {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + }, + correctBallotResult: observerTypes.BallotStatus_BallotFinalized_SuccessObservation, + cctxStatus: crosschaintypes.CctxStatus_OutboundMined, + valueReceived: "7990439496224753106", + }, + { + name: "Half success and half false", + votes: []Vote{ + {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + }, + correctBallotResult: observerTypes.BallotStatus_BallotInProgress, + cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, + valueReceived: "7990439496224753106", + }, + { + name: "Fake ballot has more votes outbound gets finalized", + votes: []Vote{ + {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: true}, + }, + correctBallotResult: observerTypes.BallotStatus_BallotInProgress, + cctxStatus: crosschaintypes.CctxStatus_OutboundMined, + valueReceived: "7987124742653889020", + }, + { + name: "5 success 5 Failed votes ", + votes: []Vote{ + {voterAddress: "zeta13c7p3xrhd6q2rx3h235jpt8pjdwvacyw6twpax", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1f203dypqg5jh9hqfx0gfkmmnkdfuat3jr45ep2", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1szrskhdeleyt6wmn0nfxvcvt2l6f4fn06uaga4", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta16h3y7s7030l4chcznwq3n6uz2m9wvmzu5vwt7c", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1xl2rfsrmx8nxryty3lsjuxwdxs59cn2q65e5ca", voteType: observerTypes.VoteType_SuccessObservation, isFakeVote: false}, + {voterAddress: "zeta1ktmprjdvc72jq0mpu8tn8sqx9xwj685qx0q6kt", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, + {voterAddress: "zeta1ygeyr8pqfjvclxay5234gulnjzv2mkz6lph9y4", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, + {voterAddress: "zeta1zegyenj7xg5nck04ykkzndm2qxdzc6v83mklsy", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, + {voterAddress: "zeta1us2qpqdcctk6q7qv2c9d9jvjxlv88jscf68kav", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, + {voterAddress: "zeta1e9fyaulgntkrnqnl0es4nyxghp3petpn2ntu3t", voteType: observerTypes.VoteType_FailureObservation, isFakeVote: false}, + }, + correctBallotResult: observerTypes.BallotStatus_BallotInProgress, + cctxStatus: crosschaintypes.CctxStatus_PendingOutbound, + valueReceived: "7991636132140714751", + }, } for i, test := range tt { // Buffer event index so that it does not clash with the inbound voter test From 76e2198cc6aa3ed3dfbfd0992456bcebda74e2d3 Mon Sep 17 00:00:00 2001 From: lumtis Date: Wed, 21 Feb 2024 13:04:13 +0100 Subject: [PATCH 22/24] use tmp context for ballot logic --- x/crosschain/keeper/msg_server_vote_inbound_tx.go | 12 +++++++++--- .../keeper/msg_server_vote_inbound_tx_test.go | 2 ++ x/observer/keeper/vote_inbound.go | 4 ++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index 7abb696ee8..61e52d5aa0 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -59,8 +59,10 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg index := msg.Digest() // vote on inbound ballot + // use a temporary context to not commit any ballot state change in case of error + tmpCtx, commit := ctx.CacheContext() finalized, isNew, err := k.zetaObserverKeeper.VoteOnInboundBallot( - ctx, + tmpCtx, msg.SenderChainId, msg.ReceiverChain, msg.CoinType, @@ -77,9 +79,13 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg // This check prevents double spending if isNew { if k.IsFinalizedInbound(ctx, msg.InTxHash, msg.SenderChainId, msg.EventIndex) { - return nil, errorsmod.Wrap(types.ErrObservedTxAlreadyFinalized, fmt.Sprintf("InTxHash:%s, SenderChainID:%d, EventIndex:%d", msg.InTxHash, msg.SenderChainId, msg.EventIndex)) + return nil, errorsmod.Wrap( + types.ErrObservedTxAlreadyFinalized, + fmt.Sprintf("InTxHash:%s, SenderChainID:%d, EventIndex:%d", msg.InTxHash, msg.SenderChainId, msg.EventIndex), + ) } } + commit() // If the ballot is not finalized return nil here to add vote to commit state if !finalized { @@ -181,7 +187,7 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg } // Receiver is not ZetaChain: Cross Chain SWAP - tmpCtx, commit := ctx.CacheContext() + tmpCtx, commit = ctx.CacheContext() err = func() error { err := k.PayGasAndUpdateCctx( tmpCtx, diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go index 1a8c742c5b..d816f62446 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go @@ -123,6 +123,7 @@ func TestNoDoubleEventProtections(t *testing.T) { ballot, found := zk.ObserverKeeper.GetBallot(ctx, msg.Digest()) require.True(t, found) require.Equal(t, ballot.BallotStatus, observerTypes.BallotStatus_BallotFinalized_SuccessObservation) + //Perform the SAME event. Except, this time, we resubmit the event. msg2 := &types.MsgVoteOnObservedInboundTx{ Creator: validatorAddr, @@ -145,6 +146,7 @@ func TestNoDoubleEventProtections(t *testing.T) { ctx, msg2, ) + require.Error(t, err) require.ErrorIs(t, err, types.ErrObservedTxAlreadyFinalized) _, found = zk.ObserverKeeper.GetBallot(ctx, msg2.Digest()) require.False(t, found) diff --git a/x/observer/keeper/vote_inbound.go b/x/observer/keeper/vote_inbound.go index 2f5ae16a46..5bc70ede88 100644 --- a/x/observer/keeper/vote_inbound.go +++ b/x/observer/keeper/vote_inbound.go @@ -75,10 +75,10 @@ func (k Keeper) VoteOnInboundBallot( // adds a vote and sets the ballot ballot, err = k.AddVoteToBallot(ctx, ballot, voter, types.VoteType_SuccessObservation) if err != nil { - return false, false, err + return false, isNew, err } // checks if the ballot is finalized _, isFinalized := k.CheckIfFinalizingVote(ctx, ballot) - return isFinalized, false, nil + return isFinalized, isNew, nil } From e0395310969724105e95f69f41fe5832d83171a5 Mon Sep 17 00:00:00 2001 From: lumtis Date: Wed, 28 Feb 2024 09:29:01 +0100 Subject: [PATCH 23/24] add new test for finalized ballot --- .../keeper/msg_server_vote_inbound_tx.go | 2 +- .../keeper/msg_server_vote_inbound_tx_test.go | 152 +++++++++--------- x/observer/keeper/vote_inbound_test.go | 62 +++++++ x/observer/keeper/vote_outbound_test.go | 56 +++++++ 4 files changed, 195 insertions(+), 77 deletions(-) diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index eeaa8d41a3..db287e6b82 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -77,7 +77,7 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg // 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(ctx, msg.InTxHash, msg.SenderChainId, msg.EventIndex) { + if k.IsFinalizedInbound(tmpCtx, msg.InTxHash, msg.SenderChainId, msg.EventIndex) { return nil, cosmoserrors.Wrap( types.ErrObservedTxAlreadyFinalized, fmt.Sprintf("InTxHash:%s, SenderChainID:%d, EventIndex:%d", msg.InTxHash, msg.SenderChainId, msg.EventIndex), diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go index c42dddd7a3..803de84576 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx_test.go @@ -33,6 +33,9 @@ func setObservers(t *testing.T, k *keeper.Keeper, ctx sdk.Context, zk keepertest }) return validatorAddressListFormatted } + +// TODO: Complete the test cases +// https://github.com/zeta-chain/node/issues/1542 func TestKeeper_VoteOnObservedInboundTx(t *testing.T) { t.Run("successfully vote on evm deposit", func(t *testing.T) { k, ctx, _, zk := keepertest.CrosschainKeeper(t) @@ -69,91 +72,88 @@ func TestKeeper_VoteOnObservedInboundTx(t *testing.T) { require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_OutboundMined) require.Equal(t, cctx.InboundTxParams.TxFinalizationStatus, types.TxFinalizationStatus_Executed) }) - // TODO : https://github.com/zeta-chain/node/issues/1542 -} -/* -Potential Double Event Submission -*/ -func TestNoDoubleEventProtections(t *testing.T) { - k, ctx, _, zk := keepertest.CrosschainKeeper(t) + t.Run("prevent double event submission", func(t *testing.T) { + k, ctx, _, zk := keepertest.CrosschainKeeper(t) - // MsgServer for the crosschain keeper - msgServer := keeper.NewMsgServerImpl(*k) + // MsgServer for the crosschain keeper + msgServer := keeper.NewMsgServerImpl(*k) - // Set the chain ids we want to use to be valid - params := observertypes.DefaultParams() - zk.ObserverKeeper.SetParams( - ctx, params, - ) + // Set the chain ids we want to use to be valid + params := observertypes.DefaultParams() + zk.ObserverKeeper.SetParams( + ctx, params, + ) - // Convert the validator address into a user address. - validators := k.GetStakingKeeper().GetAllValidators(ctx) - validatorAddress := validators[0].OperatorAddress - valAddr, _ := sdk.ValAddressFromBech32(validatorAddress) - addresstmp, _ := sdk.AccAddressFromHexUnsafe(hex.EncodeToString(valAddr.Bytes())) - validatorAddr := addresstmp.String() + // Convert the validator address into a user address. + validators := k.GetStakingKeeper().GetAllValidators(ctx) + validatorAddress := validators[0].OperatorAddress + valAddr, _ := sdk.ValAddressFromBech32(validatorAddress) + addresstmp, _ := sdk.AccAddressFromHexUnsafe(hex.EncodeToString(valAddr.Bytes())) + validatorAddr := addresstmp.String() - // Add validator to the observer list for voting - zk.ObserverKeeper.SetObserverSet(ctx, observertypes.ObserverSet{ - ObserverList: []string{validatorAddr}, - }) + // Add validator to the observer list for voting + zk.ObserverKeeper.SetObserverSet(ctx, observertypes.ObserverSet{ + ObserverList: []string{validatorAddr}, + }) - // Vote on the FIRST message. - msg := &types.MsgVoteOnObservedInboundTx{ - Creator: validatorAddr, - Sender: "0x954598965C2aCdA2885B037561526260764095B8", - SenderChainId: 1337, // ETH - Receiver: "0x954598965C2aCdA2885B037561526260764095B8", - ReceiverChain: 101, // zetachain - Amount: sdkmath.NewUintFromString("10000000"), - Message: "", - InBlockHeight: 1, - GasLimit: 1000000000, - InTxHash: "0x7a900ef978743f91f57ca47c6d1a1add75df4d3531da17671e9cf149e1aefe0b", - CoinType: 0, // zeta - TxOrigin: "0x954598965C2aCdA2885B037561526260764095B8", - Asset: "", - EventIndex: 1, - } - _, err := msgServer.VoteOnObservedInboundTx( - ctx, - msg, - ) - require.NoError(t, err) + // Vote on the FIRST message. + msg := &types.MsgVoteOnObservedInboundTx{ + Creator: validatorAddr, + Sender: "0x954598965C2aCdA2885B037561526260764095B8", + SenderChainId: 1337, // ETH + Receiver: "0x954598965C2aCdA2885B037561526260764095B8", + ReceiverChain: 101, // zetachain + Amount: sdkmath.NewUintFromString("10000000"), + Message: "", + InBlockHeight: 1, + GasLimit: 1000000000, + InTxHash: "0x7a900ef978743f91f57ca47c6d1a1add75df4d3531da17671e9cf149e1aefe0b", + CoinType: 0, // zeta + TxOrigin: "0x954598965C2aCdA2885B037561526260764095B8", + Asset: "", + EventIndex: 1, + } + _, err := msgServer.VoteOnObservedInboundTx( + ctx, + msg, + ) + require.NoError(t, err) - // Check that the vote passed - ballot, found := zk.ObserverKeeper.GetBallot(ctx, msg.Digest()) - require.True(t, found) - require.Equal(t, ballot.BallotStatus, observertypes.BallotStatus_BallotFinalized_SuccessObservation) - //Perform the SAME event. Except, this time, we resubmit the event. - msg2 := &types.MsgVoteOnObservedInboundTx{ - Creator: validatorAddr, - Sender: "0x954598965C2aCdA2885B037561526260764095B8", - SenderChainId: 1337, - Receiver: "0x954598965C2aCdA2885B037561526260764095B8", - ReceiverChain: 101, - Amount: sdkmath.NewUintFromString("10000000"), - Message: "", - InBlockHeight: 1, - GasLimit: 1000000001, // <---- Change here - InTxHash: "0x7a900ef978743f91f57ca47c6d1a1add75df4d3531da17671e9cf149e1aefe0b", - CoinType: 0, - TxOrigin: "0x954598965C2aCdA2885B037561526260764095B8", - Asset: "", - EventIndex: 1, - } + // Check that the vote passed + ballot, found := zk.ObserverKeeper.GetBallot(ctx, msg.Digest()) + require.True(t, found) + require.Equal(t, ballot.BallotStatus, observertypes.BallotStatus_BallotFinalized_SuccessObservation) + //Perform the SAME event. Except, this time, we resubmit the event. + msg2 := &types.MsgVoteOnObservedInboundTx{ + Creator: validatorAddr, + Sender: "0x954598965C2aCdA2885B037561526260764095B8", + SenderChainId: 1337, + Receiver: "0x954598965C2aCdA2885B037561526260764095B8", + ReceiverChain: 101, + Amount: sdkmath.NewUintFromString("10000000"), + Message: "", + InBlockHeight: 1, + GasLimit: 1000000001, // <---- Change here + InTxHash: "0x7a900ef978743f91f57ca47c6d1a1add75df4d3531da17671e9cf149e1aefe0b", + CoinType: 0, + TxOrigin: "0x954598965C2aCdA2885B037561526260764095B8", + Asset: "", + EventIndex: 1, + } - _, err = msgServer.VoteOnObservedInboundTx( - ctx, - msg2, - ) - require.Error(t, err) - require.ErrorIs(t, err, types.ErrObservedTxAlreadyFinalized) - _, found = zk.ObserverKeeper.GetBallot(ctx, msg2.Digest()) - require.False(t, found) + _, err = msgServer.VoteOnObservedInboundTx( + ctx, + msg2, + ) + require.Error(t, err) + require.ErrorIs(t, err, types.ErrObservedTxAlreadyFinalized) + _, found = zk.ObserverKeeper.GetBallot(ctx, msg2.Digest()) + require.False(t, found) + }) } -func TestStatus_StatusTransition(t *testing.T) { + +func TestStatus_ChangeStatus(t *testing.T) { tt := []struct { Name string Status types.Status diff --git a/x/observer/keeper/vote_inbound_test.go b/x/observer/keeper/vote_inbound_test.go index 7f6c9fb81d..aa10c85af1 100644 --- a/x/observer/keeper/vote_inbound_test.go +++ b/x/observer/keeper/vote_inbound_test.go @@ -320,4 +320,66 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { require.False(t, isFinalized) require.False(t, isNew) }) + + t.Run("can add vote to an existing ballot and finalize ballot", func(t *testing.T) { + k, ctx, _ := keepertest.ObserverKeeperWithMocks(t, keepertest.ObserverMocksAll) + + observer := sample.AccAddress() + stakingMock := keepertest.GetObserverStakingMock(t, k) + slashingMock := keepertest.GetObserverSlashingMock(t, k) + + k.SetCrosschainFlags(ctx, types.CrosschainFlags{ + IsInboundEnabled: true, + }) + k.SetChainParamsList(ctx, types.ChainParamsList{ + ChainParams: []*types.ChainParams{ + { + ChainId: getValidEthChainIDWithIndex(t, 0), + IsSupported: true, + }, + { + ChainId: getValidEthChainIDWithIndex(t, 1), + IsSupported: true, + }, + }, + }) + k.SetObserverSet(ctx, types.ObserverSet{ + ObserverList: []string{observer}, + }) + stakingMock.MockGetValidator(sample.Validator(t, sample.Rand())) + slashingMock.MockIsTombstoned(false) + + // set a ballot + threshold, err := sdk.NewDecFromStr("0.1") + require.NoError(t, err) + ballot := types.Ballot{ + Index: "index", + BallotIdentifier: "index", + VoterList: []string{ + observer, + sample.AccAddress(), + sample.AccAddress(), + }, + Votes: types.CreateVotes(3), + ObservationType: types.ObservationType_InBoundTx, + BallotThreshold: threshold, + BallotStatus: types.BallotStatus_BallotInProgress, + } + k.SetBallot(ctx, &ballot) + + isFinalized, isNew, err := k.VoteOnInboundBallot( + ctx, + getValidEthChainIDWithIndex(t, 0), + getValidEthChainIDWithIndex(t, 1), + common.CoinType_ERC20, + observer, + "index", + "inTxHash", + ) + require.NoError(t, err) + + // ballot should not be finalized as the threshold is not reached + require.True(t, isFinalized) + require.False(t, isNew) + }) } diff --git a/x/observer/keeper/vote_outbound_test.go b/x/observer/keeper/vote_outbound_test.go index edb7db3fec..a916f2f3e1 100644 --- a/x/observer/keeper/vote_outbound_test.go +++ b/x/observer/keeper/vote_outbound_test.go @@ -190,4 +190,60 @@ func TestKeeper_VoteOnOutboundBallot(t *testing.T) { require.True(t, found) require.Equal(t, expectedBallot, ballot) }) + + t.Run("can add vote to an existing ballot and finalize ballot", func(t *testing.T) { + k, ctx, _ := keepertest.ObserverKeeperWithMocks(t, keepertest.ObserverMocksAll) + + observer := sample.AccAddress() + stakingMock := keepertest.GetObserverStakingMock(t, k) + slashingMock := keepertest.GetObserverSlashingMock(t, k) + + k.SetChainParamsList(ctx, types.ChainParamsList{ + ChainParams: []*types.ChainParams{ + { + ChainId: getValidEthChainIDWithIndex(t, 0), + IsSupported: true, + }, + }, + }) + k.SetObserverSet(ctx, types.ObserverSet{ + ObserverList: []string{observer}, + }) + stakingMock.MockGetValidator(sample.Validator(t, sample.Rand())) + slashingMock.MockIsTombstoned(false) + + // set a ballot + threshold, err := sdk.NewDecFromStr("0.1") + require.NoError(t, err) + ballot := types.Ballot{ + Index: "index", + BallotIdentifier: "index", + VoterList: []string{ + observer, + sample.AccAddress(), + sample.AccAddress(), + }, + Votes: types.CreateVotes(3), + ObservationType: types.ObservationType_OutBoundTx, + BallotThreshold: threshold, + BallotStatus: types.BallotStatus_BallotInProgress, + } + k.SetBallot(ctx, &ballot) + + isFinalized, isNew, ballot, _, err := k.VoteOnOutboundBallot( + ctx, + "index", + getValidEthChainIDWithIndex(t, 0), + common.ReceiveStatus_Success, + observer, + ) + require.NoError(t, err) + + // ballot should be finalized since there is only one observer + require.True(t, isFinalized) + require.False(t, isNew) + expectedBallot, found := k.GetBallot(ctx, "index") + require.True(t, found) + require.Equal(t, expectedBallot, ballot) + }) } From 580e897f52e5e630746686c06567784f9c00064a Mon Sep 17 00:00:00 2001 From: lumtis Date: Wed, 28 Feb 2024 09:43:51 +0100 Subject: [PATCH 24/24] add not finzalized test --- x/observer/keeper/vote_inbound_test.go | 53 +++++++++++++++++++++++++ x/observer/keeper/vote_outbound_test.go | 46 +++++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/x/observer/keeper/vote_inbound_test.go b/x/observer/keeper/vote_inbound_test.go index aa10c85af1..e1391c051f 100644 --- a/x/observer/keeper/vote_inbound_test.go +++ b/x/observer/keeper/vote_inbound_test.go @@ -257,6 +257,59 @@ func TestKeeper_VoteOnInboundBallot(t *testing.T) { require.True(t, isNew) }) + t.Run("can add vote and create ballot without finalizing ballot", func(t *testing.T) { + k, ctx, _ := keepertest.ObserverKeeperWithMocks(t, keepertest.ObserverMocksAll) + + observer := sample.AccAddress() + stakingMock := keepertest.GetObserverStakingMock(t, k) + slashingMock := keepertest.GetObserverSlashingMock(t, k) + + // threshold high enough to not finalize ballot + threshold, err := sdk.NewDecFromStr("0.7") + require.NoError(t, err) + + k.SetCrosschainFlags(ctx, types.CrosschainFlags{ + IsInboundEnabled: true, + }) + k.SetChainParamsList(ctx, types.ChainParamsList{ + ChainParams: []*types.ChainParams{ + { + ChainId: getValidEthChainIDWithIndex(t, 0), + IsSupported: true, + BallotThreshold: threshold, + }, + { + ChainId: getValidEthChainIDWithIndex(t, 1), + IsSupported: true, + BallotThreshold: threshold, + }, + }, + }) + k.SetObserverSet(ctx, types.ObserverSet{ + ObserverList: []string{ + observer, + sample.AccAddress(), + }, + }) + stakingMock.MockGetValidator(sample.Validator(t, sample.Rand())) + slashingMock.MockIsTombstoned(false) + + isFinalized, isNew, err := k.VoteOnInboundBallot( + ctx, + getValidEthChainIDWithIndex(t, 0), + getValidEthChainIDWithIndex(t, 1), + common.CoinType_ERC20, + observer, + "index", + "inTxHash", + ) + require.NoError(t, err) + + // ballot should be finalized since there is only one observer + require.False(t, isFinalized) + require.True(t, isNew) + }) + t.Run("can add vote to an existing ballot", func(t *testing.T) { k, ctx, _ := keepertest.ObserverKeeperWithMocks(t, keepertest.ObserverMocksAll) diff --git a/x/observer/keeper/vote_outbound_test.go b/x/observer/keeper/vote_outbound_test.go index a916f2f3e1..0e087bac1f 100644 --- a/x/observer/keeper/vote_outbound_test.go +++ b/x/observer/keeper/vote_outbound_test.go @@ -133,6 +133,52 @@ func TestKeeper_VoteOnOutboundBallot(t *testing.T) { require.Equal(t, expectedBallot, ballot) }) + t.Run("can add vote and create ballot without finalizing ballot", func(t *testing.T) { + k, ctx, _ := keepertest.ObserverKeeperWithMocks(t, keepertest.ObserverMocksAll) + + observer := sample.AccAddress() + stakingMock := keepertest.GetObserverStakingMock(t, k) + slashingMock := keepertest.GetObserverSlashingMock(t, k) + + // threshold high enough to not finalize the ballot + threshold, err := sdk.NewDecFromStr("0.7") + require.NoError(t, err) + + k.SetChainParamsList(ctx, types.ChainParamsList{ + ChainParams: []*types.ChainParams{ + { + ChainId: getValidEthChainIDWithIndex(t, 0), + IsSupported: true, + BallotThreshold: threshold, + }, + }, + }) + k.SetObserverSet(ctx, types.ObserverSet{ + ObserverList: []string{ + observer, + sample.AccAddress(), + }, + }) + stakingMock.MockGetValidator(sample.Validator(t, sample.Rand())) + slashingMock.MockIsTombstoned(false) + + isFinalized, isNew, ballot, _, err := k.VoteOnOutboundBallot( + ctx, + "index", + getValidEthChainIDWithIndex(t, 0), + common.ReceiveStatus_Success, + observer, + ) + require.NoError(t, err) + + // ballot should be finalized since there is only one observer + require.False(t, isFinalized) + require.True(t, isNew) + expectedBallot, found := k.GetBallot(ctx, "index") + require.True(t, found) + require.Equal(t, expectedBallot, ballot) + }) + t.Run("can add vote to an existing ballot", func(t *testing.T) { k, ctx, _ := keepertest.ObserverKeeperWithMocks(t, keepertest.ObserverMocksAll)