github.com/ava-labs/avalanchego@v1.11.11/vms/platformvm/txs/executor/standard_tx_executor.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package executor 5 6 import ( 7 "context" 8 "errors" 9 "fmt" 10 "time" 11 12 "go.uber.org/zap" 13 14 "github.com/ava-labs/avalanchego/chains/atomic" 15 "github.com/ava-labs/avalanchego/ids" 16 "github.com/ava-labs/avalanchego/utils/constants" 17 "github.com/ava-labs/avalanchego/utils/set" 18 "github.com/ava-labs/avalanchego/vms/components/avax" 19 "github.com/ava-labs/avalanchego/vms/components/verify" 20 "github.com/ava-labs/avalanchego/vms/platformvm/state" 21 "github.com/ava-labs/avalanchego/vms/platformvm/txs" 22 "github.com/ava-labs/avalanchego/vms/platformvm/txs/fee" 23 ) 24 25 var ( 26 _ txs.Visitor = (*StandardTxExecutor)(nil) 27 28 errEmptyNodeID = errors.New("validator nodeID cannot be empty") 29 errMaxStakeDurationTooLarge = errors.New("max stake duration must be less than or equal to the global max stake duration") 30 errMissingStartTimePreDurango = errors.New("staker transactions must have a StartTime pre-Durango") 31 errTransformSubnetTxPostEtna = errors.New("TransformSubnetTx is not permitted post-Etna") 32 ) 33 34 type StandardTxExecutor struct { 35 // inputs, to be filled before visitor methods are called 36 *Backend 37 State state.Diff // state is expected to be modified 38 FeeCalculator fee.Calculator 39 Tx *txs.Tx 40 41 // outputs of visitor execution 42 OnAccept func() // may be nil 43 Inputs set.Set[ids.ID] 44 AtomicRequests map[ids.ID]*atomic.Requests // may be nil 45 } 46 47 func (*StandardTxExecutor) AdvanceTimeTx(*txs.AdvanceTimeTx) error { 48 return ErrWrongTxType 49 } 50 51 func (*StandardTxExecutor) RewardValidatorTx(*txs.RewardValidatorTx) error { 52 return ErrWrongTxType 53 } 54 55 func (e *StandardTxExecutor) CreateChainTx(tx *txs.CreateChainTx) error { 56 if err := e.Tx.SyntacticVerify(e.Ctx); err != nil { 57 return err 58 } 59 60 var ( 61 currentTimestamp = e.State.GetTimestamp() 62 isDurangoActive = e.Config.UpgradeConfig.IsDurangoActivated(currentTimestamp) 63 ) 64 if err := avax.VerifyMemoFieldLength(tx.Memo, isDurangoActive); err != nil { 65 return err 66 } 67 68 baseTxCreds, err := verifyPoASubnetAuthorization(e.Backend, e.State, e.Tx, tx.SubnetID, tx.SubnetAuth) 69 if err != nil { 70 return err 71 } 72 73 // Verify the flowcheck 74 fee, err := e.FeeCalculator.CalculateFee(tx) 75 if err != nil { 76 return err 77 } 78 if err := e.FlowChecker.VerifySpend( 79 tx, 80 e.State, 81 tx.Ins, 82 tx.Outs, 83 baseTxCreds, 84 map[ids.ID]uint64{ 85 e.Ctx.AVAXAssetID: fee, 86 }, 87 ); err != nil { 88 return err 89 } 90 91 txID := e.Tx.ID() 92 93 // Consume the UTXOS 94 avax.Consume(e.State, tx.Ins) 95 // Produce the UTXOS 96 avax.Produce(e.State, txID, tx.Outs) 97 // Add the new chain to the database 98 e.State.AddChain(e.Tx) 99 100 // If this proposal is committed and this node is a member of the subnet 101 // that validates the blockchain, create the blockchain 102 e.OnAccept = func() { 103 e.Config.CreateChain(txID, tx) 104 } 105 return nil 106 } 107 108 func (e *StandardTxExecutor) CreateSubnetTx(tx *txs.CreateSubnetTx) error { 109 // Make sure this transaction is well formed. 110 if err := e.Tx.SyntacticVerify(e.Ctx); err != nil { 111 return err 112 } 113 114 var ( 115 currentTimestamp = e.State.GetTimestamp() 116 isDurangoActive = e.Config.UpgradeConfig.IsDurangoActivated(currentTimestamp) 117 ) 118 if err := avax.VerifyMemoFieldLength(tx.Memo, isDurangoActive); err != nil { 119 return err 120 } 121 122 // Verify the flowcheck 123 fee, err := e.FeeCalculator.CalculateFee(tx) 124 if err != nil { 125 return err 126 } 127 if err := e.FlowChecker.VerifySpend( 128 tx, 129 e.State, 130 tx.Ins, 131 tx.Outs, 132 e.Tx.Creds, 133 map[ids.ID]uint64{ 134 e.Ctx.AVAXAssetID: fee, 135 }, 136 ); err != nil { 137 return err 138 } 139 140 txID := e.Tx.ID() 141 142 // Consume the UTXOS 143 avax.Consume(e.State, tx.Ins) 144 // Produce the UTXOS 145 avax.Produce(e.State, txID, tx.Outs) 146 // Add the new subnet to the database 147 e.State.AddSubnet(txID) 148 e.State.SetSubnetOwner(txID, tx.Owner) 149 return nil 150 } 151 152 func (e *StandardTxExecutor) ImportTx(tx *txs.ImportTx) error { 153 if err := e.Tx.SyntacticVerify(e.Ctx); err != nil { 154 return err 155 } 156 157 var ( 158 currentTimestamp = e.State.GetTimestamp() 159 isDurangoActive = e.Config.UpgradeConfig.IsDurangoActivated(currentTimestamp) 160 ) 161 if err := avax.VerifyMemoFieldLength(tx.Memo, isDurangoActive); err != nil { 162 return err 163 } 164 165 e.Inputs = set.NewSet[ids.ID](len(tx.ImportedInputs)) 166 utxoIDs := make([][]byte, len(tx.ImportedInputs)) 167 for i, in := range tx.ImportedInputs { 168 utxoID := in.UTXOID.InputID() 169 170 e.Inputs.Add(utxoID) 171 utxoIDs[i] = utxoID[:] 172 } 173 174 // Skip verification of the shared memory inputs if the other primary 175 // network chains are not guaranteed to be up-to-date. 176 if e.Bootstrapped.Get() && !e.Config.PartialSyncPrimaryNetwork { 177 if err := verify.SameSubnet(context.TODO(), e.Ctx, tx.SourceChain); err != nil { 178 return err 179 } 180 181 allUTXOBytes, err := e.Ctx.SharedMemory.Get(tx.SourceChain, utxoIDs) 182 if err != nil { 183 return fmt.Errorf("failed to get shared memory: %w", err) 184 } 185 186 utxos := make([]*avax.UTXO, len(tx.Ins)+len(tx.ImportedInputs)) 187 for index, input := range tx.Ins { 188 utxo, err := e.State.GetUTXO(input.InputID()) 189 if err != nil { 190 return fmt.Errorf("failed to get UTXO %s: %w", &input.UTXOID, err) 191 } 192 utxos[index] = utxo 193 } 194 for i, utxoBytes := range allUTXOBytes { 195 utxo := &avax.UTXO{} 196 if _, err := txs.Codec.Unmarshal(utxoBytes, utxo); err != nil { 197 return fmt.Errorf("failed to unmarshal UTXO: %w", err) 198 } 199 utxos[i+len(tx.Ins)] = utxo 200 } 201 202 ins := make([]*avax.TransferableInput, len(tx.Ins)+len(tx.ImportedInputs)) 203 copy(ins, tx.Ins) 204 copy(ins[len(tx.Ins):], tx.ImportedInputs) 205 206 // Verify the flowcheck 207 fee, err := e.FeeCalculator.CalculateFee(tx) 208 if err != nil { 209 return err 210 } 211 if err := e.FlowChecker.VerifySpendUTXOs( 212 tx, 213 utxos, 214 ins, 215 tx.Outs, 216 e.Tx.Creds, 217 map[ids.ID]uint64{ 218 e.Ctx.AVAXAssetID: fee, 219 }, 220 ); err != nil { 221 return err 222 } 223 } 224 225 txID := e.Tx.ID() 226 227 // Consume the UTXOS 228 avax.Consume(e.State, tx.Ins) 229 // Produce the UTXOS 230 avax.Produce(e.State, txID, tx.Outs) 231 232 // Note: We apply atomic requests even if we are not verifying atomic 233 // requests to ensure the shared state will be correct if we later start 234 // verifying the requests. 235 e.AtomicRequests = map[ids.ID]*atomic.Requests{ 236 tx.SourceChain: { 237 RemoveRequests: utxoIDs, 238 }, 239 } 240 return nil 241 } 242 243 func (e *StandardTxExecutor) ExportTx(tx *txs.ExportTx) error { 244 if err := e.Tx.SyntacticVerify(e.Ctx); err != nil { 245 return err 246 } 247 248 var ( 249 currentTimestamp = e.State.GetTimestamp() 250 isDurangoActive = e.Config.UpgradeConfig.IsDurangoActivated(currentTimestamp) 251 ) 252 if err := avax.VerifyMemoFieldLength(tx.Memo, isDurangoActive); err != nil { 253 return err 254 } 255 256 outs := make([]*avax.TransferableOutput, len(tx.Outs)+len(tx.ExportedOutputs)) 257 copy(outs, tx.Outs) 258 copy(outs[len(tx.Outs):], tx.ExportedOutputs) 259 260 if e.Bootstrapped.Get() { 261 if err := verify.SameSubnet(context.TODO(), e.Ctx, tx.DestinationChain); err != nil { 262 return err 263 } 264 } 265 266 // Verify the flowcheck 267 fee, err := e.FeeCalculator.CalculateFee(tx) 268 if err != nil { 269 return err 270 } 271 if err := e.FlowChecker.VerifySpend( 272 tx, 273 e.State, 274 tx.Ins, 275 outs, 276 e.Tx.Creds, 277 map[ids.ID]uint64{ 278 e.Ctx.AVAXAssetID: fee, 279 }, 280 ); err != nil { 281 return fmt.Errorf("failed verifySpend: %w", err) 282 } 283 284 txID := e.Tx.ID() 285 286 // Consume the UTXOS 287 avax.Consume(e.State, tx.Ins) 288 // Produce the UTXOS 289 avax.Produce(e.State, txID, tx.Outs) 290 291 // Note: We apply atomic requests even if we are not verifying atomic 292 // requests to ensure the shared state will be correct if we later start 293 // verifying the requests. 294 elems := make([]*atomic.Element, len(tx.ExportedOutputs)) 295 for i, out := range tx.ExportedOutputs { 296 utxo := &avax.UTXO{ 297 UTXOID: avax.UTXOID{ 298 TxID: txID, 299 OutputIndex: uint32(len(tx.Outs) + i), 300 }, 301 Asset: avax.Asset{ID: out.AssetID()}, 302 Out: out.Out, 303 } 304 305 utxoBytes, err := txs.Codec.Marshal(txs.CodecVersion, utxo) 306 if err != nil { 307 return fmt.Errorf("failed to marshal UTXO: %w", err) 308 } 309 utxoID := utxo.InputID() 310 elem := &atomic.Element{ 311 Key: utxoID[:], 312 Value: utxoBytes, 313 } 314 if out, ok := utxo.Out.(avax.Addressable); ok { 315 elem.Traits = out.Addresses() 316 } 317 318 elems[i] = elem 319 } 320 e.AtomicRequests = map[ids.ID]*atomic.Requests{ 321 tx.DestinationChain: { 322 PutRequests: elems, 323 }, 324 } 325 return nil 326 } 327 328 func (e *StandardTxExecutor) AddValidatorTx(tx *txs.AddValidatorTx) error { 329 if tx.Validator.NodeID == ids.EmptyNodeID { 330 return errEmptyNodeID 331 } 332 333 if _, err := verifyAddValidatorTx( 334 e.Backend, 335 e.FeeCalculator, 336 e.State, 337 e.Tx, 338 tx, 339 ); err != nil { 340 return err 341 } 342 343 if err := e.putStaker(tx); err != nil { 344 return err 345 } 346 347 txID := e.Tx.ID() 348 avax.Consume(e.State, tx.Ins) 349 avax.Produce(e.State, txID, tx.Outs) 350 351 if e.Config.PartialSyncPrimaryNetwork && tx.Validator.NodeID == e.Ctx.NodeID { 352 e.Ctx.Log.Warn("verified transaction that would cause this node to become unhealthy", 353 zap.String("reason", "primary network is not being fully synced"), 354 zap.Stringer("txID", txID), 355 zap.String("txType", "addValidator"), 356 zap.Stringer("nodeID", tx.Validator.NodeID), 357 ) 358 } 359 return nil 360 } 361 362 func (e *StandardTxExecutor) AddSubnetValidatorTx(tx *txs.AddSubnetValidatorTx) error { 363 if err := verifyAddSubnetValidatorTx( 364 e.Backend, 365 e.FeeCalculator, 366 e.State, 367 e.Tx, 368 tx, 369 ); err != nil { 370 return err 371 } 372 373 if err := e.putStaker(tx); err != nil { 374 return err 375 } 376 377 txID := e.Tx.ID() 378 avax.Consume(e.State, tx.Ins) 379 avax.Produce(e.State, txID, tx.Outs) 380 return nil 381 } 382 383 func (e *StandardTxExecutor) AddDelegatorTx(tx *txs.AddDelegatorTx) error { 384 if _, err := verifyAddDelegatorTx( 385 e.Backend, 386 e.FeeCalculator, 387 e.State, 388 e.Tx, 389 tx, 390 ); err != nil { 391 return err 392 } 393 394 if err := e.putStaker(tx); err != nil { 395 return err 396 } 397 398 txID := e.Tx.ID() 399 avax.Consume(e.State, tx.Ins) 400 avax.Produce(e.State, txID, tx.Outs) 401 return nil 402 } 403 404 // Verifies a [*txs.RemoveSubnetValidatorTx] and, if it passes, executes it on 405 // [e.State]. For verification rules, see [verifyRemoveSubnetValidatorTx]. This 406 // transaction will result in [tx.NodeID] being removed as a validator of 407 // [tx.SubnetID]. 408 // Note: [tx.NodeID] may be either a current or pending validator. 409 func (e *StandardTxExecutor) RemoveSubnetValidatorTx(tx *txs.RemoveSubnetValidatorTx) error { 410 staker, isCurrentValidator, err := verifyRemoveSubnetValidatorTx( 411 e.Backend, 412 e.FeeCalculator, 413 e.State, 414 e.Tx, 415 tx, 416 ) 417 if err != nil { 418 return err 419 } 420 421 if isCurrentValidator { 422 e.State.DeleteCurrentValidator(staker) 423 } else { 424 e.State.DeletePendingValidator(staker) 425 } 426 427 // Invariant: There are no permissioned subnet delegators to remove. 428 429 txID := e.Tx.ID() 430 avax.Consume(e.State, tx.Ins) 431 avax.Produce(e.State, txID, tx.Outs) 432 433 return nil 434 } 435 436 func (e *StandardTxExecutor) TransformSubnetTx(tx *txs.TransformSubnetTx) error { 437 currentTimestamp := e.State.GetTimestamp() 438 if e.Config.UpgradeConfig.IsEtnaActivated(currentTimestamp) { 439 return errTransformSubnetTxPostEtna 440 } 441 442 if err := e.Tx.SyntacticVerify(e.Ctx); err != nil { 443 return err 444 } 445 446 isDurangoActive := e.Config.UpgradeConfig.IsDurangoActivated(currentTimestamp) 447 if err := avax.VerifyMemoFieldLength(tx.Memo, isDurangoActive); err != nil { 448 return err 449 } 450 451 // Note: math.MaxInt32 * time.Second < math.MaxInt64 - so this can never 452 // overflow. 453 if time.Duration(tx.MaxStakeDuration)*time.Second > e.Backend.Config.MaxStakeDuration { 454 return errMaxStakeDurationTooLarge 455 } 456 457 baseTxCreds, err := verifyPoASubnetAuthorization(e.Backend, e.State, e.Tx, tx.Subnet, tx.SubnetAuth) 458 if err != nil { 459 return err 460 } 461 462 // Verify the flowcheck 463 fee, err := e.FeeCalculator.CalculateFee(tx) 464 if err != nil { 465 return err 466 } 467 totalRewardAmount := tx.MaximumSupply - tx.InitialSupply 468 if err := e.Backend.FlowChecker.VerifySpend( 469 tx, 470 e.State, 471 tx.Ins, 472 tx.Outs, 473 baseTxCreds, 474 // Invariant: [tx.AssetID != e.Ctx.AVAXAssetID]. This prevents the first 475 // entry in this map literal from being overwritten by the 476 // second entry. 477 map[ids.ID]uint64{ 478 e.Ctx.AVAXAssetID: fee, 479 tx.AssetID: totalRewardAmount, 480 }, 481 ); err != nil { 482 return err 483 } 484 485 txID := e.Tx.ID() 486 487 // Consume the UTXOS 488 avax.Consume(e.State, tx.Ins) 489 // Produce the UTXOS 490 avax.Produce(e.State, txID, tx.Outs) 491 // Transform the new subnet in the database 492 e.State.AddSubnetTransformation(e.Tx) 493 e.State.SetCurrentSupply(tx.Subnet, tx.InitialSupply) 494 return nil 495 } 496 497 func (e *StandardTxExecutor) AddPermissionlessValidatorTx(tx *txs.AddPermissionlessValidatorTx) error { 498 if err := verifyAddPermissionlessValidatorTx( 499 e.Backend, 500 e.FeeCalculator, 501 e.State, 502 e.Tx, 503 tx, 504 ); err != nil { 505 return err 506 } 507 508 if err := e.putStaker(tx); err != nil { 509 return err 510 } 511 512 txID := e.Tx.ID() 513 avax.Consume(e.State, tx.Ins) 514 avax.Produce(e.State, txID, tx.Outs) 515 516 if e.Config.PartialSyncPrimaryNetwork && 517 tx.Subnet == constants.PrimaryNetworkID && 518 tx.Validator.NodeID == e.Ctx.NodeID { 519 e.Ctx.Log.Warn("verified transaction that would cause this node to become unhealthy", 520 zap.String("reason", "primary network is not being fully synced"), 521 zap.Stringer("txID", txID), 522 zap.String("txType", "addPermissionlessValidator"), 523 zap.Stringer("nodeID", tx.Validator.NodeID), 524 ) 525 } 526 527 return nil 528 } 529 530 func (e *StandardTxExecutor) AddPermissionlessDelegatorTx(tx *txs.AddPermissionlessDelegatorTx) error { 531 if err := verifyAddPermissionlessDelegatorTx( 532 e.Backend, 533 e.FeeCalculator, 534 e.State, 535 e.Tx, 536 tx, 537 ); err != nil { 538 return err 539 } 540 541 if err := e.putStaker(tx); err != nil { 542 return err 543 } 544 545 txID := e.Tx.ID() 546 avax.Consume(e.State, tx.Ins) 547 avax.Produce(e.State, txID, tx.Outs) 548 return nil 549 } 550 551 // Verifies a [*txs.TransferSubnetOwnershipTx] and, if it passes, executes it on 552 // [e.State]. For verification rules, see [verifyTransferSubnetOwnershipTx]. 553 // This transaction will result in the ownership of [tx.Subnet] being transferred 554 // to [tx.Owner]. 555 func (e *StandardTxExecutor) TransferSubnetOwnershipTx(tx *txs.TransferSubnetOwnershipTx) error { 556 err := verifyTransferSubnetOwnershipTx( 557 e.Backend, 558 e.FeeCalculator, 559 e.State, 560 e.Tx, 561 tx, 562 ) 563 if err != nil { 564 return err 565 } 566 567 e.State.SetSubnetOwner(tx.Subnet, tx.Owner) 568 569 txID := e.Tx.ID() 570 avax.Consume(e.State, tx.Ins) 571 avax.Produce(e.State, txID, tx.Outs) 572 return nil 573 } 574 575 func (e *StandardTxExecutor) BaseTx(tx *txs.BaseTx) error { 576 var ( 577 currentTimestamp = e.State.GetTimestamp() 578 upgrades = e.Backend.Config.UpgradeConfig 579 ) 580 if !upgrades.IsDurangoActivated(currentTimestamp) { 581 return ErrDurangoUpgradeNotActive 582 } 583 584 // Verify the tx is well-formed 585 if err := e.Tx.SyntacticVerify(e.Ctx); err != nil { 586 return err 587 } 588 589 if err := avax.VerifyMemoFieldLength(tx.Memo, true /*=isDurangoActive*/); err != nil { 590 return err 591 } 592 593 // Verify the flowcheck 594 fee, err := e.FeeCalculator.CalculateFee(tx) 595 if err != nil { 596 return err 597 } 598 if err := e.FlowChecker.VerifySpend( 599 tx, 600 e.State, 601 tx.Ins, 602 tx.Outs, 603 e.Tx.Creds, 604 map[ids.ID]uint64{ 605 e.Ctx.AVAXAssetID: fee, 606 }, 607 ); err != nil { 608 return err 609 } 610 611 txID := e.Tx.ID() 612 // Consume the UTXOS 613 avax.Consume(e.State, tx.Ins) 614 // Produce the UTXOS 615 avax.Produce(e.State, txID, tx.Outs) 616 return nil 617 } 618 619 // Creates the staker as defined in [stakerTx] and adds it to [e.State]. 620 func (e *StandardTxExecutor) putStaker(stakerTx txs.Staker) error { 621 var ( 622 chainTime = e.State.GetTimestamp() 623 txID = e.Tx.ID() 624 staker *state.Staker 625 err error 626 ) 627 628 if !e.Config.UpgradeConfig.IsDurangoActivated(chainTime) { 629 // Pre-Durango, stakers set a future [StartTime] and are added to the 630 // pending staker set. They are promoted to the current staker set once 631 // the chain time reaches [StartTime]. 632 scheduledStakerTx, ok := stakerTx.(txs.ScheduledStaker) 633 if !ok { 634 return fmt.Errorf("%w: %T", errMissingStartTimePreDurango, stakerTx) 635 } 636 staker, err = state.NewPendingStaker(txID, scheduledStakerTx) 637 } else { 638 // Only calculate the potentialReward for permissionless stakers. 639 // Recall that we only need to check if this is a permissioned 640 // validator as there are no permissioned delegators 641 var potentialReward uint64 642 if !stakerTx.CurrentPriority().IsPermissionedValidator() { 643 subnetID := stakerTx.SubnetID() 644 currentSupply, err := e.State.GetCurrentSupply(subnetID) 645 if err != nil { 646 return err 647 } 648 649 rewards, err := GetRewardsCalculator(e.Backend, e.State, subnetID) 650 if err != nil { 651 return err 652 } 653 654 // Post-Durango, stakers are immediately added to the current staker 655 // set. Their [StartTime] is the current chain time. 656 stakeDuration := stakerTx.EndTime().Sub(chainTime) 657 potentialReward = rewards.Calculate( 658 stakeDuration, 659 stakerTx.Weight(), 660 currentSupply, 661 ) 662 663 e.State.SetCurrentSupply(subnetID, currentSupply+potentialReward) 664 } 665 666 staker, err = state.NewCurrentStaker(txID, stakerTx, chainTime, potentialReward) 667 } 668 if err != nil { 669 return err 670 } 671 672 switch priority := staker.Priority; { 673 case priority.IsCurrentValidator(): 674 if err := e.State.PutCurrentValidator(staker); err != nil { 675 return err 676 } 677 case priority.IsCurrentDelegator(): 678 e.State.PutCurrentDelegator(staker) 679 case priority.IsPendingValidator(): 680 if err := e.State.PutPendingValidator(staker); err != nil { 681 return err 682 } 683 case priority.IsPendingDelegator(): 684 e.State.PutPendingDelegator(staker) 685 default: 686 return fmt.Errorf("staker %s, unexpected priority %d", staker.TxID, priority) 687 } 688 return nil 689 }