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 }