code.vegaprotocol.io/vega@v0.79.0/core/processor/abci.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package processor
    17  
    18  import (
    19  	"bytes"
    20  	"context"
    21  	"encoding/hex"
    22  	"errors"
    23  	"fmt"
    24  	"io/ioutil"
    25  	"os"
    26  	"path/filepath"
    27  	"reflect"
    28  	"sort"
    29  	"strconv"
    30  	"strings"
    31  	"sync/atomic"
    32  	"time"
    33  
    34  	"code.vegaprotocol.io/vega/commands"
    35  	"code.vegaprotocol.io/vega/core/api"
    36  	"code.vegaprotocol.io/vega/core/blockchain"
    37  	"code.vegaprotocol.io/vega/core/blockchain/abci"
    38  	"code.vegaprotocol.io/vega/core/events"
    39  	"code.vegaprotocol.io/vega/core/genesis"
    40  	"code.vegaprotocol.io/vega/core/idgeneration"
    41  	"code.vegaprotocol.io/vega/core/netparams"
    42  	"code.vegaprotocol.io/vega/core/pow"
    43  	"code.vegaprotocol.io/vega/core/snapshot"
    44  	"code.vegaprotocol.io/vega/core/teams"
    45  	"code.vegaprotocol.io/vega/core/txn"
    46  	"code.vegaprotocol.io/vega/core/types"
    47  	"code.vegaprotocol.io/vega/core/types/statevar"
    48  	"code.vegaprotocol.io/vega/core/vegatime"
    49  	vgcontext "code.vegaprotocol.io/vega/libs/context"
    50  	vgcrypto "code.vegaprotocol.io/vega/libs/crypto"
    51  	signatures "code.vegaprotocol.io/vega/libs/crypto/signature"
    52  	verrors "code.vegaprotocol.io/vega/libs/errors"
    53  	vgfs "code.vegaprotocol.io/vega/libs/fs"
    54  	"code.vegaprotocol.io/vega/libs/num"
    55  	"code.vegaprotocol.io/vega/libs/ptr"
    56  	"code.vegaprotocol.io/vega/logging"
    57  	"code.vegaprotocol.io/vega/paths"
    58  	proto "code.vegaprotocol.io/vega/protos/vega"
    59  	protoapi "code.vegaprotocol.io/vega/protos/vega/api/v1"
    60  	commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1"
    61  	eventspb "code.vegaprotocol.io/vega/protos/vega/events/v1"
    62  
    63  	tmtypes "github.com/cometbft/cometbft/abci/types"
    64  	tmtypes1 "github.com/cometbft/cometbft/proto/tendermint/types"
    65  	types1 "github.com/cometbft/cometbft/proto/tendermint/types"
    66  	tmtypesint "github.com/cometbft/cometbft/types"
    67  	"go.uber.org/zap"
    68  )
    69  
    70  const AppVersion = 1
    71  
    72  type TxWrapper struct {
    73  	tx        abci.Tx
    74  	timeIndex int // this is an indicator of insertion order
    75  	raw       []byte
    76  	priority  uint64
    77  	gasWanted uint64
    78  }
    79  
    80  var (
    81  	ErrUnexpectedTxPubKey          = errors.New("no one listens to the public keys that signed this oracle data")
    82  	ErrTradingDisabled             = errors.New("trading disabled")
    83  	ErrMarketProposalDisabled      = errors.New("market proposal disabled")
    84  	ErrAssetProposalDisabled       = errors.New("asset proposal disabled")
    85  	ErrEthOraclesDisabled          = errors.New("ethereum oracles disabled")
    86  	ErrOracleNoSubscribers         = errors.New("there are no subscribes to the oracle data")
    87  	ErrSpotMarketProposalDisabled  = errors.New("spot market proposal disabled")
    88  	ErrPerpsMarketProposalDisabled = errors.New("perps market proposal disabled")
    89  	ErrAMMPoolDisabled             = errors.New("amm pool disabled")
    90  	ErrOracleDataNormalization     = func(err error) error {
    91  		return fmt.Errorf("error normalizing incoming oracle data: %w", err)
    92  	}
    93  )
    94  
    95  // Codec interface is here for mocking/testing.
    96  type Codec interface {
    97  	abci.Codec
    98  }
    99  
   100  type Checkpoint interface {
   101  	BalanceCheckpoint(ctx context.Context) (*types.CheckpointState, error)
   102  	Checkpoint(ctx context.Context, now time.Time) (*types.CheckpointState, error)
   103  }
   104  
   105  type SpamEngine interface {
   106  	BeginBlock(txs []abci.Tx)
   107  	EndPrepareProposal()
   108  	PreBlockAccept(tx abci.Tx) error
   109  	ProcessProposal(txs []abci.Tx) bool
   110  	CheckBlockTx(tx abci.Tx) error
   111  }
   112  
   113  type PoWEngine interface {
   114  	api.ProofOfWorkParams
   115  	BeginBlock(blockHeight uint64, blockHash string, txs []abci.Tx)
   116  	CheckBlockTx(tx abci.Tx) (pow.ValidationResult, *uint)
   117  	ProcessProposal(txs []abci.Tx) bool
   118  	EndPrepareProposal([]pow.ValidationEntry)
   119  	CheckTx(tx abci.Tx) error
   120  	GetSpamStatistics(partyID string) *protoapi.PoWStatistic
   121  	OnCommit()
   122  }
   123  
   124  //nolint:interfacebloat
   125  type SnapshotEngine interface {
   126  	Info() ([]byte, int64, string)
   127  	Snapshot(context.Context) ([]byte, snapshot.DoneCh, error)
   128  	SnapshotNow(context.Context) ([]byte, error)
   129  	AddProviders(...types.StateProvider)
   130  	HasSnapshots() (bool, error)
   131  
   132  	// Calls related to state-sync
   133  
   134  	ListLatestSnapshots() ([]*tmtypes.Snapshot, error)
   135  	ReceiveSnapshot(*types.Snapshot) tmtypes.ResponseOfferSnapshot
   136  	ReceiveSnapshotChunk(context.Context, *types.RawChunk, string) tmtypes.ResponseApplySnapshotChunk
   137  	RetrieveSnapshotChunk(uint64, uint32, uint32) (*types.RawChunk, error)
   138  	HasRestoredStateAlready() bool
   139  
   140  	// debug snapshot issues/hash mismatch problems
   141  	SnapshotDump(ctx context.Context, path string) ([]byte, error)
   142  }
   143  
   144  type StateVarEngine interface {
   145  	ProposedValueReceived(ctx context.Context, ID, nodeID, eventID string, bundle *statevar.KeyValueBundle) error
   146  	OnBlockEnd(ctx context.Context)
   147  }
   148  
   149  type TeamsEngine interface {
   150  	TeamExists(team types.TeamID) bool
   151  	CreateTeam(context.Context, types.PartyID, types.TeamID, *commandspb.CreateReferralSet_Team) error
   152  	UpdateTeam(context.Context, types.PartyID, types.TeamID, *commandspb.UpdateReferralSet_Team) error
   153  	JoinTeam(context.Context, types.PartyID, *commandspb.JoinTeam) error
   154  }
   155  
   156  type PartiesEngine interface {
   157  	UpdateProfile(context.Context, types.PartyID, *commandspb.UpdatePartyProfile) error
   158  	CheckSufficientBalanceToUpdateProfile(party types.PartyID, balance *num.Uint) error
   159  }
   160  
   161  type ReferralProgram interface {
   162  	UpdateProgram(program *types.ReferralProgram)
   163  	PartyOwnsReferralSet(types.PartyID, types.ReferralSetID) error
   164  	CreateReferralSet(context.Context, types.PartyID, types.ReferralSetID) error
   165  	ApplyReferralCode(context.Context, types.PartyID, types.ReferralSetID) error
   166  	CheckSufficientBalanceForApplyReferralCode(types.PartyID, *num.Uint) error
   167  	CheckSufficientBalanceForCreateOrUpdateReferralSet(types.PartyID, *num.Uint) error
   168  }
   169  
   170  type VolumeDiscountProgram interface {
   171  	UpdateProgram(program *types.VolumeDiscountProgram)
   172  }
   173  
   174  type VolumeRebateProgram interface {
   175  	UpdateProgram(program *types.VolumeRebateProgram)
   176  }
   177  
   178  type BlockchainClient interface {
   179  	Validators(height *int64) ([]*tmtypesint.Validator, error)
   180  	MaxMempoolSize() int64
   181  }
   182  
   183  type ProtocolUpgradeService interface {
   184  	BeginBlock(ctx context.Context, blockHeight uint64)
   185  	UpgradeProposal(ctx context.Context, pk string, upgradeBlockHeight uint64, vegaReleaseTag string) error
   186  	TimeForUpgrade() bool
   187  	GetUpgradeStatus() types.UpgradeStatus
   188  	SetReadyForUpgrade()
   189  	CoreReadyForUpgrade() bool
   190  	SetCoreReadyForUpgrade()
   191  	Cleanup(ctx context.Context)
   192  	IsValidProposal(ctx context.Context, pk string, upgradeBlockHeight uint64, vegaReleaseTag string) error
   193  }
   194  
   195  type BalanceChecker interface {
   196  	GetPartyBalance(party string) *num.Uint
   197  	BeginBlock(context.Context)
   198  }
   199  
   200  type EthCallEngine interface {
   201  	Start()
   202  }
   203  
   204  type TxCache interface {
   205  	SetRawTxs(rtx [][]byte, height uint64)
   206  	GetRawTxs(height uint64) [][]byte
   207  	NewDelayedTransaction(ctx context.Context, delayed [][]byte, height uint64) []byte
   208  	IsDelayRequired(marketID string) bool
   209  	IsDelayRequiredAnyMarket() bool
   210  	IsTxInCache(tx []byte) bool
   211  }
   212  
   213  type App struct {
   214  	abci              *abci.App
   215  	currentTimestamp  time.Time
   216  	previousTimestamp time.Time
   217  	txTotals          []uint64
   218  	txSizes           []int
   219  	cBlock            string
   220  	chainCtx          context.Context // use this to have access to chain ID
   221  	blockCtx          context.Context // use this to have access to block hash + height in commit call
   222  	lastBlockAppHash  []byte
   223  	version           string
   224  	blockchainClient  BlockchainClient
   225  
   226  	vegaPaths      paths.Paths
   227  	cfg            Config
   228  	log            *logging.Logger
   229  	cancelFn       func()
   230  	stopBlockchain func() error
   231  
   232  	// service injection
   233  	assets                         Assets
   234  	banking                        Banking
   235  	broker                         Broker
   236  	witness                        Witness
   237  	evtForwarder                   EvtForwarder
   238  	evtHeartbeat                   EvtForwarderHeartbeat
   239  	primaryChainID                 uint64
   240  	secondaryChainID               uint64
   241  	exec                           ExecutionEngine
   242  	ghandler                       *genesis.Handler
   243  	gov                            GovernanceEngine
   244  	notary                         Notary
   245  	stats                          Stats
   246  	time                           TimeService
   247  	top                            ValidatorTopology
   248  	netp                           NetworkParameters
   249  	oracles                        *Oracle
   250  	delegation                     DelegationEngine
   251  	limits                         Limits
   252  	stake                          StakeVerifier
   253  	stakingAccounts                StakingAccounts
   254  	checkpoint                     Checkpoint
   255  	spam                           SpamEngine
   256  	pow                            PoWEngine
   257  	epoch                          EpochService
   258  	snapshotEngine                 SnapshotEngine
   259  	stateVar                       StateVarEngine
   260  	teamsEngine                    TeamsEngine
   261  	partiesEngine                  PartiesEngine
   262  	referralProgram                ReferralProgram
   263  	volumeDiscountProgram          VolumeDiscountProgram
   264  	volumeRebateProgram            VolumeRebateProgram
   265  	protocolUpgradeService         ProtocolUpgradeService
   266  	primaryErc20MultiSigTopology   ERC20MultiSigTopology
   267  	secondaryErc20MultiSigTopology ERC20MultiSigTopology
   268  	gastimator                     *Gastimator
   269  	ethCallEngine                  EthCallEngine
   270  	balanceChecker                 BalanceChecker
   271  
   272  	nilPow  bool
   273  	nilSpam bool
   274  
   275  	maxBatchSize atomic.Uint64
   276  	txCache      TxCache
   277  }
   278  
   279  func NewApp(log *logging.Logger,
   280  	vegaPaths paths.Paths,
   281  	config Config,
   282  	cancelFn func(),
   283  	stopBlockchain func() error,
   284  	assets Assets,
   285  	banking Banking,
   286  	broker Broker,
   287  	witness Witness,
   288  	evtForwarder EvtForwarder,
   289  	evtHeartbeat EvtForwarderHeartbeat,
   290  	exec ExecutionEngine,
   291  	ghandler *genesis.Handler,
   292  	gov GovernanceEngine,
   293  	notary Notary,
   294  	stats Stats,
   295  	time TimeService,
   296  	epoch EpochService,
   297  	top ValidatorTopology,
   298  	netp NetworkParameters,
   299  	oracles *Oracle,
   300  	delegation DelegationEngine,
   301  	limits Limits,
   302  	stake StakeVerifier,
   303  	checkpoint Checkpoint,
   304  	spam SpamEngine,
   305  	pow PoWEngine,
   306  	stakingAccounts StakingAccounts,
   307  	snapshot SnapshotEngine,
   308  	stateVarEngine StateVarEngine,
   309  	teamsEngine TeamsEngine,
   310  	referralProgram ReferralProgram,
   311  	volumeDiscountProgram VolumeDiscountProgram,
   312  	volumeRebateProgram VolumeRebateProgram,
   313  	blockchainClient BlockchainClient,
   314  	primaryMultisig ERC20MultiSigTopology,
   315  	secondaryMultisig ERC20MultiSigTopology,
   316  	version string,
   317  	protocolUpgradeService ProtocolUpgradeService,
   318  	codec abci.Codec,
   319  	gastimator *Gastimator,
   320  	ethCallEngine EthCallEngine,
   321  	balanceChecker BalanceChecker,
   322  	partiesEngine PartiesEngine,
   323  	txCache TxCache,
   324  ) *App {
   325  	log = log.Named(namedLogger)
   326  	log.SetLevel(config.Level.Get())
   327  
   328  	app := &App{
   329  		abci: abci.New(codec),
   330  
   331  		log:                            log,
   332  		vegaPaths:                      vegaPaths,
   333  		cfg:                            config,
   334  		cancelFn:                       cancelFn,
   335  		stopBlockchain:                 stopBlockchain,
   336  		assets:                         assets,
   337  		banking:                        banking,
   338  		broker:                         broker,
   339  		witness:                        witness,
   340  		evtForwarder:                   evtForwarder,
   341  		evtHeartbeat:                   evtHeartbeat,
   342  		exec:                           exec,
   343  		ghandler:                       ghandler,
   344  		gov:                            gov,
   345  		notary:                         notary,
   346  		stats:                          stats,
   347  		time:                           time,
   348  		top:                            top,
   349  		netp:                           netp,
   350  		oracles:                        oracles,
   351  		delegation:                     delegation,
   352  		limits:                         limits,
   353  		stake:                          stake,
   354  		checkpoint:                     checkpoint,
   355  		spam:                           spam,
   356  		pow:                            pow,
   357  		stakingAccounts:                stakingAccounts,
   358  		epoch:                          epoch,
   359  		snapshotEngine:                 snapshot,
   360  		stateVar:                       stateVarEngine,
   361  		teamsEngine:                    teamsEngine,
   362  		referralProgram:                referralProgram,
   363  		volumeDiscountProgram:          volumeDiscountProgram,
   364  		volumeRebateProgram:            volumeRebateProgram,
   365  		version:                        version,
   366  		blockchainClient:               blockchainClient,
   367  		primaryErc20MultiSigTopology:   primaryMultisig,
   368  		secondaryErc20MultiSigTopology: secondaryMultisig,
   369  		protocolUpgradeService:         protocolUpgradeService,
   370  		gastimator:                     gastimator,
   371  		ethCallEngine:                  ethCallEngine,
   372  		balanceChecker:                 balanceChecker,
   373  		partiesEngine:                  partiesEngine,
   374  		txCache:                        txCache,
   375  	}
   376  
   377  	// setup handlers
   378  	app.abci.OnPrepareProposal = app.prepareProposal
   379  	app.abci.OnProcessProposal = app.processProposal
   380  	app.abci.OnInitChain = app.OnInitChain
   381  	app.abci.OnBeginBlock = app.OnBeginBlock
   382  	app.abci.OnEndBlock = app.OnEndBlock
   383  	app.abci.OnCommit = app.OnCommit
   384  	app.abci.OnCheckTx = app.OnCheckTx
   385  	app.abci.OnCheckTxSpam = app.OnCheckTxSpam
   386  	app.abci.OnInfo = app.Info
   387  	app.abci.OnFinalize = app.Finalize
   388  	// snapshot specific handlers.
   389  	app.abci.OnListSnapshots = app.ListSnapshots
   390  	app.abci.OnOfferSnapshot = app.OfferSnapshot
   391  	app.abci.OnApplySnapshotChunk = app.ApplySnapshotChunk
   392  	app.abci.OnLoadSnapshotChunk = app.LoadSnapshotChunk
   393  
   394  	app.abci.
   395  		HandleCheckTx(txn.NodeSignatureCommand, app.RequireValidatorPubKey).
   396  		HandleCheckTx(txn.NodeVoteCommand, app.RequireValidatorPubKey).
   397  		HandleCheckTx(txn.ChainEventCommand, app.RequireValidatorPubKey).
   398  		HandleCheckTx(txn.SubmitOracleDataCommand, app.CheckSubmitOracleData).
   399  		HandleCheckTx(txn.RotateKeySubmissionCommand, app.RequireValidatorMasterPubKey).
   400  		HandleCheckTx(txn.StateVariableProposalCommand, app.RequireValidatorPubKey).
   401  		HandleCheckTx(txn.ValidatorHeartbeatCommand, app.RequireValidatorPubKey).
   402  		HandleCheckTx(txn.RotateEthereumKeySubmissionCommand, app.RequireValidatorPubKey).
   403  		HandleCheckTx(txn.ProtocolUpgradeCommand, app.CheckProtocolUpgradeProposal).
   404  		HandleCheckTx(txn.BatchMarketInstructions, app.CheckBatchMarketInstructions).
   405  		HandleCheckTx(txn.ProposeCommand, app.CheckPropose).
   406  		HandleCheckTx(txn.BatchProposeCommand, addDeterministicID(app.CheckBatchPropose)).
   407  		HandleCheckTx(txn.TransferFundsCommand, app.CheckTransferCommand).
   408  		HandleCheckTx(txn.ApplyReferralCodeCommand, app.CheckApplyReferralCode).
   409  		HandleCheckTx(txn.CreateReferralSetCommand, app.CheckCreateOrUpdateReferralSet).
   410  		HandleCheckTx(txn.UpdateReferralSetCommand, app.CheckCreateOrUpdateReferralSet).
   411  		HandleCheckTx(txn.SubmitOrderCommand, app.CheckOrderSubmissionForSpam).
   412  		HandleCheckTx(txn.LiquidityProvisionCommand, app.CheckLPSubmissionForSpam).
   413  		HandleCheckTx(txn.AmendLiquidityProvisionCommand, app.CheckLPAmendForSpam).
   414  		HandleCheckTx(txn.SubmitAMMCommand, app.CheckSubmitAmmForSpam).
   415  		HandleCheckTx(txn.AmendAMMCommand, app.CheckAmendAmmForSpam).
   416  		HandleCheckTx(txn.AmendOrderCommand, app.CheckAmendOrderForSpam).
   417  		HandleCheckTx(txn.CancelOrderCommand, app.CheckCancelOrderForSpam).
   418  		HandleCheckTx(txn.CancelAMMCommand, app.CheckCancelAmmForSpam).
   419  		HandleCheckTx(txn.CancelLiquidityProvisionCommand, app.CheckCancelLPForSpam)
   420  
   421  	// node commands
   422  	app.abci.HandleDeliverTx(txn.NodeSignatureCommand,
   423  		app.RequireValidatorPubKeyW(app.DeliverNodeSignature)).
   424  		HandleDeliverTx(txn.NodeVoteCommand,
   425  			app.RequireValidatorPubKeyW(app.DeliverNodeVote)).
   426  		HandleDeliverTx(txn.ChainEventCommand,
   427  			app.RequireValidatorPubKeyW(addDeterministicID(app.DeliverChainEvent))).
   428  		HandleDeliverTx(txn.StateVariableProposalCommand,
   429  			app.RequireValidatorPubKeyW(app.DeliverStateVarProposal)).
   430  		HandleDeliverTx(txn.ValidatorHeartbeatCommand,
   431  			app.DeliverValidatorHeartbeat).
   432  		// validators commands
   433  		HandleDeliverTx(txn.IssueSignatures,
   434  			app.SendTransactionResult(app.DeliverIssueSignatures)).
   435  		HandleDeliverTx(txn.ProtocolUpgradeCommand,
   436  			app.SendTransactionResult(app.DeliverProtocolUpgradeCommand)).
   437  		HandleDeliverTx(txn.RotateKeySubmissionCommand,
   438  			app.SendTransactionResult(
   439  				app.RequireValidatorMasterPubKeyW(app.DeliverKeyRotateSubmission),
   440  			),
   441  		).
   442  		HandleDeliverTx(txn.RotateEthereumKeySubmissionCommand,
   443  			app.SendTransactionResult(
   444  				app.RequireValidatorPubKeyW(app.DeliverEthereumKeyRotateSubmission),
   445  			),
   446  		).
   447  		// user commands
   448  		HandleDeliverTx(txn.AnnounceNodeCommand,
   449  			app.SendTransactionResult(app.DeliverAnnounceNode),
   450  		).
   451  		HandleDeliverTx(txn.CancelTransferFundsCommand,
   452  			app.SendTransactionResult(app.DeliverCancelTransferFunds),
   453  		).
   454  		HandleDeliverTx(txn.TransferFundsCommand,
   455  			app.SendTransactionResult(
   456  				addDeterministicID(app.DeliverTransferFunds),
   457  			),
   458  		).
   459  		HandleDeliverTx(txn.SubmitOrderCommand,
   460  			app.SendTransactionResult(
   461  				addDeterministicID(app.DeliverSubmitOrder),
   462  			),
   463  		).
   464  		HandleDeliverTx(txn.StopOrdersSubmissionCommand,
   465  			app.SendTransactionResult(
   466  				addDeterministicID(app.DeliverStopOrdersSubmission),
   467  			),
   468  		).
   469  		HandleDeliverTx(txn.StopOrdersCancellationCommand,
   470  			app.SendTransactionResult(
   471  				addDeterministicID(app.DeliverStopOrdersCancellation),
   472  			),
   473  		).
   474  		HandleDeliverTx(txn.CancelOrderCommand,
   475  			app.SendTransactionResult(
   476  				addDeterministicID(app.DeliverCancelOrder),
   477  			),
   478  		).
   479  		HandleDeliverTx(txn.AmendOrderCommand,
   480  			app.SendTransactionResult(
   481  				addDeterministicID(app.DeliverAmendOrder),
   482  			),
   483  		).
   484  		HandleDeliverTx(txn.SubmitAMMCommand,
   485  			app.SendTransactionResult(
   486  				addDeterministicID(app.DeliverSubmitAMM),
   487  			),
   488  		).
   489  		HandleDeliverTx(txn.AmendAMMCommand,
   490  			app.SendTransactionResult(
   491  				addDeterministicID(app.DeliverAmendAMM),
   492  			),
   493  		).
   494  		HandleDeliverTx(txn.CancelAMMCommand,
   495  			app.SendTransactionResult(
   496  				addDeterministicID(app.DeliverCancelAMM),
   497  			),
   498  		).
   499  		HandleDeliverTx(txn.WithdrawCommand,
   500  			app.SendTransactionResult(
   501  				addDeterministicID(app.DeliverWithdraw))).
   502  		HandleDeliverTx(txn.ProposeCommand,
   503  			app.SendTransactionResult(
   504  				app.CheckProposeW(
   505  					addDeterministicID(app.DeliverPropose),
   506  				),
   507  			),
   508  		).
   509  		HandleDeliverTx(txn.BatchProposeCommand,
   510  			app.SendTransactionResult(
   511  				app.CheckBatchProposeW(
   512  					addDeterministicID(app.DeliverBatchPropose),
   513  				),
   514  			),
   515  		).
   516  		HandleDeliverTx(txn.VoteCommand,
   517  			app.SendTransactionResult(app.DeliverVote),
   518  		).
   519  		HandleDeliverTx(txn.LiquidityProvisionCommand,
   520  			app.SendTransactionResult(
   521  				addDeterministicID(app.DeliverLiquidityProvision),
   522  			),
   523  		).
   524  		HandleDeliverTx(txn.CancelLiquidityProvisionCommand,
   525  			app.SendTransactionResult(app.DeliverCancelLiquidityProvision),
   526  		).
   527  		HandleDeliverTx(txn.AmendLiquidityProvisionCommand,
   528  			app.SendTransactionResult(
   529  				addDeterministicID(app.DeliverAmendLiquidityProvision),
   530  			),
   531  		).
   532  		HandleDeliverTx(txn.SubmitOracleDataCommand,
   533  			app.SendTransactionResult(app.DeliverSubmitOracleData),
   534  		).
   535  		HandleDeliverTx(txn.DelegateCommand,
   536  			app.SendTransactionResult(app.DeliverDelegate),
   537  		).
   538  		HandleDeliverTx(txn.UndelegateCommand,
   539  			app.SendTransactionResult(app.DeliverUndelegate),
   540  		).
   541  		HandleDeliverTx(txn.BatchMarketInstructions,
   542  			app.SendTransactionResult(
   543  				app.CheckBatchMarketInstructionsW(
   544  					addDeterministicID(app.DeliverBatchMarketInstructions),
   545  				),
   546  			),
   547  		).
   548  		HandleDeliverTx(txn.CreateReferralSetCommand,
   549  			app.SendTransactionResult(addDeterministicID(app.CreateReferralSet)),
   550  		).
   551  		HandleDeliverTx(txn.UpdateReferralSetCommand,
   552  			app.SendTransactionResult(app.UpdateReferralSet),
   553  		).
   554  		HandleDeliverTx(txn.ApplyReferralCodeCommand,
   555  			app.SendTransactionResult(app.ApplyReferralCode),
   556  		).
   557  		HandleDeliverTx(txn.UpdateMarginModeCommand,
   558  			app.SendTransactionResult(app.UpdateMarginMode),
   559  		).
   560  		HandleDeliverTx(txn.JoinTeamCommand,
   561  			app.SendTransactionResult(app.JoinTeam),
   562  		).
   563  		HandleDeliverTx(txn.UpdatePartyProfileCommand,
   564  			app.SendTransactionResult(app.UpdatePartyProfile),
   565  		).
   566  		HandleDeliverTx(txn.DelayedTransactionsWrapper,
   567  			app.SendTransactionResult(app.handleDelayedTransactionWrapper))
   568  
   569  	app.time.NotifyOnTick(app.onTick)
   570  
   571  	app.nilPow = app.pow == nil || reflect.ValueOf(app.pow).IsNil()
   572  	app.nilSpam = app.spam == nil || reflect.ValueOf(app.spam).IsNil()
   573  	app.ensureConfig()
   574  	return app
   575  }
   576  
   577  func (app *App) OnSpamProtectionMaxBatchSizeUpdate(_ context.Context, u *num.Uint) error {
   578  	app.maxBatchSize.Store(u.Uint64())
   579  	return nil
   580  }
   581  
   582  // generateDeterministicID will build the command ID
   583  // the command ID is built using the signature of the proposer of the command
   584  // the signature is then hashed with sha3_256
   585  // the hash is the hex string encoded.
   586  func generateDeterministicID(tx abci.Tx) string {
   587  	return hex.EncodeToString(vgcrypto.Hash(tx.Signature()))
   588  }
   589  
   590  // addDeterministicID decorates give function with deterministic ID.
   591  func addDeterministicID(
   592  	f func(context.Context, abci.Tx, string) error,
   593  ) func(context.Context, abci.Tx) error {
   594  	return func(ctx context.Context, tx abci.Tx) error {
   595  		return f(ctx, tx, generateDeterministicID(tx))
   596  	}
   597  }
   598  
   599  func (app *App) CheckProposeW(
   600  	f func(context.Context, abci.Tx) error,
   601  ) func(context.Context, abci.Tx) error {
   602  	return func(ctx context.Context, tx abci.Tx) error {
   603  		if err := app.CheckPropose(ctx, tx); err != nil {
   604  			return err
   605  		}
   606  		return f(ctx, tx)
   607  	}
   608  }
   609  
   610  func (app *App) CheckBatchProposeW(
   611  	f func(context.Context, abci.Tx) error,
   612  ) func(context.Context, abci.Tx) error {
   613  	return func(ctx context.Context, tx abci.Tx) error {
   614  		if err := addDeterministicID(app.CheckBatchPropose)(ctx, tx); err != nil {
   615  			return err
   616  		}
   617  		return f(ctx, tx)
   618  	}
   619  }
   620  
   621  func (app *App) CheckBatchMarketInstructionsW(
   622  	f func(context.Context, abci.Tx) error,
   623  ) func(context.Context, abci.Tx) error {
   624  	return func(ctx context.Context, tx abci.Tx) error {
   625  		if err := app.CheckBatchMarketInstructions(ctx, tx); err != nil {
   626  			return err
   627  		}
   628  		return f(ctx, tx)
   629  	}
   630  }
   631  
   632  func (app *App) RequireValidatorPubKeyW(
   633  	f func(context.Context, abci.Tx) error,
   634  ) func(context.Context, abci.Tx) error {
   635  	return func(ctx context.Context, tx abci.Tx) error {
   636  		if err := app.RequireValidatorPubKey(ctx, tx); err != nil {
   637  			return err
   638  		}
   639  		return f(ctx, tx)
   640  	}
   641  }
   642  
   643  func (app *App) RequireValidatorMasterPubKeyW(
   644  	f func(context.Context, abci.Tx) error,
   645  ) func(context.Context, abci.Tx) error {
   646  	return func(ctx context.Context, tx abci.Tx) error {
   647  		if err := app.RequireValidatorMasterPubKey(ctx, tx); err != nil {
   648  			return err
   649  		}
   650  		return f(ctx, tx)
   651  	}
   652  }
   653  
   654  func (app *App) SendTransactionResult(
   655  	f func(context.Context, abci.Tx) error,
   656  ) func(context.Context, abci.Tx) error {
   657  	return func(ctx context.Context, tx abci.Tx) error {
   658  		if err := f(ctx, tx); err != nil {
   659  			// Send and error event
   660  			app.broker.Send(events.NewTransactionResultEventFailure(
   661  				ctx, hex.EncodeToString(tx.Hash()), tx.Party(), err, tx.GetCmd(),
   662  			))
   663  
   664  			// FIXME(j): remove this once anyone have stopped using the event
   665  			app.broker.Send(events.NewTxErrEvent(ctx, err, tx.Party(), tx.GetCmd(), tx.Command().String()))
   666  
   667  			return err
   668  		}
   669  
   670  		// Send and error event
   671  		app.broker.Send(events.NewTransactionResultEventSuccess(
   672  			ctx, hex.EncodeToString(tx.Hash()), tx.Party(), tx.GetCmd(),
   673  		))
   674  
   675  		return nil
   676  	}
   677  }
   678  
   679  func (app *App) ensureConfig() {
   680  	if app.cfg.KeepCheckpointsMax < 1 {
   681  		app.cfg.KeepCheckpointsMax = 1
   682  	}
   683  
   684  	v := &proto.EthereumConfig{}
   685  	if err := app.netp.GetJSONStruct(netparams.BlockchainsPrimaryEthereumConfig, v); err != nil {
   686  		return
   687  	}
   688  	primaryChainID, err := strconv.ParseUint(v.ChainId, 10, 64)
   689  	if err != nil {
   690  		return
   691  	}
   692  	app.primaryChainID = primaryChainID
   693  	_ = app.gov.OnChainIDUpdate(primaryChainID)
   694  	_ = app.exec.OnChainIDUpdate(primaryChainID)
   695  
   696  	bridgeConfigs := &proto.EVMBridgeConfigs{}
   697  	if err := app.netp.GetJSONStruct(netparams.BlockchainsEVMBridgeConfigs, bridgeConfigs); err != nil {
   698  		return
   699  	}
   700  
   701  	secondaryChainID, err := strconv.ParseUint(bridgeConfigs.Configs[0].ChainId, 10, 64)
   702  	if err != nil {
   703  		return
   704  	}
   705  	app.secondaryChainID = secondaryChainID
   706  }
   707  
   708  // ReloadConf updates the internal configuration.
   709  func (app *App) ReloadConf(cfg Config) {
   710  	app.log.Info("reloading configuration")
   711  	if app.log.GetLevel() != cfg.Level.Get() {
   712  		app.log.Info("updating log level",
   713  			logging.String("old", app.log.GetLevel().String()),
   714  			logging.String("new", cfg.Level.String()),
   715  		)
   716  		app.log.SetLevel(cfg.Level.Get())
   717  	}
   718  
   719  	app.cfg = cfg
   720  	app.ensureConfig()
   721  }
   722  
   723  func (app *App) Abci() *abci.App {
   724  	return app.abci
   725  }
   726  
   727  func (app *App) cancel() {
   728  	if fn := app.cancelFn; fn != nil {
   729  		fn()
   730  	}
   731  }
   732  
   733  func (app *App) Info(_ context.Context, _ *tmtypes.RequestInfo) (*tmtypes.ResponseInfo, error) {
   734  	if len(app.lastBlockAppHash) != 0 {
   735  		// we must've lost connection to tendermint for a bit, tell it where we got up to
   736  		height, _ := vgcontext.BlockHeightFromContext(app.blockCtx)
   737  		app.log.Info("ABCI service INFO requested after reconnect",
   738  			logging.Uint64("height", height),
   739  			logging.String("hash", hex.EncodeToString(app.lastBlockAppHash)),
   740  		)
   741  		return &tmtypes.ResponseInfo{
   742  			AppVersion:       AppVersion,
   743  			Version:          app.version,
   744  			LastBlockHeight:  int64(height),
   745  			LastBlockAppHash: app.lastBlockAppHash,
   746  		}, nil
   747  	}
   748  
   749  	// returns whether or not we have loaded from a snapshot (and may even do the loading)
   750  	old := app.broker.SetStreaming(false)
   751  	defer app.broker.SetStreaming(old)
   752  
   753  	resp := tmtypes.ResponseInfo{
   754  		AppVersion: AppVersion,
   755  		Version:    app.version,
   756  	}
   757  
   758  	hasSnapshots, err := app.snapshotEngine.HasSnapshots()
   759  	if err != nil {
   760  		app.log.Panic("Failed to verify if the snapshot engine has stored snapshots", logging.Error(err))
   761  	}
   762  
   763  	// If the snapshot engine has snapshots stored, the node can safely advertise
   764  	// its chain info. This comes from the snapshot engine because it is
   765  	// its responsibility to store it.
   766  	if hasSnapshots {
   767  		hash, height, chainID := app.snapshotEngine.Info()
   768  		resp.LastBlockHeight = height
   769  		resp.LastBlockAppHash = hash
   770  		app.abci.SetChainID(chainID)
   771  		app.chainCtx = vgcontext.WithChainID(context.Background(), chainID)
   772  	}
   773  
   774  	app.log.Info("ABCI service INFO requested",
   775  		logging.String("version", resp.Version),
   776  		logging.Uint64("app-version", resp.AppVersion),
   777  		logging.Int64("height", resp.LastBlockHeight),
   778  		logging.String("hash", hex.EncodeToString(resp.LastBlockAppHash)),
   779  	)
   780  	return &resp, nil
   781  }
   782  
   783  func (app *App) ListSnapshots(_ context.Context, _ *tmtypes.RequestListSnapshots) (*tmtypes.ResponseListSnapshots, error) {
   784  	app.log.Debug("ABCI service ListSnapshots requested")
   785  	latestSnapshots, err := app.snapshotEngine.ListLatestSnapshots()
   786  	if err != nil {
   787  		app.log.Error("Could not list latest snapshots", logging.Error(err))
   788  		return &tmtypes.ResponseListSnapshots{}, err
   789  	}
   790  	return &tmtypes.ResponseListSnapshots{
   791  		Snapshots: latestSnapshots,
   792  	}, nil
   793  }
   794  
   795  func (app *App) OfferSnapshot(_ context.Context, req *tmtypes.RequestOfferSnapshot) (*tmtypes.ResponseOfferSnapshot, error) {
   796  	app.log.Debug("ABCI service OfferSnapshot start")
   797  	if app.snapshotEngine.HasRestoredStateAlready() {
   798  		app.log.Warn("The snapshot engine aborted the snapshot offer from state-sync since the state has already been restored")
   799  		return &tmtypes.ResponseOfferSnapshot{
   800  			Result: tmtypes.ResponseOfferSnapshot_ABORT,
   801  		}, nil
   802  	}
   803  
   804  	deserializedSnapshot, err := types.SnapshotFromTM(req.Snapshot)
   805  	if err != nil {
   806  		app.log.Error("Could not deserialize snapshot", logging.Error(err))
   807  		return &tmtypes.ResponseOfferSnapshot{
   808  			Result: tmtypes.ResponseOfferSnapshot_REJECT_SENDER,
   809  		}, err
   810  	}
   811  
   812  	// check that our unpacked snapshot's hash matches that which tendermint thinks it sent
   813  	if !bytes.Equal(deserializedSnapshot.Hash, req.AppHash) {
   814  		app.log.Error("The hashes from the request and the deserialized snapshot mismatch",
   815  			logging.String("deserialized-hash", hex.EncodeToString(deserializedSnapshot.Hash)),
   816  			logging.String("request-hash", hex.EncodeToString(req.AppHash)))
   817  		return &tmtypes.ResponseOfferSnapshot{
   818  			Result: tmtypes.ResponseOfferSnapshot_REJECT,
   819  		}, fmt.Errorf("hash mismatch")
   820  	}
   821  
   822  	res := app.snapshotEngine.ReceiveSnapshot(deserializedSnapshot)
   823  	return &res, nil
   824  }
   825  
   826  func (app *App) ApplySnapshotChunk(ctx context.Context, req *tmtypes.RequestApplySnapshotChunk) (*tmtypes.ResponseApplySnapshotChunk, error) {
   827  	app.log.Debug("ABCI service ApplySnapshotChunk start")
   828  
   829  	if app.snapshotEngine.HasRestoredStateAlready() {
   830  		app.log.Warn("The snapshot engine aborted the snapshot chunk from state-sync since the state has already been restored")
   831  		return &tmtypes.ResponseApplySnapshotChunk{
   832  			Result: tmtypes.ResponseApplySnapshotChunk_ABORT,
   833  		}, nil // ???
   834  	}
   835  	chunk := &types.RawChunk{
   836  		Nr:   req.Index,
   837  		Data: req.Chunk,
   838  	}
   839  
   840  	res := app.snapshotEngine.ReceiveSnapshotChunk(ctx, chunk, req.Sender)
   841  	return &res, nil
   842  }
   843  
   844  func (app *App) LoadSnapshotChunk(_ context.Context, req *tmtypes.RequestLoadSnapshotChunk) (*tmtypes.ResponseLoadSnapshotChunk, error) {
   845  	app.log.Debug("ABCI service LoadSnapshotChunk start")
   846  	raw, err := app.snapshotEngine.RetrieveSnapshotChunk(req.Height, req.Format, req.Chunk)
   847  	if err != nil {
   848  		app.log.Error("failed to load snapshot chunk", logging.Error(err), logging.Uint64("height", req.Height))
   849  		return &tmtypes.ResponseLoadSnapshotChunk{}, err
   850  	}
   851  	return &tmtypes.ResponseLoadSnapshotChunk{
   852  		Chunk: raw.Data,
   853  	}, nil
   854  }
   855  
   856  func (app *App) OnInitChain(req *tmtypes.RequestInitChain) (*tmtypes.ResponseInitChain, error) {
   857  	app.log.Debug("ABCI service InitChain start")
   858  	hash := hex.EncodeToString(vgcrypto.Hash([]byte(req.ChainId)))
   859  	app.abci.SetChainID(req.ChainId)
   860  	app.chainCtx = vgcontext.WithChainID(context.Background(), req.ChainId)
   861  	ctx := vgcontext.WithBlockHeight(app.chainCtx, uint64(req.InitialHeight))
   862  	ctx = vgcontext.WithTraceID(ctx, hash)
   863  	app.blockCtx = ctx
   864  
   865  	app.log.Debug("OnInitChain-NewBeginBlock", logging.Uint64("height", uint64(req.InitialHeight)), logging.Time("blockTime", req.Time), logging.String("blockHash", hash))
   866  
   867  	app.broker.Send(
   868  		events.NewBeginBlock(ctx, eventspb.BeginBlock{
   869  			Height:    uint64(req.InitialHeight),
   870  			Timestamp: req.Time.UnixNano(),
   871  			Hash:      hash,
   872  		}),
   873  	)
   874  
   875  	if err := app.ghandler.OnGenesis(ctx, req.Time, req.AppStateBytes); err != nil {
   876  		app.cancel()
   877  		app.log.Fatal("couldn't initialise vega with the genesis block", logging.Error(err))
   878  	}
   879  
   880  	app.broker.Send(
   881  		events.NewEndBlock(ctx, eventspb.EndBlock{
   882  			Height: uint64(req.InitialHeight),
   883  		}),
   884  	)
   885  
   886  	app.ethCallEngine.Start()
   887  
   888  	return &tmtypes.ResponseInitChain{
   889  		Validators: app.top.GetValidatorPowerUpdates(),
   890  	}, nil
   891  }
   892  
   893  // prepareProposal takes an ordered slice of transactions and decides which of them go into the next block.
   894  // The logic for selection is as follows:
   895  // 1. mempool transactions are sorted by priority then insertion order (aka time)
   896  // 2. we add *valid* transaction to the block so long as gas and maxBytes limits are not violated
   897  // 3. we never add transactions failing pow checks
   898  // 4. we never add transactions failing spam checks
   899  // therefore a block generated with this method will never contain any transactions that would violate spam/pow constraints that would have previously
   900  // caused the party to get blocked.
   901  func (app *App) prepareProposal(height uint64, txs []abci.Tx, rawTxs [][]byte) [][]byte {
   902  	var totalBytes int64
   903  	validationResults := []pow.ValidationEntry{}
   904  
   905  	// internally we use this as max bytes, externally to consensus params we return max ints. This is done so that cometbft always returns to us the full mempool
   906  	// and we can first sort it by priority and then reap by size.
   907  	maxBytes := tmtypesint.DefaultBlockParams().MaxBytes * 4
   908  	app.log.Debug("prepareProposal called with", logging.Int("txs", len(rawTxs)), logging.Int64("max-bytes", maxBytes))
   909  
   910  	// as transactions that are wrapped for sending in the next block are not removed from the mempool
   911  	// to avoid adding them both from the mempool and from the cache we need to check
   912  	// they were not in the cache.
   913  	// we still need to check that the transactions from previous block are passing pow and spam requirements.
   914  	addedFromPreviousHash := map[string]struct{}{}
   915  	delayedTxs := [][]byte{}
   916  	for _, txx := range app.txCache.GetRawTxs(height) {
   917  		tx, err := app.abci.GetTx(txx)
   918  		if err != nil {
   919  			continue
   920  		}
   921  		if !app.nilPow {
   922  			vr, d := app.pow.CheckBlockTx(tx)
   923  			validationResults = append(validationResults, pow.ValidationEntry{Tx: tx, Difficulty: d, ValResult: vr})
   924  			if vr != pow.ValidationResultSuccess && vr != pow.ValidationResultValidatorCommand {
   925  				app.log.Debug("pow failure", logging.Int64("validation-result", int64(vr)))
   926  				continue
   927  			}
   928  		}
   929  		if !app.nilSpam {
   930  			err := app.spam.CheckBlockTx(tx)
   931  			if err != nil {
   932  				app.log.Debug("spam error", logging.Error(err))
   933  				continue
   934  			}
   935  		}
   936  		if err := app.canSubmitTx(tx); err != nil {
   937  			continue
   938  		}
   939  
   940  		addedFromPreviousHash[hex.EncodeToString(tx.Hash())] = struct{}{}
   941  		delayedTxs = append(delayedTxs, txx)
   942  		totalBytes += int64(len(txx))
   943  	}
   944  
   945  	// wrap the transaction with information about gas wanted and priority
   946  	wrappedTxs := make([]*TxWrapper, 0, len(txs))
   947  	for i, v := range txs {
   948  		wtx, error := app.wrapTx(v, rawTxs[i], i)
   949  		if error != nil {
   950  			continue
   951  		}
   952  		if _, ok := addedFromPreviousHash[hex.EncodeToString(wtx.tx.Hash())]; ok {
   953  			app.log.Debug("ignoring mempool transaction corresponding to a delayed transaction from previous block")
   954  			continue
   955  		}
   956  		wrappedTxs = append(wrappedTxs, wtx)
   957  	}
   958  
   959  	// sort by priority descending. If priority is equal use the order in the mempol ascending
   960  	sort.Slice(wrappedTxs, func(i, j int) bool {
   961  		if wrappedTxs[i].priority == wrappedTxs[j].priority {
   962  			return wrappedTxs[i].timeIndex < wrappedTxs[j].timeIndex
   963  		}
   964  		return wrappedTxs[i].priority > wrappedTxs[j].priority
   965  	})
   966  
   967  	// add transactions to the block as long as we can without breaking size and gas limits in order of priority
   968  	maxGas := app.getMaxGas()
   969  	totalGasWanted := uint64(0)
   970  	cancellations := [][]byte{}
   971  	postOnly := [][]byte{}
   972  	anythingElseFromThisBlock := [][]byte{}
   973  	nextBlockRtx := [][]byte{}
   974  
   975  	for _, tx := range wrappedTxs {
   976  		totalBytes += int64(len(tx.raw))
   977  		if totalBytes > maxBytes {
   978  			break
   979  		}
   980  		totalGasWanted += tx.gasWanted
   981  		if totalGasWanted > maxGas {
   982  			break
   983  		}
   984  
   985  		if tx.tx.Command() == txn.DelayedTransactionsWrapper {
   986  			app.log.Debug("delayed transaction wrapper should never be submitted into the mempool")
   987  			continue
   988  		}
   989  
   990  		if !app.nilPow {
   991  			vr, d := app.pow.CheckBlockTx(tx.tx)
   992  			validationResults = append(validationResults, pow.ValidationEntry{Tx: tx.tx, Difficulty: d, ValResult: vr})
   993  			if vr != pow.ValidationResultSuccess && vr != pow.ValidationResultValidatorCommand {
   994  				app.log.Debug("pow failure", logging.Int64("validation-result", int64(vr)))
   995  				continue
   996  			}
   997  		}
   998  
   999  		if !app.nilSpam {
  1000  			err := app.spam.CheckBlockTx(tx.tx)
  1001  			if err != nil {
  1002  				app.log.Debug("spam error", logging.Error(err))
  1003  				continue
  1004  			}
  1005  		}
  1006  
  1007  		if err := app.canSubmitTx(tx.tx); err != nil {
  1008  			continue
  1009  		}
  1010  
  1011  		switch tx.tx.Command() {
  1012  		case txn.CancelOrderCommand:
  1013  			s := &commandspb.OrderCancellation{}
  1014  			if err := tx.tx.Unmarshal(s); err != nil {
  1015  				continue
  1016  			}
  1017  			if len(s.MarketId) > 0 {
  1018  				if app.txCache.IsDelayRequired(s.MarketId) {
  1019  					cancellations = append(cancellations, tx.raw)
  1020  				} else {
  1021  					anythingElseFromThisBlock = append(anythingElseFromThisBlock, tx.raw)
  1022  				}
  1023  			} else if app.txCache.IsDelayRequiredAnyMarket() {
  1024  				cancellations = append(cancellations, tx.raw)
  1025  			} else {
  1026  				anythingElseFromThisBlock = append(anythingElseFromThisBlock, tx.raw)
  1027  			}
  1028  		case txn.CancelAMMCommand:
  1029  			s := &commandspb.CancelAMM{}
  1030  			if err := tx.tx.Unmarshal(s); err != nil {
  1031  				continue
  1032  			}
  1033  			if len(s.MarketId) > 0 {
  1034  				if app.txCache.IsDelayRequired(s.MarketId) {
  1035  					cancellations = append(cancellations, tx.raw)
  1036  				} else {
  1037  					anythingElseFromThisBlock = append(anythingElseFromThisBlock, tx.raw)
  1038  				}
  1039  			} else if app.txCache.IsDelayRequiredAnyMarket() {
  1040  				cancellations = append(cancellations, tx.raw)
  1041  			} else {
  1042  				anythingElseFromThisBlock = append(anythingElseFromThisBlock, tx.raw)
  1043  			}
  1044  		case txn.StopOrdersCancellationCommand:
  1045  			s := &commandspb.StopOrdersCancellation{}
  1046  			if err := tx.tx.Unmarshal(s); err != nil {
  1047  				continue
  1048  			}
  1049  			if s.MarketId != nil {
  1050  				if app.txCache.IsDelayRequired(*s.MarketId) {
  1051  					cancellations = append(cancellations, tx.raw)
  1052  				} else {
  1053  					anythingElseFromThisBlock = append(anythingElseFromThisBlock, tx.raw)
  1054  				}
  1055  			} else if app.txCache.IsDelayRequiredAnyMarket() {
  1056  				cancellations = append(cancellations, tx.raw)
  1057  			} else {
  1058  				anythingElseFromThisBlock = append(anythingElseFromThisBlock, tx.raw)
  1059  			}
  1060  		case txn.SubmitOrderCommand:
  1061  			s := &commandspb.OrderSubmission{}
  1062  			if err := tx.tx.Unmarshal(s); err != nil {
  1063  				continue
  1064  			}
  1065  			if s.PostOnly {
  1066  				postOnly = append(postOnly, tx.raw)
  1067  			} else if app.txCache.IsDelayRequired(s.MarketId) {
  1068  				nextBlockRtx = append(nextBlockRtx, tx.raw)
  1069  			} else {
  1070  				anythingElseFromThisBlock = append(anythingElseFromThisBlock, tx.raw)
  1071  			}
  1072  		case txn.AmendOrderCommand:
  1073  			s := &commandspb.OrderAmendment{}
  1074  			if err := tx.tx.Unmarshal(s); err != nil {
  1075  				continue
  1076  			}
  1077  			if app.txCache.IsDelayRequired(s.MarketId) {
  1078  				nextBlockRtx = append(nextBlockRtx, tx.raw)
  1079  			} else {
  1080  				anythingElseFromThisBlock = append(anythingElseFromThisBlock, tx.raw)
  1081  			}
  1082  		case txn.AmendAMMCommand:
  1083  			s := &commandspb.AmendAMM{}
  1084  			if err := tx.tx.Unmarshal(s); err != nil {
  1085  				continue
  1086  			}
  1087  			if app.txCache.IsDelayRequired(s.MarketId) {
  1088  				nextBlockRtx = append(nextBlockRtx, tx.raw)
  1089  			} else {
  1090  				anythingElseFromThisBlock = append(anythingElseFromThisBlock, tx.raw)
  1091  			}
  1092  		case txn.StopOrdersSubmissionCommand:
  1093  			s := &commandspb.StopOrdersSubmission{}
  1094  			if err := tx.tx.Unmarshal(s); err != nil {
  1095  				continue
  1096  			}
  1097  			if s.RisesAbove != nil && s.FallsBelow == nil {
  1098  				if app.txCache.IsDelayRequired(s.RisesAbove.OrderSubmission.MarketId) {
  1099  					nextBlockRtx = append(nextBlockRtx, tx.raw)
  1100  				} else {
  1101  					anythingElseFromThisBlock = append(anythingElseFromThisBlock, tx.raw)
  1102  				}
  1103  			} else if s.FallsBelow != nil && s.RisesAbove == nil {
  1104  				if app.txCache.IsDelayRequired(s.FallsBelow.OrderSubmission.MarketId) {
  1105  					nextBlockRtx = append(nextBlockRtx, tx.raw)
  1106  				} else {
  1107  					anythingElseFromThisBlock = append(anythingElseFromThisBlock, tx.raw)
  1108  				}
  1109  			} else if s.FallsBelow != nil && s.RisesAbove != nil {
  1110  				if app.txCache.IsDelayRequired(s.FallsBelow.OrderSubmission.MarketId) || app.txCache.IsDelayRequired(s.RisesAbove.OrderSubmission.MarketId) {
  1111  					nextBlockRtx = append(nextBlockRtx, tx.raw)
  1112  				} else {
  1113  					anythingElseFromThisBlock = append(anythingElseFromThisBlock, tx.raw)
  1114  				}
  1115  			}
  1116  		case txn.BatchMarketInstructions:
  1117  			batch := &commandspb.BatchMarketInstructions{}
  1118  			if err := tx.tx.Unmarshal(batch); err != nil {
  1119  				continue
  1120  			}
  1121  			someMarketRequiresDelay := false
  1122  			for _, s := range batch.Submissions {
  1123  				if app.txCache.IsDelayRequired(s.MarketId) {
  1124  					someMarketRequiresDelay = true
  1125  					break
  1126  				}
  1127  			}
  1128  			if !someMarketRequiresDelay {
  1129  				for _, s := range batch.Amendments {
  1130  					if app.txCache.IsDelayRequired(s.MarketId) {
  1131  						someMarketRequiresDelay = true
  1132  						break
  1133  					}
  1134  				}
  1135  			}
  1136  			if !someMarketRequiresDelay {
  1137  				for _, s := range batch.Cancellations {
  1138  					if len(s.MarketId) != 0 && app.txCache.IsDelayRequired(s.MarketId) {
  1139  						someMarketRequiresDelay = true
  1140  						break
  1141  					}
  1142  				}
  1143  			}
  1144  			if !someMarketRequiresDelay {
  1145  				for _, s := range batch.StopOrdersSubmission {
  1146  					if s.FallsBelow != nil && s.FallsBelow.OrderSubmission != nil && app.txCache.IsDelayRequired(s.FallsBelow.OrderSubmission.MarketId) {
  1147  						someMarketRequiresDelay = true
  1148  						break
  1149  					}
  1150  					if !someMarketRequiresDelay {
  1151  						if s.RisesAbove != nil && s.RisesAbove.OrderSubmission != nil && app.txCache.IsDelayRequired(s.RisesAbove.OrderSubmission.MarketId) {
  1152  							someMarketRequiresDelay = true
  1153  							break
  1154  						}
  1155  					}
  1156  				}
  1157  			}
  1158  			if !someMarketRequiresDelay {
  1159  				for _, s := range batch.StopOrdersCancellation {
  1160  					if app.txCache.IsDelayRequired(*s.MarketId) {
  1161  						someMarketRequiresDelay = true
  1162  						break
  1163  					}
  1164  				}
  1165  			}
  1166  			if !someMarketRequiresDelay {
  1167  				anythingElseFromThisBlock = append(anythingElseFromThisBlock, tx.raw)
  1168  				continue
  1169  			}
  1170  			// if there are no amends/submissions
  1171  			if len(batch.Amendments) == 0 && len(batch.Submissions) == 0 && len(batch.StopOrdersSubmission) == 0 {
  1172  				cancellations = append(cancellations, tx.raw)
  1173  			} else if len(batch.Amendments) == 0 && len(batch.StopOrdersSubmission) == 0 {
  1174  				allPostOnly := true
  1175  				for _, sub := range batch.Submissions {
  1176  					if !sub.PostOnly {
  1177  						allPostOnly = false
  1178  						break
  1179  					}
  1180  				}
  1181  				if allPostOnly {
  1182  					postOnly = append(postOnly, tx.raw)
  1183  				} else {
  1184  					nextBlockRtx = append(nextBlockRtx, tx.raw)
  1185  				}
  1186  			} else {
  1187  				nextBlockRtx = append(nextBlockRtx, tx.raw)
  1188  			}
  1189  		default:
  1190  			anythingElseFromThisBlock = append(anythingElseFromThisBlock, tx.raw)
  1191  		}
  1192  	}
  1193  	blockTxs := [][]byte{}
  1194  	blockTxs = append(blockTxs, cancellations...) // cancellations go first
  1195  	blockTxs = append(blockTxs, postOnly...)      // then post only orders
  1196  	if delayedTxs != nil {
  1197  		blockTxs = append(blockTxs, delayedTxs...) // then anything from previous block
  1198  	}
  1199  	blockTxs = append(blockTxs, anythingElseFromThisBlock...) // finally anything else from this block
  1200  	if len(nextBlockRtx) > 0 {
  1201  		wrapperTx := app.txCache.NewDelayedTransaction(app.blockCtx, nextBlockRtx, height)
  1202  		blockTxs = append(blockTxs, wrapperTx)
  1203  	}
  1204  	if !app.nilPow {
  1205  		app.pow.EndPrepareProposal(validationResults)
  1206  	}
  1207  	if !app.nilSpam {
  1208  		app.spam.EndPrepareProposal()
  1209  	}
  1210  	return blockTxs
  1211  }
  1212  
  1213  // processProposal takes a block proposal and verifies that it has no malformed or offending transactions which should never be if the validator is using the prepareProposal
  1214  // to generate a block.
  1215  // The verifications include:
  1216  // 1. no violations of pow and spam
  1217  // 2. max gas limit is not exceeded
  1218  // 3. (soft) max bytes is not exceeded.
  1219  func (app *App) processProposal(height uint64, txs []abci.Tx) bool {
  1220  	totalGasWanted := 0
  1221  	maxGas := app.gastimator.GetMaxGas()
  1222  	maxBytes := tmtypesint.DefaultBlockParams().MaxBytes * 4
  1223  	size := int64(0)
  1224  	delayedTxCount := 0
  1225  
  1226  	expectedDelayedAtHeight := app.txCache.GetRawTxs(height)
  1227  	expectedDelayedTxs := make(map[string]struct{}, len(expectedDelayedAtHeight))
  1228  	for _, tx := range expectedDelayedAtHeight {
  1229  		txx, err := app.abci.GetTx(tx)
  1230  		if err == nil {
  1231  			expectedDelayedTxs[hex.EncodeToString(txx.Hash())] = struct{}{}
  1232  		}
  1233  	}
  1234  	foundDelayedTxs := make(map[string]struct{}, len(expectedDelayedAtHeight))
  1235  
  1236  	for _, tx := range txs {
  1237  		size += int64(tx.GetLength())
  1238  		if size > maxBytes {
  1239  			return false
  1240  		}
  1241  		gw, err := app.getGasWanted(tx)
  1242  		if err != nil {
  1243  			return false
  1244  		}
  1245  		totalGasWanted += int(gw)
  1246  		if totalGasWanted > int(maxGas) {
  1247  			return false
  1248  		}
  1249  		// allow only one delayed transaction wrapper in one block and its transactions must match what we expect.
  1250  		if tx.Command() == txn.DelayedTransactionsWrapper {
  1251  			if delayedTxCount > 0 {
  1252  				app.log.Debug("more than one DelayedTransactionsWrapper")
  1253  				return false
  1254  			}
  1255  			delayedTxCount += 1
  1256  		}
  1257  		if _, ok := expectedDelayedTxs[hex.EncodeToString(tx.Hash())]; ok {
  1258  			foundDelayedTxs[hex.EncodeToString(tx.Hash())] = struct{}{}
  1259  		}
  1260  	}
  1261  
  1262  	if len(foundDelayedTxs) != len(expectedDelayedAtHeight) {
  1263  		return false
  1264  	}
  1265  
  1266  	if !app.nilPow && !app.pow.ProcessProposal(txs) {
  1267  		return false
  1268  	}
  1269  
  1270  	if !app.nilSpam && !app.spam.ProcessProposal(txs) {
  1271  		return false
  1272  	}
  1273  	return true
  1274  }
  1275  
  1276  func (app *App) OnEndBlock(blockHeight uint64) (tmtypes.ValidatorUpdates, types1.ConsensusParams) {
  1277  	app.log.Debug("entering end block", logging.Time("at", time.Now()))
  1278  	defer func() { app.log.Debug("leaving end block", logging.Time("at", time.Now())) }()
  1279  
  1280  	app.log.Debug("ABCI service END block completed",
  1281  		logging.Int64("current-timestamp", app.currentTimestamp.UnixNano()),
  1282  		logging.Int64("previous-timestamp", app.previousTimestamp.UnixNano()),
  1283  		logging.String("current-datetime", vegatime.Format(app.currentTimestamp)),
  1284  		logging.String("previous-datetime", vegatime.Format(app.previousTimestamp)),
  1285  	)
  1286  
  1287  	app.epoch.OnBlockEnd(app.blockCtx)
  1288  	app.stateVar.OnBlockEnd(app.blockCtx)
  1289  	app.banking.OnBlockEnd(app.blockCtx, app.currentTimestamp)
  1290  
  1291  	powerUpdates := app.top.GetValidatorPowerUpdates()
  1292  	if len(powerUpdates) == 0 {
  1293  		powerUpdates = tmtypes.ValidatorUpdates{}
  1294  	}
  1295  
  1296  	// update max gas based on the network parameter
  1297  	consensusParamUpdates := types1.ConsensusParams{
  1298  		Block: &types1.BlockParams{
  1299  			MaxGas:   int64(app.gastimator.OnBlockEnd()),
  1300  			MaxBytes: -1, // we tell comet that we always want to get the full mempool
  1301  		},
  1302  		Version: &tmtypes1.VersionParams{
  1303  			App: AppVersion,
  1304  		},
  1305  	}
  1306  	app.exec.BlockEnd(app.blockCtx)
  1307  
  1308  	return powerUpdates, consensusParamUpdates
  1309  }
  1310  
  1311  // OnBeginBlock updates the internal lastBlockTime value with each new block.
  1312  func (app *App) OnBeginBlock(blockHeight uint64, blockHash string, blockTime time.Time, proposer string, txs []abci.Tx) context.Context {
  1313  	app.log.Debug("entering begin block", logging.Time("at", time.Now()), logging.Uint64("height", blockHeight), logging.Time("time", blockTime), logging.String("blockHash", blockHash))
  1314  	defer func() { app.log.Debug("leaving begin block", logging.Time("at", time.Now())) }()
  1315  
  1316  	app.txCache.SetRawTxs(nil, blockHeight)
  1317  
  1318  	ctx := vgcontext.WithBlockHeight(vgcontext.WithTraceID(app.chainCtx, blockHash), blockHeight)
  1319  	if app.protocolUpgradeService.CoreReadyForUpgrade() {
  1320  		app.startProtocolUpgrade(ctx)
  1321  	}
  1322  
  1323  	app.broker.Send(events.NewBeginBlock(ctx, eventspb.BeginBlock{
  1324  		Height:    blockHeight,
  1325  		Timestamp: blockTime.UnixNano(),
  1326  		Hash:      blockHash,
  1327  	}))
  1328  	app.cBlock = blockHash
  1329  
  1330  	for _, tx := range txs {
  1331  		app.setTxStats(tx.GetLength())
  1332  	}
  1333  
  1334  	// update pow engine on a new block
  1335  	if !app.nilPow {
  1336  		app.pow.BeginBlock(blockHeight, blockHash, txs)
  1337  	}
  1338  
  1339  	if !app.nilSpam {
  1340  		app.spam.BeginBlock(txs)
  1341  	}
  1342  
  1343  	app.stats.SetHash(blockHash)
  1344  	app.stats.SetHeight(blockHeight)
  1345  	app.blockCtx = ctx
  1346  	now := blockTime
  1347  	app.time.SetTimeNow(ctx, now)
  1348  	app.currentTimestamp = app.time.GetTimeNow()
  1349  	app.previousTimestamp = app.time.GetTimeLastBatch()
  1350  	app.log.Debug("ABCI service BEGIN completed",
  1351  		logging.Int64("current-timestamp", app.currentTimestamp.UnixNano()),
  1352  		logging.Int64("previous-timestamp", app.previousTimestamp.UnixNano()),
  1353  		logging.String("current-datetime", vegatime.Format(app.currentTimestamp)),
  1354  		logging.String("previous-datetime", vegatime.Format(app.previousTimestamp)),
  1355  		logging.Uint64("height", blockHeight),
  1356  	)
  1357  
  1358  	app.protocolUpgradeService.BeginBlock(ctx, blockHeight)
  1359  	app.top.BeginBlock(ctx, blockHeight, proposer)
  1360  	app.balanceChecker.BeginBlock(ctx)
  1361  	blockDuration := app.currentTimestamp.Sub(app.previousTimestamp)
  1362  	app.exec.BeginBlock(ctx, blockDuration)
  1363  	return ctx
  1364  }
  1365  
  1366  func (app *App) startProtocolUpgrade(ctx context.Context) {
  1367  	// Stop blockchain server so it doesn't accept transactions and it doesn't times out.
  1368  	go func() {
  1369  		if err := app.stopBlockchain(); err != nil {
  1370  			app.log.Error("an error occurred while stopping the blockchain", zap.Error(err))
  1371  		}
  1372  	}()
  1373  
  1374  	ctx, cancel := context.WithCancel(ctx)
  1375  	defer cancel()
  1376  
  1377  	var eventsCh <-chan events.Event
  1378  	var errsCh <-chan error
  1379  	if app.broker.StreamingEnabled() {
  1380  		// wait here for data node send back the confirmation
  1381  		eventsCh, errsCh = app.broker.SocketClient().Receive(ctx)
  1382  	}
  1383  
  1384  	app.broker.Send(
  1385  		events.NewProtocolUpgradeStarted(ctx, eventspb.ProtocolUpgradeStarted{
  1386  			LastBlockHeight: app.stats.Height(),
  1387  		}),
  1388  	)
  1389  
  1390  	if eventsCh != nil {
  1391  		app.log.Info("waiting for data node to get ready for upgrade")
  1392  
  1393  	Loop:
  1394  		for {
  1395  			select {
  1396  			case e := <-eventsCh:
  1397  				if e.Type() != events.ProtocolUpgradeDataNodeReadyEvent {
  1398  					continue
  1399  				}
  1400  				if e.StreamMessage().GetProtocolUpgradeDataNodeReady().GetLastBlockHeight() == app.stats.Height() {
  1401  					cancel()
  1402  					break Loop
  1403  				}
  1404  			case err := <-errsCh:
  1405  				app.log.Panic("failed to wait for data node to get ready for upgrade", logging.Error(err))
  1406  			}
  1407  		}
  1408  	}
  1409  
  1410  	app.protocolUpgradeService.SetReadyForUpgrade()
  1411  
  1412  	// wait until killed
  1413  	for {
  1414  		time.Sleep(1 * time.Second)
  1415  		app.log.Info("application is ready for shutdown")
  1416  	}
  1417  }
  1418  
  1419  // Finalize calculates the app hash for the block ending.
  1420  func (app *App) Finalize() []byte {
  1421  	// call checkpoint _first_ so the snapshot contains the correct checkpoint state.
  1422  	cpt, _ := app.checkpoint.Checkpoint(app.blockCtx, app.currentTimestamp)
  1423  
  1424  	t0 := time.Now()
  1425  
  1426  	var snapHash []byte
  1427  	var err error
  1428  	// if there is an approved protocol upgrade proposal and the current block height is later than the proposal's block height then take a snapshot and wait to be killed by the process manager
  1429  	if app.protocolUpgradeService.TimeForUpgrade() {
  1430  		app.protocolUpgradeService.Cleanup(app.blockCtx)
  1431  		snapHash, err = app.snapshotEngine.SnapshotNow(app.blockCtx)
  1432  		if err == nil {
  1433  			app.protocolUpgradeService.SetCoreReadyForUpgrade()
  1434  		}
  1435  	} else if app.cfg.SnapshotDebug.DevEnabled {
  1436  		if height, _ := vgcontext.BlockHeightFromContext(app.blockCtx); height == app.cfg.SnapshotDebug.CrashAtHeight {
  1437  			hash, err := app.snapshotEngine.SnapshotDump(app.blockCtx, app.cfg.SnapshotDebug.DebugCrashFile)
  1438  			if err != nil {
  1439  				app.log.Panic("Failed to dump snapshot file", logging.Error(err), logging.String("snapshot-hash", string(hash)))
  1440  			} else {
  1441  				app.log.Panic("Dumped snapshot file successfully", logging.String("snapshot-hash", string(hash)), logging.String("dump-file", app.cfg.SnapshotDebug.DebugCrashFile))
  1442  			}
  1443  		}
  1444  	} else {
  1445  		snapHash, _, err = app.snapshotEngine.Snapshot(app.blockCtx)
  1446  	}
  1447  
  1448  	if err != nil {
  1449  		app.log.Panic("Failed to create snapshot",
  1450  			logging.Error(err))
  1451  	}
  1452  
  1453  	t1 := time.Now()
  1454  	if len(snapHash) > 0 {
  1455  		app.log.Info("State has been snapshotted", logging.Float64("duration", t1.Sub(t0).Seconds()))
  1456  	}
  1457  	appHash := snapHash
  1458  
  1459  	if len(snapHash) == 0 {
  1460  		appHash = vgcrypto.Hash([]byte(app.version))
  1461  		appHash = append(appHash, app.exec.Hash()...)
  1462  		appHash = append(appHash, app.delegation.Hash()...)
  1463  		appHash = append(appHash, app.gov.Hash()...)
  1464  		appHash = append(appHash, app.stakingAccounts.Hash()...)
  1465  	}
  1466  
  1467  	if cpt != nil {
  1468  		if len(snapHash) == 0 {
  1469  			// only append to commit hash if we aren't using the snapshot hash
  1470  			// otherwise restoring a checkpoint would restore an incomplete/wrong hash
  1471  			appHash = append(appHash, cpt.Hash...)
  1472  			app.log.Debug("checkpoint hash", logging.String("response-data", hex.EncodeToString(cpt.Hash)))
  1473  		}
  1474  		_ = app.handleCheckpoint(cpt)
  1475  	}
  1476  
  1477  	// the snapshot produce an actual hash, so no need
  1478  	// to rehash if we have a snapshot hash.
  1479  	// otherwise, it's a concatenation of hash that we get,
  1480  	// so we just re-hash to have an output which is actually an
  1481  	// hash and is consistent over all calls to Commit
  1482  	if len(snapHash) <= 0 {
  1483  		appHash = vgcrypto.Hash(appHash)
  1484  	} else {
  1485  		app.broker.Send(events.NewSnapshotEventEvent(app.blockCtx, app.stats.Height(), app.cBlock, app.protocolUpgradeService.TimeForUpgrade()))
  1486  	}
  1487  
  1488  	// Update response and save the apphash incase we lose connection with tendermint and need to verify our
  1489  	// current state
  1490  	app.log.Debug("apphash calculated", logging.String("response-data", hex.EncodeToString(appHash)))
  1491  	return appHash
  1492  }
  1493  
  1494  func (app *App) OnCommit() (*tmtypes.ResponseCommit, error) {
  1495  	app.log.Debug("entering commit", logging.Time("at", time.Now()), logging.Uint64("height", app.stats.Height()))
  1496  	defer func() { app.log.Debug("leaving commit", logging.Time("at", time.Now())) }()
  1497  	app.updateStats()
  1498  	app.setBatchStats()
  1499  	if !app.nilPow {
  1500  		app.pow.OnCommit()
  1501  	}
  1502  	app.broker.Send(
  1503  		events.NewEndBlock(app.blockCtx, eventspb.EndBlock{
  1504  			Height: app.stats.Height(),
  1505  		}),
  1506  	)
  1507  
  1508  	return &tmtypes.ResponseCommit{}, nil
  1509  }
  1510  
  1511  func (app *App) handleCheckpoint(cpt *types.CheckpointState) error {
  1512  	now := app.currentTimestamp
  1513  	height, _ := vgcontext.BlockHeightFromContext(app.blockCtx)
  1514  	cpFileName := fmt.Sprintf("%s-%d-%s.cp", now.Format("20060102150405"), height, hex.EncodeToString(cpt.Hash))
  1515  	cpFilePath, err := app.vegaPaths.CreateStatePathFor(paths.StatePath(filepath.Join(paths.CheckpointStateHome.String(), cpFileName)))
  1516  	if err != nil {
  1517  		return fmt.Errorf("couldn't get path for checkpoint file: %w", err)
  1518  	}
  1519  	if err := vgfs.WriteFile(cpFilePath, cpt.State); err != nil {
  1520  		return fmt.Errorf("couldn't write checkpoint file at %s: %w", cpFilePath, err)
  1521  	}
  1522  	// emit the event indicating a new checkpoint was created
  1523  	// this function is called both for interval checkpoints and withdrawal checkpoints
  1524  	event := events.NewCheckpointEvent(app.blockCtx, cpt)
  1525  	app.broker.Send(event)
  1526  
  1527  	return app.removeOldCheckpoints()
  1528  }
  1529  
  1530  func (app *App) removeOldCheckpoints() error {
  1531  	cpDirPath, err := app.vegaPaths.CreateStatePathFor(paths.StatePath(paths.CheckpointStateHome.String()))
  1532  	if err != nil {
  1533  		return fmt.Errorf("couldn't get checkpoints directory: %w", err)
  1534  	}
  1535  
  1536  	files, err := ioutil.ReadDir(cpDirPath)
  1537  	if err != nil {
  1538  		return fmt.Errorf("could not open the checkpoint directory: %w", err)
  1539  	}
  1540  
  1541  	// we assume that the files in this directory are only
  1542  	// from the checkpoints
  1543  	// and always keep the last 20, so return if we have less than that
  1544  	if len(files) <= int(app.cfg.KeepCheckpointsMax) {
  1545  		return nil
  1546  	}
  1547  
  1548  	oldest := app.stats.Height()
  1549  	toRemove := ""
  1550  	for _, file := range files {
  1551  		// checkpoint have the following format:
  1552  		// 20230322173929-12140156-d833359cb648eb315b4d3f9ccaa5092bd175b2f72a9d44783377ca5d7a2ec965.cp
  1553  		// which is:
  1554  		// time-block-hash.cp
  1555  		// we split and should have the block in splitted[1]
  1556  		splitted := strings.Split(file.Name(), "-")
  1557  		if len(splitted) != 3 {
  1558  			app.log.Error("weird checkpoint file name", logging.String("checkpoint-file", file.Name()))
  1559  			// weird file, keep going
  1560  			continue
  1561  		}
  1562  		block, err := strconv.ParseInt(splitted[1], 10, 64)
  1563  		if err != nil {
  1564  			app.log.Error("could not parse block number", logging.Error(err), logging.String("checkpoint-file", file.Name()))
  1565  			continue
  1566  		}
  1567  
  1568  		if uint64(block) < oldest {
  1569  			oldest = uint64(block)
  1570  			toRemove = file.Name()
  1571  		}
  1572  	}
  1573  
  1574  	if len(toRemove) > 0 {
  1575  		finalPath := filepath.Join(cpDirPath, toRemove)
  1576  		if err := os.Remove(finalPath); err != nil {
  1577  			app.log.Error("could not remove old checkpoint file",
  1578  				logging.Error(err),
  1579  				logging.String("checkpoint-file", finalPath),
  1580  			)
  1581  		}
  1582  		// just return an error, not much we can do
  1583  		return nil
  1584  	}
  1585  
  1586  	return nil
  1587  }
  1588  
  1589  // OnCheckTxSpam checks for spam and replay.
  1590  func (app *App) OnCheckTxSpam(tx abci.Tx) tmtypes.ResponseCheckTx {
  1591  	resp := tmtypes.ResponseCheckTx{}
  1592  
  1593  	if app.txCache.IsTxInCache(tx.Hash()) {
  1594  		resp.Code = blockchain.AbciSpamError
  1595  		resp.Data = []byte("delayed transaction already included in a block")
  1596  		return resp
  1597  	}
  1598  
  1599  	// verify proof of work and replay
  1600  	if !app.nilPow {
  1601  		if err := app.pow.CheckTx(tx); err != nil {
  1602  			if app.log.IsDebug() {
  1603  				app.log.Debug(err.Error())
  1604  			}
  1605  			resp.Code = blockchain.AbciSpamError
  1606  			resp.Data = []byte(err.Error())
  1607  			return resp
  1608  		}
  1609  	}
  1610  	// additional spam checks
  1611  	if !app.nilSpam {
  1612  		if err := app.spam.PreBlockAccept(tx); err != nil {
  1613  			app.log.Error(err.Error())
  1614  			resp.Code = blockchain.AbciSpamError
  1615  			resp.Data = []byte(err.Error())
  1616  			return resp
  1617  		}
  1618  	}
  1619  	return resp
  1620  }
  1621  
  1622  // OnCheckTx performs soft validations.
  1623  func (app *App) OnCheckTx(ctx context.Context, _ *tmtypes.RequestCheckTx, tx abci.Tx) (context.Context, *tmtypes.ResponseCheckTx) {
  1624  	resp := tmtypes.ResponseCheckTx{}
  1625  
  1626  	if app.log.IsDebug() {
  1627  		app.log.Debug("entering checkTx", logging.String("tid", tx.GetPoWTID()), logging.String("command", tx.Command().String()))
  1628  	}
  1629  
  1630  	if err := app.canSubmitTx(tx); err != nil {
  1631  		resp.Code = blockchain.AbciTxnValidationFailure
  1632  		resp.Data = []byte(err.Error())
  1633  		return ctx, &resp
  1634  	}
  1635  
  1636  	gasWanted, err := app.gastimator.CalcGasWantedForTx(tx)
  1637  	if err != nil { // this error means the transaction couldn't be parsed
  1638  		app.log.Error("error getting gas estimate", logging.Error(err))
  1639  		resp.Code = blockchain.AbciTxnValidationFailure
  1640  		resp.Data = []byte(err.Error())
  1641  		return ctx, &resp
  1642  	}
  1643  
  1644  	resp.GasWanted = int64(gasWanted)
  1645  	if app.log.IsDebug() {
  1646  		app.log.Debug("transaction passed checkTx", logging.String("tid", tx.GetPoWTID()), logging.String("command", tx.Command().String()))
  1647  	}
  1648  
  1649  	return ctx, &resp
  1650  }
  1651  
  1652  func (app *App) canSubmitTx(tx abci.Tx) (err error) {
  1653  	defer func() {
  1654  		if err != nil {
  1655  			app.log.Error("cannot submit transaction", logging.Error(err))
  1656  		}
  1657  	}()
  1658  
  1659  	switch tx.Command() {
  1660  	case txn.SubmitOrderCommand, txn.AmendOrderCommand, txn.CancelOrderCommand, txn.LiquidityProvisionCommand, txn.AmendLiquidityProvisionCommand, txn.CancelLiquidityProvisionCommand, txn.StopOrdersCancellationCommand, txn.StopOrdersSubmissionCommand:
  1661  		if !app.limits.CanTrade() {
  1662  			return ErrTradingDisabled
  1663  		}
  1664  	case txn.SubmitAMMCommand, txn.AmendAMMCommand, txn.CancelAMMCommand:
  1665  		if !app.limits.CanUseAMMPool() {
  1666  			return ErrAMMPoolDisabled
  1667  		}
  1668  	case txn.ProposeCommand:
  1669  		praw := &commandspb.ProposalSubmission{}
  1670  		if err := tx.Unmarshal(praw); err != nil {
  1671  			return fmt.Errorf("could not unmarshal proposal submission: %w", err)
  1672  		}
  1673  		p, err := types.NewProposalSubmissionFromProto(praw)
  1674  		if err != nil {
  1675  			return fmt.Errorf("invalid proposal submission: %w", err)
  1676  		}
  1677  		if p.Terms == nil {
  1678  			return errors.New("invalid proposal submission")
  1679  		}
  1680  		switch p.Terms.Change.GetTermType() {
  1681  		case types.ProposalTermsTypeNewMarket:
  1682  			if !app.limits.CanProposeMarket() {
  1683  				return ErrMarketProposalDisabled
  1684  			}
  1685  			if p.Terms.GetNewMarket().Changes.ProductType() == types.ProductTypePerps && !app.limits.CanProposePerpsMarket() {
  1686  				return ErrPerpsMarketProposalDisabled
  1687  			}
  1688  			return validateUseOfEthOracles(p.Terms.Change, app.netp)
  1689  		case types.ProposalTermsTypeUpdateMarket:
  1690  			return validateUseOfEthOracles(p.Terms.Change, app.netp)
  1691  
  1692  		case types.ProposalTermsTypeNewAsset:
  1693  			if !app.limits.CanProposeAsset() {
  1694  				return ErrAssetProposalDisabled
  1695  			}
  1696  		case types.ProposalTermsTypeNewSpotMarket:
  1697  			if !app.limits.CanProposeSpotMarket() {
  1698  				return ErrSpotMarketProposalDisabled
  1699  			}
  1700  		}
  1701  	case txn.BatchProposeCommand:
  1702  		ps := &commandspb.BatchProposalSubmission{}
  1703  		if err := tx.Unmarshal(ps); err != nil {
  1704  			return fmt.Errorf("could not unmarshal batch proposal submission: %w", err)
  1705  		}
  1706  
  1707  		idgen := idgeneration.New(generateDeterministicID(tx))
  1708  		ids := make([]string, 0, len(ps.Terms.Changes))
  1709  
  1710  		for i := 0; i < len(ps.Terms.Changes); i++ {
  1711  			ids = append(ids, idgen.NextID())
  1712  		}
  1713  
  1714  		p, err := types.NewBatchProposalSubmissionFromProto(ps, ids)
  1715  		if err != nil {
  1716  			return fmt.Errorf("invalid batch proposal submission: %w", err)
  1717  		}
  1718  		if p.Terms == nil || len(p.Terms.Changes) == 0 {
  1719  			return errors.New("invalid batch proposal submission")
  1720  		}
  1721  
  1722  		for _, batchChange := range p.Terms.Changes {
  1723  			switch c := batchChange.Change.(type) {
  1724  			case *types.ProposalTermsNewMarket:
  1725  				if !app.limits.CanProposeMarket() {
  1726  					return ErrMarketProposalDisabled
  1727  				}
  1728  
  1729  				if c.NewMarket.Changes.ProductType() == types.ProductTypePerps && !app.limits.CanProposePerpsMarket() {
  1730  					return ErrPerpsMarketProposalDisabled
  1731  				}
  1732  				return validateUseOfEthOracles(c, app.netp)
  1733  			case *types.ProposalTermsUpdateMarket:
  1734  				return validateUseOfEthOracles(c, app.netp)
  1735  
  1736  			case *types.ProposalTermsNewSpotMarket:
  1737  				if !app.limits.CanProposeSpotMarket() {
  1738  					return ErrSpotMarketProposalDisabled
  1739  				}
  1740  			}
  1741  		}
  1742  	}
  1743  	return nil
  1744  }
  1745  
  1746  func validateUseOfEthOracles(change types.ProposalTerm, netp NetworkParameters) error {
  1747  	ethOracleEnabled, _ := netp.GetInt(netparams.EthereumOraclesEnabled)
  1748  
  1749  	switch c := change.(type) {
  1750  	case *types.ProposalTermsNewMarket:
  1751  		m := c.NewMarket
  1752  
  1753  		if m.Changes == nil {
  1754  			return nil
  1755  		}
  1756  
  1757  		// Here the instrument is *types.InstrumentConfiguration
  1758  		if m.Changes.Instrument == nil {
  1759  			return nil
  1760  		}
  1761  
  1762  		if m.Changes.Instrument.Product == nil {
  1763  			return nil
  1764  		}
  1765  
  1766  		switch product := m.Changes.Instrument.Product.(type) {
  1767  		case *types.InstrumentConfigurationFuture:
  1768  			if product.Future == nil {
  1769  				return nil
  1770  			}
  1771  			terminatedWithEthOracle := !product.Future.DataSourceSpecForTradingTermination.GetEthCallSpec().IsZero()
  1772  			settledWithEthOracle := !product.Future.DataSourceSpecForSettlementData.GetEthCallSpec().IsZero()
  1773  			if (terminatedWithEthOracle || settledWithEthOracle) && ethOracleEnabled != 1 {
  1774  				return ErrEthOraclesDisabled
  1775  			}
  1776  		}
  1777  
  1778  	case *types.ProposalTermsUpdateMarket:
  1779  		m := c.UpdateMarket
  1780  
  1781  		if m.Changes == nil {
  1782  			return nil
  1783  		}
  1784  
  1785  		// Here the instrument is *types.UpdateInstrumentConfiguration
  1786  		if m.Changes.Instrument == nil {
  1787  			return nil
  1788  		}
  1789  
  1790  		if m.Changes.Instrument.Product == nil {
  1791  			return nil
  1792  		}
  1793  
  1794  		switch product := m.Changes.Instrument.Product.(type) {
  1795  		case *types.UpdateInstrumentConfigurationFuture:
  1796  			if product.Future == nil {
  1797  				return nil
  1798  			}
  1799  			terminatedWithEthOracle := !product.Future.DataSourceSpecForTradingTermination.GetEthCallSpec().IsZero()
  1800  			settledWithEthOracle := !product.Future.DataSourceSpecForSettlementData.GetEthCallSpec().IsZero()
  1801  			if (terminatedWithEthOracle || settledWithEthOracle) && ethOracleEnabled != 1 {
  1802  				return ErrEthOraclesDisabled
  1803  			}
  1804  		}
  1805  	}
  1806  
  1807  	return nil
  1808  }
  1809  
  1810  func (app *App) CheckProtocolUpgradeProposal(ctx context.Context, tx abci.Tx) error {
  1811  	if err := app.RequireValidatorPubKey(ctx, tx); err != nil {
  1812  		return err
  1813  	}
  1814  	pu := &commandspb.ProtocolUpgradeProposal{}
  1815  	if err := tx.Unmarshal(pu); err != nil {
  1816  		return err
  1817  	}
  1818  	return app.protocolUpgradeService.IsValidProposal(ctx, tx.PubKeyHex(), pu.UpgradeBlockHeight, pu.VegaReleaseTag)
  1819  }
  1820  
  1821  func (app *App) RequireValidatorPubKey(_ context.Context, tx abci.Tx) error {
  1822  	if !app.top.IsValidatorVegaPubKey(tx.PubKeyHex()) {
  1823  		return ErrNodeSignatureFromNonValidator
  1824  	}
  1825  	return nil
  1826  }
  1827  
  1828  func (app *App) CheckBatchMarketInstructions(_ context.Context, tx abci.Tx) error {
  1829  	bmi := &commandspb.BatchMarketInstructions{}
  1830  	if err := tx.Unmarshal(bmi); err != nil {
  1831  		return err
  1832  	}
  1833  
  1834  	maxBatchSize := app.maxBatchSize.Load()
  1835  	size := uint64(len(bmi.UpdateMarginMode) + len(bmi.Cancellations) + len(bmi.Amendments) + len(bmi.Submissions) + len(bmi.StopOrdersSubmission) + len(bmi.StopOrdersCancellation))
  1836  	if size > maxBatchSize {
  1837  		return ErrMarketBatchInstructionTooBig(size, maxBatchSize)
  1838  	}
  1839  
  1840  	for _, s := range bmi.Submissions {
  1841  		if err := app.exec.CheckCanSubmitOrderOrLiquidityCommitment(tx.Party(), s.MarketId); err != nil {
  1842  			return err
  1843  		}
  1844  
  1845  		os, err := types.NewOrderSubmissionFromProto(s)
  1846  		if err != nil {
  1847  			return err
  1848  		}
  1849  
  1850  		if err := app.exec.CheckOrderSubmissionForSpam(os, tx.Party()); err != nil {
  1851  			return err
  1852  		}
  1853  	}
  1854  
  1855  	for _, s := range bmi.Amendments {
  1856  		if err := app.exec.CheckCanSubmitOrderOrLiquidityCommitment(tx.Party(), s.MarketId); err != nil {
  1857  			return err
  1858  		}
  1859  		// TODO add amend checks
  1860  	}
  1861  	return nil
  1862  }
  1863  
  1864  func (app *App) DeliverBatchMarketInstructions(
  1865  	ctx context.Context,
  1866  	tx abci.Tx,
  1867  	deterministicID string,
  1868  ) error {
  1869  	batch := &commandspb.BatchMarketInstructions{}
  1870  	if err := tx.Unmarshal(batch); err != nil {
  1871  		return err
  1872  	}
  1873  
  1874  	return NewBMIProcessor(app.log, app.exec, Validate{}).
  1875  		ProcessBatch(ctx, batch, tx.Party(), deterministicID, app.stats)
  1876  }
  1877  
  1878  func (app *App) RequireValidatorMasterPubKey(_ context.Context, tx abci.Tx) error {
  1879  	if !app.top.IsValidatorNodeID(tx.PubKeyHex()) {
  1880  		return ErrNodeSignatureWithNonValidatorMasterKey
  1881  	}
  1882  	return nil
  1883  }
  1884  
  1885  func (app *App) DeliverIssueSignatures(ctx context.Context, tx abci.Tx) error {
  1886  	is := &commandspb.IssueSignatures{}
  1887  	if err := tx.Unmarshal(is); err != nil {
  1888  		return err
  1889  	}
  1890  
  1891  	return app.top.IssueSignatures(ctx, vgcrypto.EthereumChecksumAddress(is.Submitter), is.ValidatorNodeId, is.ChainId, is.Kind)
  1892  }
  1893  
  1894  func (app *App) DeliverProtocolUpgradeCommand(ctx context.Context, tx abci.Tx) error {
  1895  	pu := &commandspb.ProtocolUpgradeProposal{}
  1896  	if err := tx.Unmarshal(pu); err != nil {
  1897  		return err
  1898  	}
  1899  	return app.protocolUpgradeService.UpgradeProposal(ctx, tx.PubKeyHex(), pu.UpgradeBlockHeight, pu.VegaReleaseTag)
  1900  }
  1901  
  1902  func (app *App) DeliverAnnounceNode(ctx context.Context, tx abci.Tx) error {
  1903  	an := &commandspb.AnnounceNode{}
  1904  	if err := tx.Unmarshal(an); err != nil {
  1905  		return err
  1906  	}
  1907  
  1908  	return app.top.ProcessAnnounceNode(ctx, an)
  1909  }
  1910  
  1911  func (app *App) DeliverValidatorHeartbeat(ctx context.Context, tx abci.Tx) error {
  1912  	an := &commandspb.ValidatorHeartbeat{}
  1913  	if err := tx.Unmarshal(an); err != nil {
  1914  		return err
  1915  	}
  1916  
  1917  	return app.top.ProcessValidatorHeartbeat(ctx, an, signatures.VerifyVegaSignature, signatures.VerifyEthereumSignature)
  1918  }
  1919  
  1920  func (app *App) CheckApplyReferralCode(_ context.Context, tx abci.Tx) error {
  1921  	if err := app.referralProgram.CheckSufficientBalanceForApplyReferralCode(types.PartyID(tx.Party()), app.balanceChecker.GetPartyBalance(tx.Party())); err != nil {
  1922  		return err
  1923  	}
  1924  	return nil
  1925  }
  1926  
  1927  func (app *App) CheckCreateOrUpdateReferralSet(_ context.Context, tx abci.Tx) error {
  1928  	if err := app.referralProgram.CheckSufficientBalanceForCreateOrUpdateReferralSet(types.PartyID(tx.Party()), app.balanceChecker.GetPartyBalance(tx.Party())); err != nil {
  1929  		return err
  1930  	}
  1931  	return nil
  1932  }
  1933  
  1934  func (app *App) CheckTransferCommand(_ context.Context, tx abci.Tx) error {
  1935  	tfr := &commandspb.Transfer{}
  1936  	if err := tx.Unmarshal(tfr); err != nil {
  1937  		return err
  1938  	}
  1939  	party := tx.Party()
  1940  	transfer, err := types.NewTransferFromProto("", party, tfr)
  1941  	if err != nil {
  1942  		return err
  1943  	}
  1944  	switch transfer.Kind {
  1945  	case types.TransferCommandKindOneOff:
  1946  		return app.banking.CheckTransfer(transfer.OneOff.TransferBase)
  1947  	case types.TransferCommandKindRecurring:
  1948  		return app.banking.CheckTransfer(transfer.Recurring.TransferBase)
  1949  	default:
  1950  		return errors.New("unsupported transfer kind")
  1951  	}
  1952  }
  1953  
  1954  func (app *App) DeliverTransferFunds(ctx context.Context, tx abci.Tx, id string) error {
  1955  	tfr := &commandspb.Transfer{}
  1956  	if err := tx.Unmarshal(tfr); err != nil {
  1957  		return err
  1958  	}
  1959  
  1960  	party := tx.Party()
  1961  	transferFunds, err := types.NewTransferFromProto(id, party, tfr)
  1962  	if err != nil {
  1963  		return err
  1964  	}
  1965  
  1966  	return app.banking.TransferFunds(ctx, transferFunds)
  1967  }
  1968  
  1969  func (app *App) DeliverCancelTransferFunds(ctx context.Context, tx abci.Tx) error {
  1970  	cancel := &commandspb.CancelTransfer{}
  1971  	if err := tx.Unmarshal(cancel); err != nil {
  1972  		return err
  1973  	}
  1974  
  1975  	return app.banking.CancelTransferFunds(ctx, types.NewCancelTransferFromProto(tx.Party(), cancel))
  1976  }
  1977  
  1978  func (app *App) DeliverStopOrdersSubmission(ctx context.Context, tx abci.Tx, deterministicID string) error {
  1979  	s := &commandspb.StopOrdersSubmission{}
  1980  	if err := tx.Unmarshal(s); err != nil {
  1981  		return err
  1982  	}
  1983  
  1984  	// Convert from proto to domain type
  1985  	os, err := types.NewStopOrderSubmissionFromProto(s)
  1986  	if err != nil {
  1987  		return err
  1988  	}
  1989  
  1990  	// Submit the create order request to the execution engine
  1991  	idgen := idgeneration.New(deterministicID)
  1992  	var fallsBelow, risesAbove *string
  1993  	if os.FallsBelow != nil {
  1994  		fallsBelow = ptr.From(idgen.NextID())
  1995  	}
  1996  	if os.RisesAbove != nil {
  1997  		risesAbove = ptr.From(idgen.NextID())
  1998  	}
  1999  
  2000  	_, err = app.exec.SubmitStopOrders(ctx, os, tx.Party(), idgen, fallsBelow, risesAbove)
  2001  	if err != nil {
  2002  		app.log.Error("could not submit stop order",
  2003  			logging.StopOrderSubmission(os), logging.Error(err))
  2004  	}
  2005  
  2006  	return nil
  2007  }
  2008  
  2009  func (app *App) DeliverStopOrdersCancellation(ctx context.Context, tx abci.Tx, deterministicID string) error {
  2010  	s := &commandspb.StopOrdersCancellation{}
  2011  	if err := tx.Unmarshal(s); err != nil {
  2012  		return err
  2013  	}
  2014  
  2015  	// Convert from proto to domain type
  2016  	os := types.NewStopOrderCancellationFromProto(s)
  2017  
  2018  	// Submit the create order request to the execution engine
  2019  	idgen := idgeneration.New(deterministicID)
  2020  	err := app.exec.CancelStopOrders(ctx, os, tx.Party(), idgen)
  2021  	if err != nil {
  2022  		app.log.Error("could not submit stop order",
  2023  			logging.StopOrderCancellation(os), logging.Error(err))
  2024  	}
  2025  
  2026  	return nil
  2027  }
  2028  
  2029  func (app *App) DeliverSubmitOrder(ctx context.Context, tx abci.Tx, deterministicID string) error {
  2030  	s := &commandspb.OrderSubmission{}
  2031  	if err := tx.Unmarshal(s); err != nil {
  2032  		return err
  2033  	}
  2034  
  2035  	app.stats.IncTotalCreateOrder()
  2036  
  2037  	// Convert from proto to domain type
  2038  	os, err := types.NewOrderSubmissionFromProto(s)
  2039  	if err != nil {
  2040  		return err
  2041  	}
  2042  	// Submit the create order request to the execution engine
  2043  	idgen := idgeneration.New(deterministicID)
  2044  	conf, err := app.exec.SubmitOrder(ctx, os, tx.Party(), idgen, idgen.NextID())
  2045  	if conf != nil {
  2046  		if app.log.GetLevel() <= logging.DebugLevel {
  2047  			app.log.Debug("Order confirmed",
  2048  				logging.OrderSubmission(os),
  2049  				logging.OrderWithTag(*conf.Order, "aggressive-order"),
  2050  				logging.String("passive-trades", fmt.Sprintf("%+v", conf.Trades)),
  2051  				logging.String("passive-orders", fmt.Sprintf("%+v", conf.PassiveOrdersAffected)))
  2052  		}
  2053  
  2054  		app.stats.AddCurrentTradesInBatch(uint64(len(conf.Trades)))
  2055  		app.stats.AddTotalTrades(uint64(len(conf.Trades)))
  2056  		app.stats.IncCurrentOrdersInBatch()
  2057  	}
  2058  
  2059  	// increment total orders, even for failures so current ID strategy is valid.
  2060  	app.stats.IncTotalOrders()
  2061  
  2062  	if err != nil && app.log.GetLevel() <= logging.DebugLevel {
  2063  		app.log.Debug("error message on creating order",
  2064  			logging.OrderSubmission(os),
  2065  			logging.Error(err))
  2066  	}
  2067  
  2068  	return err
  2069  }
  2070  
  2071  func (app *App) DeliverCancelOrder(ctx context.Context, tx abci.Tx, deterministicID string) error {
  2072  	porder := &commandspb.OrderCancellation{}
  2073  	if err := tx.Unmarshal(porder); err != nil {
  2074  		return err
  2075  	}
  2076  
  2077  	app.stats.IncTotalCancelOrder()
  2078  	app.log.Debug("Blockchain service received a CANCEL ORDER request", logging.String("order-id", porder.OrderId))
  2079  
  2080  	order := types.OrderCancellationFromProto(porder)
  2081  	// Submit the cancel new order request to the Vega trading core
  2082  	idgen := idgeneration.New(deterministicID)
  2083  	msg, err := app.exec.CancelOrder(ctx, order, tx.Party(), idgen)
  2084  	if err != nil {
  2085  		app.log.Error("error on cancelling order", logging.String("order-id", order.OrderID), logging.Error(err))
  2086  		return err
  2087  	}
  2088  	if app.cfg.LogOrderCancelDebug {
  2089  		for _, v := range msg {
  2090  			app.log.Debug("Order cancelled", logging.Order(*v.Order))
  2091  		}
  2092  	}
  2093  
  2094  	return nil
  2095  }
  2096  
  2097  func (app *App) DeliverAmendOrder(
  2098  	ctx context.Context,
  2099  	tx abci.Tx,
  2100  	deterministicID string,
  2101  ) (errl error) {
  2102  	order := &commandspb.OrderAmendment{}
  2103  	if err := tx.Unmarshal(order); err != nil {
  2104  		return err
  2105  	}
  2106  
  2107  	app.stats.IncTotalAmendOrder()
  2108  	app.log.Debug("Blockchain service received a AMEND ORDER request", logging.String("order-id", order.OrderId))
  2109  
  2110  	// Convert protobuf into local domain type
  2111  	oa, err := types.NewOrderAmendmentFromProto(order)
  2112  	if err != nil {
  2113  		return err
  2114  	}
  2115  
  2116  	// Submit the cancel new order request to the Vega trading core
  2117  	idgen := idgeneration.New(deterministicID)
  2118  	msg, err := app.exec.AmendOrder(ctx, oa, tx.Party(), idgen)
  2119  	if err != nil {
  2120  		app.log.Error("error on amending order", logging.String("order-id", order.OrderId), logging.Error(err))
  2121  		return err
  2122  	}
  2123  	if app.cfg.LogOrderAmendDebug {
  2124  		app.log.Debug("Order amended", logging.Order(*msg.Order))
  2125  	}
  2126  
  2127  	return nil
  2128  }
  2129  
  2130  func (app *App) DeliverWithdraw(ctx context.Context, tx abci.Tx, id string) error {
  2131  	w := &commandspb.WithdrawSubmission{}
  2132  	if err := tx.Unmarshal(w); err != nil {
  2133  		return err
  2134  	}
  2135  
  2136  	// Convert protobuf to local domain type
  2137  	ws, err := types.NewWithdrawSubmissionFromProto(w)
  2138  	if err != nil {
  2139  		return err
  2140  	}
  2141  	if err := app.processWithdraw(ctx, ws, id, tx.Party()); err != nil {
  2142  		return err
  2143  	}
  2144  	snap, err := app.checkpoint.BalanceCheckpoint(ctx)
  2145  	if err != nil {
  2146  		return err
  2147  	}
  2148  	return app.handleCheckpoint(snap)
  2149  }
  2150  
  2151  func (app *App) CheckCancelOrderForSpam(_ context.Context, tx abci.Tx) error {
  2152  	sub := &commandspb.OrderCancellation{}
  2153  	if err := tx.Unmarshal(sub); err != nil {
  2154  		return err
  2155  	}
  2156  	if err := app.exec.CheckCanSubmitOrderOrLiquidityCommitment(tx.Party(), sub.MarketId); err != nil {
  2157  		return err
  2158  	}
  2159  	return nil
  2160  }
  2161  
  2162  func (app *App) CheckCancelAmmForSpam(_ context.Context, tx abci.Tx) error {
  2163  	sub := &commandspb.CancelAMM{}
  2164  	if err := tx.Unmarshal(sub); err != nil {
  2165  		return err
  2166  	}
  2167  	if err := app.exec.CheckCanSubmitOrderOrLiquidityCommitment(tx.Party(), sub.MarketId); err != nil {
  2168  		return err
  2169  	}
  2170  	return nil
  2171  }
  2172  
  2173  func (app *App) CheckCancelLPForSpam(_ context.Context, tx abci.Tx) error {
  2174  	sub := &commandspb.LiquidityProvisionCancellation{}
  2175  	if err := tx.Unmarshal(sub); err != nil {
  2176  		return err
  2177  	}
  2178  	if err := app.exec.CheckCanSubmitOrderOrLiquidityCommitment(tx.Party(), sub.MarketId); err != nil {
  2179  		return err
  2180  	}
  2181  	return nil
  2182  }
  2183  
  2184  func (app *App) CheckAmendOrderForSpam(_ context.Context, tx abci.Tx) error {
  2185  	sub := &commandspb.OrderAmendment{}
  2186  	if err := tx.Unmarshal(sub); err != nil {
  2187  		return err
  2188  	}
  2189  	if err := app.exec.CheckCanSubmitOrderOrLiquidityCommitment(tx.Party(), sub.MarketId); err != nil {
  2190  		return err
  2191  	}
  2192  	return nil
  2193  }
  2194  
  2195  func (app *App) CheckAmendAmmForSpam(_ context.Context, tx abci.Tx) error {
  2196  	sub := &commandspb.AmendAMM{}
  2197  	if err := tx.Unmarshal(sub); err != nil {
  2198  		return err
  2199  	}
  2200  	if err := app.exec.CheckCanSubmitOrderOrLiquidityCommitment(tx.Party(), sub.MarketId); err != nil {
  2201  		return err
  2202  	}
  2203  	return nil
  2204  }
  2205  
  2206  func (app *App) CheckSubmitAmmForSpam(_ context.Context, tx abci.Tx) error {
  2207  	sub := &commandspb.SubmitAMM{}
  2208  	if err := tx.Unmarshal(sub); err != nil {
  2209  		return err
  2210  	}
  2211  	if err := app.exec.CheckCanSubmitOrderOrLiquidityCommitment(tx.Party(), sub.MarketId); err != nil {
  2212  		return err
  2213  	}
  2214  	return nil
  2215  }
  2216  
  2217  func (app *App) CheckLPSubmissionForSpam(_ context.Context, tx abci.Tx) error {
  2218  	sub := &commandspb.LiquidityProvisionSubmission{}
  2219  	if err := tx.Unmarshal(sub); err != nil {
  2220  		return err
  2221  	}
  2222  	if err := app.exec.CheckCanSubmitOrderOrLiquidityCommitment(tx.Party(), sub.MarketId); err != nil {
  2223  		return err
  2224  	}
  2225  	return nil
  2226  }
  2227  
  2228  func (app *App) CheckLPAmendForSpam(_ context.Context, tx abci.Tx) error {
  2229  	sub := &commandspb.LiquidityProvisionAmendment{}
  2230  	if err := tx.Unmarshal(sub); err != nil {
  2231  		return err
  2232  	}
  2233  	if err := app.exec.CheckCanSubmitOrderOrLiquidityCommitment(tx.Party(), sub.MarketId); err != nil {
  2234  		return err
  2235  	}
  2236  	return nil
  2237  }
  2238  
  2239  func (app *App) CheckOrderSubmissionForSpam(_ context.Context, tx abci.Tx) error {
  2240  	s := &commandspb.OrderSubmission{}
  2241  	if err := tx.Unmarshal(s); err != nil {
  2242  		return err
  2243  	}
  2244  
  2245  	if err := app.exec.CheckCanSubmitOrderOrLiquidityCommitment(tx.Party(), s.MarketId); err != nil {
  2246  		return err
  2247  	}
  2248  
  2249  	// Convert from proto to domain type
  2250  	os, err := types.NewOrderSubmissionFromProto(s)
  2251  	if err != nil {
  2252  		return err
  2253  	}
  2254  
  2255  	return app.exec.CheckOrderSubmissionForSpam(os, tx.Party())
  2256  }
  2257  
  2258  func (app *App) CheckPropose(_ context.Context, tx abci.Tx) error {
  2259  	p := &commandspb.ProposalSubmission{}
  2260  	if err := tx.Unmarshal(p); err != nil {
  2261  		return err
  2262  	}
  2263  
  2264  	propSubmission, err := types.NewProposalSubmissionFromProto(p)
  2265  	if err != nil {
  2266  		return err
  2267  	}
  2268  
  2269  	terms := propSubmission.Terms
  2270  	switch terms.Change.GetTermType() {
  2271  	case types.ProposalTermsTypeUpdateNetworkParameter:
  2272  		return app.netp.IsUpdateAllowed(terms.GetUpdateNetworkParameter().Changes.Key)
  2273  	default:
  2274  		return nil
  2275  	}
  2276  }
  2277  
  2278  func (app *App) CheckBatchPropose(_ context.Context, tx abci.Tx, deterministicBatchID string) error {
  2279  	p := &commandspb.BatchProposalSubmission{}
  2280  	if err := tx.Unmarshal(p); err != nil {
  2281  		return err
  2282  	}
  2283  
  2284  	idgen := idgeneration.New(deterministicBatchID)
  2285  	ids := make([]string, 0, len(p.Terms.Changes))
  2286  
  2287  	for i := 0; i < len(p.Terms.Changes); i++ {
  2288  		ids = append(ids, idgen.NextID())
  2289  	}
  2290  
  2291  	propSubmission, err := types.NewBatchProposalSubmissionFromProto(p, ids)
  2292  	if err != nil {
  2293  		return err
  2294  	}
  2295  
  2296  	errs := verrors.NewCumulatedErrors()
  2297  	for _, change := range propSubmission.Terms.Changes {
  2298  		switch term := change.Change.(type) {
  2299  		case *types.ProposalTermsUpdateNetworkParameter:
  2300  			if err := app.netp.IsUpdateAllowed(term.UpdateNetworkParameter.Changes.Key); err != nil {
  2301  				errs.Add(err)
  2302  			}
  2303  		}
  2304  	}
  2305  
  2306  	if errs.HasAny() {
  2307  		return errs
  2308  	}
  2309  
  2310  	return nil
  2311  }
  2312  
  2313  func (app *App) DeliverPropose(ctx context.Context, tx abci.Tx, deterministicID string) error {
  2314  	prop := &commandspb.ProposalSubmission{}
  2315  	if err := tx.Unmarshal(prop); err != nil {
  2316  		return err
  2317  	}
  2318  
  2319  	party := tx.Party()
  2320  
  2321  	if app.log.GetLevel() <= logging.DebugLevel {
  2322  		app.log.Debug("submitting proposal",
  2323  			logging.ProposalID(deterministicID),
  2324  			logging.String("proposal-reference", prop.Reference),
  2325  			logging.String("proposal-party", party),
  2326  			logging.String("proposal-terms", prop.Terms.String()))
  2327  	}
  2328  
  2329  	propSubmission, err := types.NewProposalSubmissionFromProto(prop)
  2330  	if err != nil {
  2331  		return err
  2332  	}
  2333  	toSubmit, err := app.gov.SubmitProposal(ctx, *propSubmission, deterministicID, party)
  2334  	if err != nil {
  2335  		app.log.Debug("could not submit proposal",
  2336  			logging.ProposalID(deterministicID),
  2337  			logging.Error(err))
  2338  		return err
  2339  	}
  2340  
  2341  	if toSubmit.IsNewMarket() {
  2342  		// opening auction start
  2343  		oos := time.Unix(toSubmit.Proposal().Terms.ClosingTimestamp, 0).Round(time.Second)
  2344  		nm := toSubmit.NewMarket()
  2345  
  2346  		// @TODO pass in parent and insurance pool share if required
  2347  		if err := app.exec.SubmitMarket(ctx, nm.Market(), party, oos); err != nil {
  2348  			app.log.Debug("unable to submit new market with liquidity submission",
  2349  				logging.ProposalID(nm.Market().ID),
  2350  				logging.Error(err))
  2351  			// an error happened when submitting the market
  2352  			// we should cancel this proposal now
  2353  			if err := app.gov.RejectProposal(ctx, toSubmit.Proposal(), types.ProposalErrorCouldNotInstantiateMarket, err); err != nil {
  2354  				// this should never happen
  2355  				app.log.Panic("tried to reject a nonexistent proposal",
  2356  					logging.String("proposal-id", toSubmit.Proposal().ID),
  2357  					logging.Error(err))
  2358  			}
  2359  			return err
  2360  		}
  2361  	} else if toSubmit.IsNewSpotMarket() {
  2362  		oos := time.Unix(toSubmit.Proposal().Terms.ClosingTimestamp, 0).Round(time.Second)
  2363  		nm := toSubmit.NewSpotMarket()
  2364  		if err := app.exec.SubmitSpotMarket(ctx, nm.Market(), party, oos); err != nil {
  2365  			app.log.Debug("unable to submit new spot market",
  2366  				logging.ProposalID(nm.Market().ID),
  2367  				logging.Error(err))
  2368  			// an error happened when submitting the market
  2369  			// we should cancel this proposal now
  2370  			if err := app.gov.RejectProposal(ctx, toSubmit.Proposal(), types.ProposalErrorCouldNotInstantiateMarket, err); err != nil {
  2371  				// this should never happen
  2372  				app.log.Panic("tried to reject a nonexistent proposal",
  2373  					logging.String("proposal-id", toSubmit.Proposal().ID),
  2374  					logging.Error(err))
  2375  			}
  2376  			return err
  2377  		}
  2378  	}
  2379  
  2380  	return nil
  2381  }
  2382  
  2383  func (app *App) DeliverBatchPropose(ctx context.Context, tx abci.Tx, deterministicBatchID string) (err error) {
  2384  	prop := &commandspb.BatchProposalSubmission{}
  2385  	if err := tx.Unmarshal(prop); err != nil {
  2386  		return err
  2387  	}
  2388  
  2389  	party := tx.Party()
  2390  
  2391  	if app.log.GetLevel() <= logging.DebugLevel {
  2392  		app.log.Debug("submitting batch proposal",
  2393  			logging.ProposalID(deterministicBatchID),
  2394  			logging.String("proposal-reference", prop.Reference),
  2395  			logging.String("proposal-party", party),
  2396  			logging.String("proposal-terms", prop.Terms.String()))
  2397  	}
  2398  
  2399  	idgen := idgeneration.New(deterministicBatchID)
  2400  
  2401  	// Burn one so the first proposal doesn't have the same ID as the batch ID
  2402  	idgen.NextID()
  2403  	ids := make([]string, 0, len(prop.Terms.Changes))
  2404  
  2405  	for i := 0; i < len(prop.Terms.Changes); i++ {
  2406  		ids = append(ids, idgen.NextID())
  2407  	}
  2408  
  2409  	propSubmission, err := types.NewBatchProposalSubmissionFromProto(prop, ids)
  2410  	if err != nil {
  2411  		return err
  2412  	}
  2413  	toSubmits, err := app.gov.SubmitBatchProposal(ctx, *propSubmission, deterministicBatchID, party)
  2414  	if err != nil {
  2415  		app.log.Debug("could not submit batch proposal",
  2416  			logging.ProposalID(deterministicBatchID),
  2417  			logging.Error(err))
  2418  		return err
  2419  	}
  2420  
  2421  	var submittedMarketIDs []string
  2422  	defer func() {
  2423  		if err == nil {
  2424  			return
  2425  		}
  2426  
  2427  		// an error happened when submitting the market
  2428  		// we should cancel this proposal now
  2429  		if err := app.gov.RejectBatchProposal(ctx, deterministicBatchID,
  2430  			types.ProposalErrorCouldNotInstantiateMarket, err); err != nil {
  2431  			// this should never happen
  2432  			app.log.Panic("tried to reject a nonexistent batch proposal",
  2433  				logging.String("proposal-id", deterministicBatchID),
  2434  				logging.Error(err))
  2435  		}
  2436  
  2437  		for _, marketID := range submittedMarketIDs {
  2438  			if err := app.exec.RejectMarket(ctx, marketID); err != nil {
  2439  				// this should never happen
  2440  				app.log.Panic("unable to submit reject submitted market",
  2441  					logging.ProposalID(marketID),
  2442  					logging.Error(err))
  2443  			}
  2444  		}
  2445  	}()
  2446  
  2447  	for _, toSubmit := range toSubmits {
  2448  		if toSubmit.IsNewMarket() {
  2449  			// opening auction start
  2450  			oos := time.Unix(toSubmit.Proposal().Terms.ClosingTimestamp, 0).Round(time.Second)
  2451  			nm := toSubmit.NewMarket()
  2452  
  2453  			// @TODO pass in parent and insurance pool share if required
  2454  			if err = app.exec.SubmitMarket(ctx, nm.Market(), party, oos); err != nil {
  2455  				app.log.Debug("unable to submit new market with liquidity submission",
  2456  					logging.ProposalID(nm.Market().ID),
  2457  					logging.Error(err))
  2458  				return err
  2459  			}
  2460  
  2461  			submittedMarketIDs = append(submittedMarketIDs, nm.Market().ID)
  2462  		} else if toSubmit.IsNewSpotMarket() {
  2463  			oos := time.Unix(toSubmit.Proposal().Terms.ClosingTimestamp, 0).Round(time.Second)
  2464  			nm := toSubmit.NewSpotMarket()
  2465  			if err = app.exec.SubmitSpotMarket(ctx, nm.Market(), party, oos); err != nil {
  2466  				app.log.Debug("unable to submit new spot market",
  2467  					logging.ProposalID(nm.Market().ID),
  2468  					logging.Error(err))
  2469  				return err
  2470  			}
  2471  
  2472  			submittedMarketIDs = append(submittedMarketIDs, nm.Market().ID)
  2473  		}
  2474  	}
  2475  
  2476  	return nil
  2477  }
  2478  
  2479  func (app *App) DeliverVote(ctx context.Context, tx abci.Tx) error {
  2480  	vote := &commandspb.VoteSubmission{}
  2481  
  2482  	if err := tx.Unmarshal(vote); err != nil {
  2483  		return err
  2484  	}
  2485  
  2486  	party := tx.Party()
  2487  	app.log.Debug("Voting on proposal",
  2488  		logging.String("proposal-id", vote.ProposalId),
  2489  		logging.String("vote-party", party),
  2490  		logging.String("vote-value", vote.Value.String()))
  2491  
  2492  	if err := commands.CheckVoteSubmission(vote); err != nil {
  2493  		return err
  2494  	}
  2495  
  2496  	v := types.NewVoteSubmissionFromProto(vote)
  2497  
  2498  	return app.gov.AddVote(ctx, *v, party)
  2499  }
  2500  
  2501  func (app *App) DeliverNodeSignature(ctx context.Context, tx abci.Tx) error {
  2502  	ns := &commandspb.NodeSignature{}
  2503  	if err := tx.Unmarshal(ns); err != nil {
  2504  		return err
  2505  	}
  2506  	return app.notary.RegisterSignature(ctx, tx.PubKeyHex(), *ns)
  2507  }
  2508  
  2509  func (app *App) DeliverLiquidityProvision(ctx context.Context, tx abci.Tx, deterministicID string) error {
  2510  	sub := &commandspb.LiquidityProvisionSubmission{}
  2511  	if err := tx.Unmarshal(sub); err != nil {
  2512  		return err
  2513  	}
  2514  
  2515  	// Convert protobuf message to local domain type
  2516  	lps, err := types.LiquidityProvisionSubmissionFromProto(sub)
  2517  	if err != nil {
  2518  		if app.log.GetLevel() <= logging.DebugLevel {
  2519  			app.log.Debug("Unable to convert LiquidityProvisionSubmission protobuf message to domain type",
  2520  				logging.LiquidityProvisionSubmissionProto(sub), logging.Error(err))
  2521  		}
  2522  		return err
  2523  	}
  2524  
  2525  	return app.exec.SubmitLiquidityProvision(ctx, lps, tx.Party(), deterministicID)
  2526  }
  2527  
  2528  func (app *App) DeliverCancelLiquidityProvision(ctx context.Context, tx abci.Tx) error {
  2529  	cancel := &commandspb.LiquidityProvisionCancellation{}
  2530  	if err := tx.Unmarshal(cancel); err != nil {
  2531  		return err
  2532  	}
  2533  
  2534  	app.log.Debug("Blockchain service received a CANCEL Liquidity Provision request", logging.String("liquidity-provision-market-id", cancel.MarketId))
  2535  
  2536  	lpc, err := types.LiquidityProvisionCancellationFromProto(cancel)
  2537  	if err != nil {
  2538  		if app.log.GetLevel() <= logging.DebugLevel {
  2539  			app.log.Debug("Unable to convert LiquidityProvisionCancellation protobuf message to domain type",
  2540  				logging.LiquidityProvisionCancellationProto(cancel), logging.Error(err))
  2541  		}
  2542  		return err
  2543  	}
  2544  
  2545  	err = app.exec.CancelLiquidityProvision(ctx, lpc, tx.Party())
  2546  	if err != nil {
  2547  		app.log.Debug("error on cancelling order",
  2548  			logging.PartyID(tx.Party()),
  2549  			logging.String("liquidity-provision-market-id", lpc.MarketID),
  2550  			logging.Error(err))
  2551  		return err
  2552  	}
  2553  	if app.cfg.LogOrderCancelDebug {
  2554  		app.log.Debug("Liquidity provision cancelled", logging.LiquidityProvisionCancellation(*lpc))
  2555  	}
  2556  
  2557  	return nil
  2558  }
  2559  
  2560  func (app *App) DeliverAmendLiquidityProvision(ctx context.Context, tx abci.Tx, deterministicID string) error {
  2561  	lp := &commandspb.LiquidityProvisionAmendment{}
  2562  	if err := tx.Unmarshal(lp); err != nil {
  2563  		return err
  2564  	}
  2565  
  2566  	app.log.Debug("Blockchain service received a AMEND Liquidity Provision request", logging.String("liquidity-provision-market-id", lp.MarketId))
  2567  
  2568  	// Convert protobuf into local domain type
  2569  	lpa, err := types.LiquidityProvisionAmendmentFromProto(lp)
  2570  	if err != nil {
  2571  		return err
  2572  	}
  2573  
  2574  	// Submit the amend liquidity provision request to the Vega trading core
  2575  	err = app.exec.AmendLiquidityProvision(ctx, lpa, tx.Party(), deterministicID)
  2576  	if err != nil {
  2577  		app.log.Debug("error on amending Liquidity Provision",
  2578  			logging.String("liquidity-provision-market-id", lpa.MarketID),
  2579  			logging.PartyID(tx.Party()),
  2580  			logging.Error(err))
  2581  		return err
  2582  	}
  2583  	if app.cfg.LogOrderAmendDebug {
  2584  		app.log.Debug("Liquidity Provision amended", logging.LiquidityProvisionAmendment(*lpa))
  2585  	}
  2586  
  2587  	return nil
  2588  }
  2589  
  2590  func (app *App) DeliverNodeVote(ctx context.Context, tx abci.Tx) error {
  2591  	vote := &commandspb.NodeVote{}
  2592  	if err := tx.Unmarshal(vote); err != nil {
  2593  		return err
  2594  	}
  2595  
  2596  	pubKey := vgcrypto.NewPublicKey(tx.PubKeyHex(), tx.PubKey())
  2597  
  2598  	return app.witness.AddNodeCheck(ctx, vote, pubKey)
  2599  }
  2600  
  2601  func (app *App) DeliverChainEvent(ctx context.Context, tx abci.Tx, id string) error {
  2602  	ce := &commandspb.ChainEvent{}
  2603  	if err := tx.Unmarshal(ce); err != nil {
  2604  		return err
  2605  	}
  2606  	return app.processChainEvent(ctx, ce, tx.PubKeyHex(), id)
  2607  }
  2608  
  2609  func (app *App) DeliverSubmitOracleData(ctx context.Context, tx abci.Tx) error {
  2610  	data := &commandspb.OracleDataSubmission{}
  2611  	if err := tx.Unmarshal(data); err != nil {
  2612  		return err
  2613  	}
  2614  
  2615  	pubKey := vgcrypto.NewPublicKey(tx.PubKeyHex(), tx.PubKey())
  2616  	oracleData, err := app.oracles.Adaptors.Normalise(pubKey, *data)
  2617  	if err != nil {
  2618  		return err
  2619  	}
  2620  
  2621  	return app.oracles.Engine.BroadcastData(ctx, *oracleData)
  2622  }
  2623  
  2624  func (app *App) CheckSubmitOracleData(_ context.Context, tx abci.Tx) error {
  2625  	data := &commandspb.OracleDataSubmission{}
  2626  	if err := tx.Unmarshal(data); err != nil {
  2627  		return err
  2628  	}
  2629  
  2630  	pubKey := vgcrypto.NewPublicKey(tx.PubKeyHex(), tx.PubKey())
  2631  	oracleData, err := app.oracles.Adaptors.Normalise(pubKey, *data)
  2632  	if err != nil {
  2633  		return ErrOracleDataNormalization(err)
  2634  	}
  2635  
  2636  	if !app.oracles.Engine.ListensToSigners(*oracleData) {
  2637  		return ErrUnexpectedTxPubKey
  2638  	}
  2639  
  2640  	hasMatch, err := app.oracles.Engine.HasMatch(*oracleData)
  2641  	if err != nil {
  2642  		return err
  2643  	}
  2644  	if !hasMatch {
  2645  		return ErrOracleNoSubscribers
  2646  	}
  2647  	return nil
  2648  }
  2649  
  2650  func (app *App) onTick(ctx context.Context, t time.Time) {
  2651  	toEnactProposals, voteClosedProposals := app.gov.OnTick(ctx, t)
  2652  	for _, voteClosed := range voteClosedProposals {
  2653  		prop := voteClosed.Proposal()
  2654  		switch {
  2655  		case voteClosed.IsNewMarket(): // can be spot or futures new market
  2656  			// Here we panic in both case as we should never reach a point
  2657  			// where we try to Reject or start the opening auction of a
  2658  			// non-existing market or any other error would be quite critical
  2659  			// anyway...
  2660  			nm := voteClosed.NewMarket()
  2661  			if nm.Rejected() {
  2662  				// RejectMarket can return an error if the proposed successor market was rejected because its parent
  2663  				// was already rejected
  2664  				if err := app.exec.RejectMarket(ctx, prop.ID); err != nil && !prop.IsSuccessorMarket() {
  2665  					app.log.Panic("unable to reject market",
  2666  						logging.String("market-id", prop.ID),
  2667  						logging.Error(err))
  2668  				}
  2669  			} else if nm.StartAuction() {
  2670  				err := app.exec.StartOpeningAuction(ctx, prop.ID)
  2671  				if err != nil {
  2672  					if prop.IsSuccessorMarket() {
  2673  						app.log.Warn("parent market was already succeeded, market rejected",
  2674  							logging.String("market-id", prop.ID),
  2675  						)
  2676  						prop.FailWithErr(types.ProposalErrorInvalidSuccessorMarket, ErrParentMarketAlreadySucceeded)
  2677  					} else {
  2678  						app.log.Panic("unable to start market opening auction",
  2679  							logging.String("market-id", prop.ID),
  2680  							logging.Error(err))
  2681  					}
  2682  				}
  2683  			}
  2684  		}
  2685  	}
  2686  
  2687  	for _, toEnact := range toEnactProposals {
  2688  		prop := toEnact.Proposal()
  2689  		switch {
  2690  		case prop.IsSuccessorMarket():
  2691  			app.enactSuccessorMarket(ctx, prop)
  2692  		case toEnact.IsNewMarket():
  2693  			app.enactMarket(ctx, prop)
  2694  		case toEnact.IsNewSpotMarket():
  2695  			app.enactSpotMarket(ctx, prop)
  2696  		case toEnact.IsNewAsset():
  2697  			app.enactAsset(ctx, prop, toEnact.NewAsset())
  2698  		case toEnact.IsUpdateAsset():
  2699  			app.enactAssetUpdate(ctx, prop, toEnact.UpdateAsset())
  2700  		case toEnact.IsUpdateMarket():
  2701  			app.enactUpdateMarket(ctx, prop, toEnact.UpdateMarket())
  2702  		case toEnact.IsUpdateSpotMarket():
  2703  			app.enactUpdateSpotMarket(ctx, prop, toEnact.UpdateSpotMarket())
  2704  		case toEnact.IsUpdateNetworkParameter():
  2705  			app.enactNetworkParameterUpdate(ctx, prop, toEnact.UpdateNetworkParameter())
  2706  		case toEnact.IsFreeform():
  2707  			app.enactFreeform(ctx, prop)
  2708  		case toEnact.IsNewTransfer():
  2709  			app.enactNewTransfer(ctx, prop)
  2710  		case toEnact.IsCancelTransfer():
  2711  			app.enactCancelTransfer(ctx, prop)
  2712  		case toEnact.IsMarketStateUpdate():
  2713  			app.enactMarketStateUpdate(ctx, prop)
  2714  		case toEnact.IsReferralProgramUpdate():
  2715  			prop.State = types.ProposalStateEnacted
  2716  			app.referralProgram.UpdateProgram(toEnact.ReferralProgramChanges())
  2717  		case toEnact.IsVolumeDiscountProgramUpdate():
  2718  			prop.State = types.ProposalStateEnacted
  2719  			app.volumeDiscountProgram.UpdateProgram(toEnact.VolumeDiscountProgramUpdate())
  2720  		case toEnact.IsVolumeRebateProgramUpdate():
  2721  			prop.State = types.ProposalStateEnacted
  2722  			app.volumeRebateProgram.UpdateProgram(toEnact.VolumeRebateProgramUpdate())
  2723  		case toEnact.IsAutomatedPurchase():
  2724  			app.enactNewAutomatePurahce(ctx, prop)
  2725  		default:
  2726  			app.log.Error("unknown proposal cannot be enacted", logging.ProposalID(prop.ID))
  2727  			prop.FailUnexpectedly(fmt.Errorf("unknown proposal \"%s\" cannot be enacted", prop.ID))
  2728  		}
  2729  
  2730  		app.gov.FinaliseEnactment(ctx, prop)
  2731  	}
  2732  }
  2733  
  2734  func (app *App) enactAsset(ctx context.Context, prop *types.Proposal, _ *types.Asset) {
  2735  	prop.State = types.ProposalStateEnacted
  2736  	asset, err := app.assets.Get(prop.ID)
  2737  	if err != nil {
  2738  		app.log.Panic("couldn't retrieve asset when enacting asset update",
  2739  			logging.AssetID(prop.ID),
  2740  			logging.Error(err))
  2741  	}
  2742  
  2743  	// if this is a builtin asset nothing needs to be done, just start the asset
  2744  	// straight away
  2745  	if asset.IsBuiltinAsset() {
  2746  		err = app.banking.EnableBuiltinAsset(ctx, asset.Type().ID)
  2747  		if err != nil {
  2748  			app.log.Panic("unable to get builtin asset enabled",
  2749  				logging.AssetID(prop.ID),
  2750  				logging.Error(err))
  2751  		}
  2752  		return
  2753  	}
  2754  	app.assets.EnactPendingAsset(prop.ID)
  2755  }
  2756  
  2757  func (app *App) enactAssetUpdate(_ context.Context, prop *types.Proposal, updatedAsset *types.Asset) {
  2758  	asset, err := app.assets.Get(updatedAsset.ID)
  2759  	if err != nil {
  2760  		app.log.Panic("couldn't retrieve asset when enacting asset update",
  2761  			logging.AssetID(updatedAsset.ID),
  2762  			logging.Error(err))
  2763  	}
  2764  
  2765  	var signature []byte
  2766  	if app.top.IsValidator() {
  2767  		switch {
  2768  		case asset.IsERC20():
  2769  			// need to remove IDs
  2770  			nonce, err := num.UintFromHex("0x" + strings.TrimLeft(prop.ID, "0"))
  2771  			if err != nil {
  2772  				app.log.Panic("couldn't generate nonce from proposal ID",
  2773  					logging.AssetID(updatedAsset.ID),
  2774  					logging.ProposalID(prop.ID),
  2775  					logging.Error(err),
  2776  				)
  2777  			}
  2778  			asset, _ := asset.ERC20()
  2779  			_, signature, err = asset.SignSetAssetLimits(
  2780  				nonce,
  2781  				updatedAsset.Details.GetERC20().LifetimeLimit.Clone(),
  2782  				updatedAsset.Details.GetERC20().WithdrawThreshold.Clone(),
  2783  			)
  2784  			if err != nil {
  2785  				app.log.Panic("couldn't to sign transaction to set asset limits, is the node properly configured as a validator?",
  2786  					logging.AssetID(updatedAsset.ID),
  2787  					logging.Error(err))
  2788  			}
  2789  		}
  2790  	}
  2791  
  2792  	prop.State = types.ProposalStateEnacted
  2793  
  2794  	if err := app.assets.StageAssetUpdate(updatedAsset); err != nil {
  2795  		app.log.Panic("couldn't stage the asset update",
  2796  			logging.Error(err),
  2797  			logging.AssetID(updatedAsset.ID),
  2798  		)
  2799  	}
  2800  
  2801  	// then instruct the notary to start getting signature from validators
  2802  	app.notary.StartAggregate(prop.ID, types.NodeSignatureKindAssetUpdate, signature)
  2803  }
  2804  
  2805  func (app *App) enactSuccessorMarket(ctx context.Context, prop *types.Proposal) {
  2806  	// @TODO remove parent market (or flag as ready to be removed)
  2807  	// transfer the insurance pool balance and ELS state
  2808  	// then finally:
  2809  	successor := prop.ID
  2810  	nm := prop.NewMarket()
  2811  	parent := nm.Changes.Successor.ParentID
  2812  	if err := app.exec.SucceedMarket(ctx, successor, parent); err != nil {
  2813  		prop.State = types.ProposalStateFailed
  2814  		prop.ErrorDetails = err.Error()
  2815  		return
  2816  	}
  2817  	prop.State = types.ProposalStateEnacted
  2818  }
  2819  
  2820  func (app *App) enactMarket(_ context.Context, prop *types.Proposal) {
  2821  	prop.State = types.ProposalStateEnacted
  2822  
  2823  	// TODO: add checks for end of auction in here
  2824  }
  2825  
  2826  func (app *App) enactSpotMarket(_ context.Context, prop *types.Proposal) {
  2827  	prop.State = types.ProposalStateEnacted
  2828  }
  2829  
  2830  func (app *App) enactFreeform(_ context.Context, prop *types.Proposal) {
  2831  	// There is nothing to enact in a freeform proposal so we just set the state
  2832  	prop.State = types.ProposalStateEnacted
  2833  }
  2834  
  2835  func (app *App) enactNewTransfer(ctx context.Context, prop *types.Proposal) {
  2836  	prop.State = types.ProposalStateEnacted
  2837  	proposal := prop.Terms.GetNewTransfer().Changes
  2838  
  2839  	if err := app.banking.VerifyGovernanceTransfer(proposal); err != nil {
  2840  		app.log.Error("failed to enact governance transfer - invalid transfer", logging.String("proposal", prop.ID), logging.String("error", err.Error()))
  2841  		prop.FailWithErr(types.ProporsalErrorInvalidGovernanceTransfer, err)
  2842  		return
  2843  	}
  2844  
  2845  	_ = app.banking.NewGovernanceTransfer(ctx, prop.ID, prop.Reference, proposal)
  2846  }
  2847  
  2848  func (app *App) enactNewAutomatePurahce(ctx context.Context, prop *types.Proposal) {
  2849  	prop.State = types.ProposalStateEnacted
  2850  	proposal := prop.Terms.GetAutomatedPurchase().Changes
  2851  	if err := app.exec.NewProtocolAutomatedPurchase(ctx, prop.ID, proposal); err != nil {
  2852  		app.log.Error("failed to enact governance automated purchase", logging.String("proposal", prop.ID), logging.String("error", err.Error()))
  2853  		prop.FailWithErr(types.ProporsalErrorFailedGovernanceTransferCancel, err)
  2854  	}
  2855  }
  2856  
  2857  func (app *App) enactCancelTransfer(ctx context.Context, prop *types.Proposal) {
  2858  	prop.State = types.ProposalStateEnacted
  2859  	transferID := prop.Terms.GetCancelTransfer().Changes.TransferID
  2860  	if err := app.banking.VerifyCancelGovernanceTransfer(transferID); err != nil {
  2861  		app.log.Error("failed to enact governance transfer cancellation - invalid transfer cancellation", logging.String("proposal", prop.ID), logging.String("error", err.Error()))
  2862  		prop.FailWithErr(types.ProporsalErrorFailedGovernanceTransferCancel, err)
  2863  		return
  2864  	}
  2865  	if err := app.banking.CancelGovTransfer(ctx, transferID); err != nil {
  2866  		app.log.Error("failed to enact governance transfer cancellation", logging.String("proposal", prop.ID), logging.String("error", err.Error()))
  2867  		prop.FailWithErr(types.ProporsalErrorFailedGovernanceTransferCancel, err)
  2868  		return
  2869  	}
  2870  }
  2871  
  2872  func (app *App) enactMarketStateUpdate(ctx context.Context, prop *types.Proposal) {
  2873  	prop.State = types.ProposalStateEnacted
  2874  	changes := prop.Terms.GetMarketStateUpdate().Changes
  2875  	if err := app.exec.VerifyUpdateMarketState(changes); err != nil {
  2876  		app.log.Error("failed to enact governance market state update", logging.String("proposal", prop.ID), logging.String("error", err.Error()))
  2877  		prop.FailWithErr(types.ProposalErrorInvalidStateUpdate, err)
  2878  		return
  2879  	}
  2880  	if err := app.exec.UpdateMarketState(ctx, changes); err != nil {
  2881  		app.log.Error("failed to enact governance market state update", logging.String("proposal", prop.ID), logging.String("error", err.Error()))
  2882  		prop.FailWithErr(types.ProposalErrorInvalidStateUpdate, err)
  2883  	}
  2884  }
  2885  
  2886  func (app *App) enactNetworkParameterUpdate(ctx context.Context, prop *types.Proposal, np *types.NetworkParameter) {
  2887  	prop.State = types.ProposalStateEnacted
  2888  	if err := app.netp.Update(ctx, np.Key, np.Value); err != nil {
  2889  		prop.FailUnexpectedly(err)
  2890  		app.log.Error("failed to update network parameters",
  2891  			logging.ProposalID(prop.ID),
  2892  			logging.Error(err))
  2893  		return
  2894  	}
  2895  
  2896  	// we call the dispatch updates here then
  2897  	// just so we are sure all netparams updates are dispatches one by one
  2898  	// in a deterministic order
  2899  	app.netp.DispatchChanges(ctx)
  2900  }
  2901  
  2902  func (app *App) DeliverDelegate(ctx context.Context, tx abci.Tx) (err error) {
  2903  	ce := &commandspb.DelegateSubmission{}
  2904  	if err := tx.Unmarshal(ce); err != nil {
  2905  		return err
  2906  	}
  2907  
  2908  	amount, overflowed := num.UintFromString(ce.Amount, 10)
  2909  	if overflowed {
  2910  		return errors.New("amount is not a valid base 10 number")
  2911  	}
  2912  
  2913  	return app.delegation.Delegate(ctx, tx.Party(), ce.NodeId, amount)
  2914  }
  2915  
  2916  func (app *App) DeliverUndelegate(ctx context.Context, tx abci.Tx) (err error) {
  2917  	ce := &commandspb.UndelegateSubmission{}
  2918  	if err := tx.Unmarshal(ce); err != nil {
  2919  		return err
  2920  	}
  2921  
  2922  	switch ce.Method {
  2923  	case commandspb.UndelegateSubmission_METHOD_NOW:
  2924  		amount, overflowed := num.UintFromString(ce.Amount, 10)
  2925  		if overflowed {
  2926  			return errors.New("amount is not a valid base 10 number")
  2927  		}
  2928  		return app.delegation.UndelegateNow(ctx, tx.Party(), ce.NodeId, amount)
  2929  	case commandspb.UndelegateSubmission_METHOD_AT_END_OF_EPOCH:
  2930  		amount, overflowed := num.UintFromString(ce.Amount, 10)
  2931  		if overflowed {
  2932  			return errors.New("amount is not a valid base 10 number")
  2933  		}
  2934  		return app.delegation.UndelegateAtEndOfEpoch(ctx, tx.Party(), ce.NodeId, amount)
  2935  	default:
  2936  		return errors.New("unimplemented")
  2937  	}
  2938  }
  2939  
  2940  func (app *App) DeliverKeyRotateSubmission(ctx context.Context, tx abci.Tx) error {
  2941  	kr := &commandspb.KeyRotateSubmission{}
  2942  	if err := tx.Unmarshal(kr); err != nil {
  2943  		return err
  2944  	}
  2945  
  2946  	currentBlockHeight, _ := vgcontext.BlockHeightFromContext(ctx)
  2947  
  2948  	return app.top.AddKeyRotate(
  2949  		ctx,
  2950  		tx.PubKeyHex(),
  2951  		currentBlockHeight,
  2952  		kr,
  2953  	)
  2954  }
  2955  
  2956  func (app *App) DeliverStateVarProposal(ctx context.Context, tx abci.Tx) error {
  2957  	proposal := &commandspb.StateVariableProposal{}
  2958  	if err := tx.Unmarshal(proposal); err != nil {
  2959  		app.log.Error("failed to unmarshal StateVariableProposal", logging.Error(err), logging.String("pub-key", tx.PubKeyHex()))
  2960  		return err
  2961  	}
  2962  
  2963  	stateVarID := proposal.Proposal.StateVarId
  2964  	node := tx.PubKeyHex()
  2965  	eventID := proposal.Proposal.EventId
  2966  	bundle, err := statevar.KeyValueBundleFromProto(proposal.Proposal.Kvb)
  2967  	if err != nil {
  2968  		app.log.Error("failed to propose value", logging.Error(err))
  2969  		return err
  2970  	}
  2971  	return app.stateVar.ProposedValueReceived(ctx, stateVarID, node, eventID, bundle)
  2972  }
  2973  
  2974  func (app *App) enactUpdateMarket(ctx context.Context, prop *types.Proposal, market *types.Market) {
  2975  	if err := app.exec.UpdateMarket(ctx, market); err != nil {
  2976  		prop.FailUnexpectedly(err)
  2977  		app.log.Error("failed to update market",
  2978  			logging.ProposalID(prop.ID),
  2979  			logging.Error(err))
  2980  		return
  2981  	}
  2982  	prop.State = types.ProposalStateEnacted
  2983  }
  2984  
  2985  func (app *App) enactUpdateSpotMarket(ctx context.Context, prop *types.Proposal, market *types.Market) {
  2986  	if err := app.exec.UpdateSpotMarket(ctx, market); err != nil {
  2987  		prop.FailUnexpectedly(err)
  2988  		app.log.Error("failed to update spot market",
  2989  			logging.ProposalID(prop.ID),
  2990  			logging.Error(err))
  2991  		return
  2992  	}
  2993  	prop.State = types.ProposalStateEnacted
  2994  }
  2995  
  2996  func (app *App) DeliverEthereumKeyRotateSubmission(ctx context.Context, tx abci.Tx) error {
  2997  	kr := &commandspb.EthereumKeyRotateSubmission{}
  2998  	if err := tx.Unmarshal(kr); err != nil {
  2999  		return err
  3000  	}
  3001  
  3002  	return app.top.ProcessEthereumKeyRotation(
  3003  		ctx,
  3004  		tx.PubKeyHex(),
  3005  		kr,
  3006  		signatures.VerifyEthereumSignature,
  3007  	)
  3008  }
  3009  
  3010  func (app *App) wrapTx(tx abci.Tx, rawTx []byte, insertionOrder int) (*TxWrapper, error) {
  3011  	priority := app.getPriority(tx)
  3012  	gasWanted, err := app.getGasWanted(tx)
  3013  	if err != nil {
  3014  		return nil, err
  3015  	}
  3016  
  3017  	return &TxWrapper{
  3018  		tx:        tx,
  3019  		timeIndex: insertionOrder,
  3020  		raw:       rawTx,
  3021  		priority:  priority,
  3022  		gasWanted: gasWanted,
  3023  	}, nil
  3024  }
  3025  
  3026  func (app *App) getPriority(tx abci.Tx) uint64 {
  3027  	return app.gastimator.GetPriority(tx)
  3028  }
  3029  
  3030  func (app *App) getGasWanted(tx abci.Tx) (uint64, error) {
  3031  	return app.gastimator.CalcGasWantedForTx(tx)
  3032  }
  3033  
  3034  func (app *App) getMaxGas() uint64 {
  3035  	return app.gastimator.maxGas
  3036  }
  3037  
  3038  func (app *App) UpdateMarginMode(ctx context.Context, tx abci.Tx) error {
  3039  	var err error
  3040  	params := &commandspb.UpdateMarginMode{}
  3041  	if err = tx.Unmarshal(params); err != nil {
  3042  		return fmt.Errorf("could not deserialize UpdateMarginMode command: %w", err)
  3043  	}
  3044  	marginFactor := num.DecimalZero()
  3045  	if params.MarginFactor != nil && len(*params.MarginFactor) > 0 {
  3046  		marginFactor, err = num.DecimalFromString(*params.MarginFactor)
  3047  		if err != nil {
  3048  			return err
  3049  		}
  3050  	}
  3051  	return app.exec.UpdateMarginMode(ctx, tx.Party(), params.MarketId, types.MarginMode(params.Mode), marginFactor)
  3052  }
  3053  
  3054  func (app *App) DeliverSubmitAMM(ctx context.Context, tx abci.Tx, deterministicID string) error {
  3055  	params := &commandspb.SubmitAMM{}
  3056  	if err := tx.Unmarshal(params); err != nil {
  3057  		return fmt.Errorf("could not deserialize SubmitAMM command: %w", err)
  3058  	}
  3059  
  3060  	submit := types.NewSubmitAMMFromProto(params, tx.Party())
  3061  	return app.exec.SubmitAMM(ctx, submit, deterministicID)
  3062  }
  3063  
  3064  func (app *App) DeliverAmendAMM(ctx context.Context, tx abci.Tx, deterministicID string) error {
  3065  	params := &commandspb.AmendAMM{}
  3066  	if err := tx.Unmarshal(params); err != nil {
  3067  		return fmt.Errorf("could not deserialize AmendAMM command: %w", err)
  3068  	}
  3069  
  3070  	amend := types.NewAmendAMMFromProto(params, tx.Party())
  3071  	return app.exec.AmendAMM(ctx, amend, deterministicID)
  3072  }
  3073  
  3074  func (app *App) DeliverCancelAMM(ctx context.Context, tx abci.Tx, deterministicID string) error {
  3075  	params := &commandspb.CancelAMM{}
  3076  	if err := tx.Unmarshal(params); err != nil {
  3077  		return fmt.Errorf("could not deserialize CancelAMM command: %w", err)
  3078  	}
  3079  
  3080  	cancel := types.NewCancelAMMFromProto(params, tx.Party())
  3081  	return app.exec.CancelAMM(ctx, cancel, deterministicID)
  3082  }
  3083  
  3084  func (app *App) CreateReferralSet(ctx context.Context, tx abci.Tx, deterministicID string) error {
  3085  	params := &commandspb.CreateReferralSet{}
  3086  	if err := tx.Unmarshal(params); err != nil {
  3087  		return fmt.Errorf("could not deserialize CreateReferralSet command: %w", err)
  3088  	}
  3089  
  3090  	if !params.DoNotCreateReferralSet {
  3091  		if err := app.referralProgram.CreateReferralSet(ctx, types.PartyID(tx.Party()), types.ReferralSetID(deterministicID)); err != nil {
  3092  			return err
  3093  		}
  3094  	}
  3095  
  3096  	if params.IsTeam {
  3097  		return app.teamsEngine.CreateTeam(ctx, types.PartyID(tx.Party()), types.TeamID(deterministicID), params.Team)
  3098  	}
  3099  
  3100  	return nil
  3101  }
  3102  
  3103  // UpdateReferralSet this is effectively Update team, but also served to create
  3104  // a team for an existing referral set...
  3105  func (app *App) UpdateReferralSet(ctx context.Context, tx abci.Tx) error {
  3106  	params := &commandspb.UpdateReferralSet{}
  3107  	if err := tx.Unmarshal(params); err != nil {
  3108  		return fmt.Errorf("could not deserialize UpdateReferralSet command: %w", err)
  3109  	}
  3110  
  3111  	// Is this relevant at all now? With anyone able to create a team, this verification should not matter.
  3112  	//
  3113  	// if err := app.referralProgram.PartyOwnsReferralSet(types.PartyID(tx.Party()), types.ReferralSetID(params.Id)); err != nil {
  3114  	//     return fmt.Errorf("cannot update referral set: %w", err)
  3115  	// }
  3116  
  3117  	// ultimately this has just become a createOrUpdateTeam.
  3118  	if params.IsTeam {
  3119  		teamID := types.TeamID(params.Id)
  3120  		if app.teamsEngine.TeamExists(teamID) {
  3121  			return app.teamsEngine.UpdateTeam(ctx, types.PartyID(tx.Party()), teamID, params.Team)
  3122  		}
  3123  
  3124  		return app.teamsEngine.CreateTeam(ctx, types.PartyID(tx.Party()), teamID, &commandspb.CreateReferralSet_Team{
  3125  			Name:      ptr.UnBox(params.Team.Name),
  3126  			AvatarUrl: params.Team.AvatarUrl,
  3127  			TeamUrl:   params.Team.TeamUrl,
  3128  			Closed:    ptr.UnBox(params.Team.Closed),
  3129  		})
  3130  	}
  3131  
  3132  	return nil
  3133  }
  3134  
  3135  func (app *App) ApplyReferralCode(ctx context.Context, tx abci.Tx) error {
  3136  	params := &commandspb.ApplyReferralCode{}
  3137  	if err := tx.Unmarshal(params); err != nil {
  3138  		return fmt.Errorf("could not deserialize ApplyReferralCode command: %w", err)
  3139  	}
  3140  
  3141  	partyID := types.PartyID(tx.Party())
  3142  	err := app.referralProgram.ApplyReferralCode(ctx, partyID, types.ReferralSetID(params.Id))
  3143  	if err != nil {
  3144  		return fmt.Errorf("could not apply the referral code: %w", err)
  3145  	}
  3146  
  3147  	if !params.DoNotJoinTeam {
  3148  		teamID := types.TeamID(params.Id)
  3149  		joinTeam := &commandspb.JoinTeam{
  3150  			Id: params.Id,
  3151  		}
  3152  		err = app.teamsEngine.JoinTeam(ctx, partyID, joinTeam)
  3153  		// This is ok as well, as not all referral sets are teams as well.
  3154  		if err != nil && err.Error() != teams.ErrNoTeamMatchesID(teamID).Error() {
  3155  			return fmt.Errorf("couldn't join team: %w", err)
  3156  		}
  3157  	}
  3158  
  3159  	return nil
  3160  }
  3161  
  3162  func (app *App) JoinTeam(ctx context.Context, tx abci.Tx) error {
  3163  	params := &commandspb.JoinTeam{}
  3164  	if err := tx.Unmarshal(params); err != nil {
  3165  		return fmt.Errorf("could not deserialize JoinTeam command: %w", err)
  3166  	}
  3167  
  3168  	partyID := types.PartyID(tx.Party())
  3169  	err := app.teamsEngine.JoinTeam(ctx, partyID, params)
  3170  	if err != nil {
  3171  		return fmt.Errorf("couldn't join team: %w", err)
  3172  	}
  3173  
  3174  	return nil
  3175  }
  3176  
  3177  func (app *App) handleDelayedTransactionWrapper(ctx context.Context, tx abci.Tx) error {
  3178  	txs := &commandspb.DelayedTransactionsWrapper{}
  3179  	if err := tx.Unmarshal(txs); err != nil {
  3180  		return fmt.Errorf("could not deserialize DelayedTransactionsWrapper command: %w", err)
  3181  	}
  3182  	app.txCache.SetRawTxs(txs.Transactions, txs.Height)
  3183  	return nil
  3184  }
  3185  
  3186  func (app *App) UpdatePartyProfile(ctx context.Context, tx abci.Tx) error {
  3187  	params := &commandspb.UpdatePartyProfile{}
  3188  	if err := tx.Unmarshal(params); err != nil {
  3189  		return fmt.Errorf("could not deserialize UpdatePartyProfile command: %w", err)
  3190  	}
  3191  
  3192  	err := app.partiesEngine.CheckSufficientBalanceToUpdateProfile(
  3193  		types.PartyID(tx.Party()),
  3194  		app.balanceChecker.GetPartyBalance(tx.Party()),
  3195  	)
  3196  	if err != nil {
  3197  		return err
  3198  	}
  3199  
  3200  	partyID := types.PartyID(tx.Party())
  3201  	err = app.partiesEngine.UpdateProfile(ctx, partyID, params)
  3202  	if err != nil {
  3203  		return fmt.Errorf("couldn't update profile: %w", err)
  3204  	}
  3205  
  3206  	return nil
  3207  }
  3208  
  3209  func (app *App) OnBlockchainPrimaryEthereumConfigUpdate(_ context.Context, conf any) error {
  3210  	cfg, err := types.EthereumConfigFromUntypedProto(conf)
  3211  	if err != nil {
  3212  		return err
  3213  	}
  3214  	cID, err := strconv.ParseUint(cfg.ChainID(), 10, 64)
  3215  	if err != nil {
  3216  		return err
  3217  	}
  3218  	app.primaryChainID = cID
  3219  	_ = app.exec.OnChainIDUpdate(cID)
  3220  	return app.gov.OnChainIDUpdate(cID)
  3221  }
  3222  
  3223  func (app *App) OnBlockchainEVMChainConfigUpdate(_ context.Context, conf any) error {
  3224  	cfg, err := types.EVMChainConfigFromUntypedProto(conf)
  3225  	if err != nil {
  3226  		return err
  3227  	}
  3228  	cID, err := strconv.ParseUint(cfg.Configs[0].ChainID(), 10, 64)
  3229  	if err != nil {
  3230  		return err
  3231  	}
  3232  	app.secondaryChainID = cID
  3233  	return nil
  3234  }